Azure cloud ethernet controlled slotcar suddenly stops after three perfect laps.

I’m working on a project to control my old slotcar race track with an Arduino and cloud. To read the complete story so far go to http://www.codeproject.com/Articles/887003/Control-a-model-car-track-with-Azure-and-Arduino
After solving the issues with the current sensors with a lot of thanks to TomGeorge, who set me on the right ‘track’ in this forum thread: http://forum.arduino.cc/index.php?topic=312426.0 I thought everthing was fine. However the car ran perfectly for three laps and than stopped. You can see this in the attached graph that depicts the current readings as they arrive in the Azure service. There are no errors, the tcp communication keeps running and the correct voltage values are send to the multiplexer. I only use 0 and 255 values at the moment so there are no block pulses. I have no idea what’s going on. It seems the PWM signal on pin 5 get’s jammed perhaps by the Ethernet reads as when I disable the readBytes the car keeps running albeit at a constant speed of course. Could there be some kind of interference between the readBytes and the analogWrite? Anyone know of issues with PWM that could cause this?

Here is the code:

#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network, and it's optional if DHCP is enabled
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xBC, 0xAE };
//IPAddress ip(192,168,15,177); //We're not going to use this, it's just for reference
byte device = 0; //device id
byte sendbuff[6]; //buffer for sending
byte replybuff[2]; //buffer for receiving
EthernetClient client;
//The union is for converting the float to a byte array
typedef union {
  float floatingPoint;
  byte binary[4];
} binaryFloat;
binaryFloat v;

int r0 = 0;      //value of select pin at the 4051 (s0)
int r1 = 0;      //value of select pin at the 4051 (s1)
int r2 = 0;      //value of select pin at the 4051 (s2)
byte count = 0;   //which y pin we are selecting
const int sensorPin =  A0; // the number of the sensor pin
float section[6]; //the six track sections to measure
byte voltage[6] = {255,255,255,255,255,255}; //the speed on the six track sections
float current[6] = {0,0,0,0,0,0}; //the current on the six track sections
float lp = 0; //sample loops

void setup(){
  
  Ethernet.begin(mac);
  
  pinMode(2, OUTPUT);    // s0
  pinMode(3, OUTPUT);    // s1
  pinMode(4, OUTPUT);    // s2
  
  pinMode(6, OUTPUT);    // s0
  pinMode(7, OUTPUT);    // s1
  pinMode(8, OUTPUT);    // s2
  
  pinMode(sensorPin, INPUT); 
  
}

void loop () {

  if (! client.connected()){  
        client.stop();    
        const char* host = "192.168.178.28";
        client.connect(host, 10100);
    }
  
  for (count=0; count<=5; count++) {
      
      // select the bit  
      r0 = bitRead(count,0);      
      r1 = bitRead(count,1);   
      r2 = bitRead(count,2);   
      
      //select the first multiplexer channel for driving the transistors
      digitalWrite(2, r0);
      digitalWrite(3, r1);
      digitalWrite(4, r2);  
      //write the multiplexed pin here
      analogWrite(5, voltage[count]);
      
      //select the second multiplexer channel for reading the optocouplers
      digitalWrite(6, r0);
      digitalWrite(7, r1);
      digitalWrite(8, r2);        
      //read the multiplexed pin here and sample the result
      section[count] = section[count] + analogRead(sensorPin);
       
      if(lp >= 100){  
        v.floatingPoint = section[count]/lp;
        current[count] = v.floatingPoint;
        sendbuff[0] = v.binary[0];
        sendbuff[1] = v.binary[1];
        sendbuff[2] = v.binary[2];
        sendbuff[3] = v.binary[3];
        sendbuff[4] = count;
        sendbuff[5] = device;
        //send the current value to the remote service
        client.write(sendbuff, sizeof(sendbuff)); 
        //reset the value for the next sample
        section[count] = 0; 
         
        //read the reply (if any)
        if(client.available() >= sizeof(replybuff)){
          client.readBytes(replybuff, sizeof(replybuff));
          //assign the new voltage value
          voltage[replybuff[0]] = replybuff[1];
        }
      }
    }
    
    if(lp >= 100){ 
      //reset the sample counter
      lp = 0; 
    }    
    lp++;      
}

  pinMode(sensorPin, INPUT);

Useless. The pinMode() function affects the digital pin that shares the same physical space as the analog pin. You are not using that pin as a digital pin.

        client.write(sendbuff, sizeof(sendbuff)); 
        //reset the value for the next sample
        section[count] = 0; 
         
        //read the reply (if any)
        if(client.available() >= sizeof(replybuff)){

I believe that it is unrealistic to expect a reply in the few nanoseconds that it takes to set the memory location to 0.

You need to either wait for the complete reply to arrive, reading it as it arrives, or make the sending and receiving of data separate, independent, sections of code.

Because you don't read the server response, the socket you are using gets taken out of service. There are only 4 sockets available, so after only a few iterations of loop(), you are out of sockets. Which sounds like what your problem is.

Hi PaulS,

Thanks for your reply. During the 3 laps the car runs flawless there have been a lot of loops. I do read the server reply but as they don't come back in sequence from the Azure service (and don't have to) I just read any reply waiting at that specific moment. Not all writes are replied to (When it doesn't cause any voltage changes there's no reply from the server) so I finally get all the relevant data back and in time. With only 4 sockets available one would expect the car to die very soon, in the first section already. As I already pointed out in my question, the tcp logic keeps running so the Arduino client and the Azure server are still communicating after the car has stalled.

Where did you find the function readBytes in the ethernet library?

With only 4 sockets available one would expect the car to die very soon, in the first section already.

Sounds like it is. Add this function to your sketch and call it either before or after each connection to check your socket status. If you don’t show a socket with a status of 0x0, then all subsequent connection attempts will fail.

#include <utility/w5100.h>

byte socketStat[MAX_SOCK_NUM];

void ShowSockStatus()
{
  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    Serial.print(F("Socket#"));
    Serial.print(i);
    uint8_t s = W5100.readSnSR(i);
    socketStat[i] = s;
    Serial.print(F(":0x"));
    Serial.print(s,16);
    Serial.print(F(" "));
    Serial.print(W5100.readSnPORT(i));
    Serial.print(F(" D:"));
    uint8_t dip[4];
    W5100.readSnDIPR(i, dip);
    for (int j=0; j<4; j++) {
      Serial.print(dip[j],10);
      if (j<3) Serial.print(".");
    }
    Serial.print(F("("));
    Serial.print(W5100.readSnDPORT(i));
    Serial.println(F(")"));
  }
}

The status codes are as follows
0x0 = available
0x14 = waiting for connection
0x17 = connected to server
0x1C = connected waiting for close
0x22 = UDP socket

edit: If you are using properly running code, all sockets should show a status of 0x0 between connections.

Hi SurferTim,
Thanks for your reply. I’d like to make clear I don’t have connection problems, the connection is fine (I don’t use multiple connections, there’s always only one), I can see the data coming in and going out long after the car has stalled. It’s feeding the analogWrite function with the correct values but there’s no power on the track anymore after three laps. That’s why I think client.readBytes is messing with the signal on pin 5 (Unfortunately I don’t own an oscilloscope so I can’t check this). When I comment out the client.readBytes() line everything keeps running fine. (I also tried client.read() but made no difference). Anyone any ideas?

It came out the reason for stalling of the car had nothing to do with the Arduino but with a bug on the Azure service side causing the commands running out of sync with the location of the car on the track.

Interesting. Thanks for letting us know. :)