Arduino Serial not behaving as expected, data present when it should not be

Hello Everyone,

Hopefully this is the right section of the forum. I am trying to communicate with a Dynamixel Servo using an Arduino. I have tried multiple Arduinos and Hardware/Software Serial, but the behavior is the same. I am using Serial to communicate to the PC, and Serial1 to communicate to the Dynamixel Servo using an Arduino Micro in this example.

My code is as follows:

word    Response[10];           // Holds the bytes of the response

void setup() {

  Serial.begin(115200);         // Sets the PC serial port Baud Rate
  Serial1.begin(57600);         // Sets the Dynamixel servo port Baud Rate   
  
}

void loop() {

Ping(); // Ping the Dynamixel

}

void Ping() // Pings the Dynamixel to see if it is present.
  {
    Serial1.write(0xFF);        // Header byte 1
    Serial1.write(0xFF);        // Header byte 2
    Serial1.write(0x01);        // Dynamixel ID
    Serial1.write(0x02);        // Length of Packet (Only 2 for Ping Command)
    Serial1.write(0x01);        // Ping type of instruction
    Serial1.write(lowByte(~(0x01 + 0x02 + 0x01))); // Checksum. This is the NOT (~) of the SUM of everything else.
    Serial1.flush();            // Waits for the serial transmission to finish
    
    delay(100);                 // Wait for Dynamixel to respond
        
    while(Serial1.available() > 0) // If there is some data at the serial port
    { 
      for(int n=0; n<8; n++) // Read 8 bytes 
          {
            Response[n] = Serial1.read(); // and put them into the response array
          }
    }

    Serial.print ("Response: ");
    Serial.println(Response [0] + Response [1] + Response [2] + Response [3] + Response [4] + Response [5]);
        
   }

When the program starts up without anything connected, “Response” is 0. When I connect the Dynamixel, it returns some data, as it should. The problem is that when I DISCONNECT the Dynamixel, the data in the Response does NOT change, it stays at the same value as before.

How is this possible if there is nothing connected and the Arduino is not receiving any valid data? What is it reading? Or where is this data stored?

If anyone could shed some light on what is going on, I would really appreciate it! I have been struggling with this for days now and I am not sure what I am doing wrong.

Sounds perfectly legit. Unless you specifically write something over what you have in the serial1 buffer, it will stay the same until you power off the Arduino. Why do you think otherwise?

Paul

How many bytes are returned ? Exactly 8 ?
Can you give a link to your Dynamixel Servo ? Is there a document with the communication protocol ?

I would change the structure of the code, because I don’t understand your while-statement.

// clear RX buffer
while( Serial1.available() > 0)
{
  Serial1.read();
}

// Send command
Serial1.write( 0xFF);
...

// no flush

// wait until the whole answer is received
delay( 100);

// Received everything ?
if( Serial1.available() == 8)
{
  // Read the 8 bytes
  for( int i=0; i<8; i++)
  {
    Response[n] = Serial1.read();
  }

  // 8 bytes are received, everything is okay
  Serial.print ("Response...
  ...
}
else
{
  // The 8 bytes were not received ! something is wrong.
}

Paul_KD7HB:
Unless you specifically write something over what you have in the serial1 buffer, it will stay the same until you power off the Arduino.

Really? Why is this the case? This might be exactly what the problem is. I am expecting the serial buffer to get filled with garbage or something else once the servo is disconnected, not to retain valid information. Is there a way to clear this buffer? Writing “0” to it does not seem to work.

Koepel:
How many bytes are returned ? Exactly 8 ?
Can you give a link to your Dynamixel Servo ? Is there a document with the communication protocol ?

The number of bytes returned changes depending on the command issued to the Dynamixel servo. The ping command actually returns 6 bytes, so that is indeed a mistake in my code.

Here is some information on the protocol if you are interested:
https://emanual.robotis.com/docs/en/dxl/protocol1/

The "Ping" Section is what I am trying to utilize. The "Instruction" packet is what I am sending, and the "Status" packet is what I am receiving.

The motor I am using is specifically the Dynamixel MX-28AR, but this applies to all Dynamixels running protocol 1.0 I believe. There are a fair bit of libraries available to control this motor, but I am trying to do it from scratch to understand what is happening.

saaifk:
Really? Why is this the case?

Can you compare your sketch with the code that I showed ?

You have this:

if( serial data available)
{
  do something if data was received
}

print data, regardless if something was received.

The data is printed, regardless if something was received.

Koepel:
The data is printed, regardless if something was received.

This was absolutely 100% the problem. I was printing data regardless of whether it had been written to or not, so I was printing the old data when Serial was not available. Unfortunately I found other bugs in my code, but this is a great help.
Thank you so much Koepel! I really appreciate it and hopefully this helps someone else in the future as well!

 while(Serial1.available() > 0)     // If there is at least ONE character ready
{
  for(int n=0; n<8; n++)            // Blindly read EIGHT characters, whether eight chars were received or not
  {
    Response[n] = Serial1.read(); // and put them into the response array
  }
}

Read the comments. Does that logic sound right to you?

RayLivingston:

 while(Serial1.available() > 0)     // If there is at least ONE character ready

{
 for(int n=0; n<8; n++)            // Blindly read EIGHT characters, whether eight chars were received or not
 {
   Response[n] = Serial1.read(); // and put them into the response array
 }
}




Read the comments. Does that logic sound right to you?

Hey Ray, thanks for the help as well! I do admit that this is a mistake in my code, but due to the way that this servo works, it will never send more than 8 bytes back as a response. The correct number should be 6, but this is not really the fatal flaw in this code. If I am correct, reading more bytes than what is available will just read garbage into the bytes where there is nothing there. If I am wrong, please let me know!

You should see everything in motion.
Even at 57600 baud, there could be just one character in the input buffer. The Serial1.available() returns 1, then you read 8 bytes and only the first one is valid. Maybe because the code takes time, the while-loop does the second byte, but after that the Serial1.available() returns zero. The code continues and meanwhile the rest of the bytes are coming in.

You have to read a byte when a byte is available. No matter what.

There are a few Dynamixel libraries and there is a MKR Dynamixel shield.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.