[SOLVED] Arduino Due with Dynamixel X/Pro (RS485)

I’m using an Arduino Due (3.3V TTL, 32-bit) with a RS485 Transceiver Module (MAX3485) to communicate with Dynamixel X/Pro servos using the Robotis Communication Protocol 2.0 (http://emanual.robotis.com/docs/en/dxl/protocol2/).

I’ve been struggling to get any serial response from the servo and after trying over 20 different solutions (lower baud rate to 9600, send simplified packet, add delays after direction change) and tests (TX waveform, RS485 A-B waveforms, DE/RE enable timing, …) I am getting stumped and would appreciate your help.

On the Arduino Due:

  • TX1 (pin 18)
  • RX1 (pin 19)
  • Direction Pin (pin 22)

On the MAX3485 Transceiver:

  • Driver Input (from TX1)
  • Receiver Output (to RX1)
  • Driver Enable/Receiver Enable (tied together, from Direction Pin, HIGH = Driver Enabled, LOW = Receiver Enabled)

On the Dynamixel Servo:

  • GND (common GND with Transceiver and Arduino Due)
  • VCC (24VDC)
  • Data+ (RS485 B Output from Transceiver)
  • Data- (RS485 A Output from Transceiver)

Because of the following tests, I believe the problem is software-side:

  • Multimeter verifies 24VDC to servo? Yes
  • Servo LED briefly lights green on power on? Yes
  • Oscilloscope verifies direction pin changes between HIGH and LOW? Yes
  • Oscilloscope verifies 3.3V RS485 A/B serial byte signals? Yes
  • Robotis provided MAX485 (5V) circuit diagram connects transceiver B output pin to servo DATA+ pin? Yes

There are a few thoughts in the back of my mind:

  • The transceiver board has a 120 ohm terminating resistor but I haven’t wired a terminating resistor on the other end yet. With <30cm distances surely the lack of an opposing terminating resistor would not matter enough for RX.
  • Surely the Dynamixel servo accepts 3.3V RS485.

Here’s some basic serial communication code that doesn’t get any response:

void setup()
{
Serial.begin(9600); // For TX/RX with PC serial monitor
pinMode(22, OUTPUT); // Setup direction pin
Serial1.begin(57600); // For TX1/RX1 with transceiver
}

void loop()
{
unsigned char packet[] = {
0xFF, 	
0xFF,	
0xFD, 	
0x00, 	
0x01, 	
0x03, 	
0x00, 	
0x01, 	
0x19, 	
0x4E
};

digitalWrite(22, HIGH); // Enable driver
Serial1.write(packet, sizeof(packet));
Serial1.flush();
delayMicroseconds(250);
digitalWrite(22, LOW); // Enable receiver
delayMicroseconds(250); // Wait the ~500us response delay time

// Loop and check availableData()

Serial.println(Serial1.read()); // Should be 0xFF, but -1 (nothing to read)
Serial.println(Serial1.read()); // Should be 0xFF, but -1 (nothing to read)
Serial.println(Serial1.read()); // Should be 0xFD, but -1 (nothing to read)

delay(1000);
}

UPDATE: Found the solution. The MAX485 reference circuit on Robotis is not completely transferable to the MAX3485. The correct wiring is TRANSCEIVER A to SERVO DATA+ and TRANSCEIVER B to SERVO DATA-. I also recommend starting with the REBOOT command instead of the PING command, because the green LED flicker on successful reboot makes it much easier to confirm successful TX. For successful RX of the status packet, make sure to set the post-TX delay period to 500us, because longer delays somehow rearrange the Serial1.read() RX buffer (not exactly sure the nuances here yet).

I hope all of that is helpful and make sure to pass on new useful info to others. The more I do engineering work the more I appreciate that we’re standing on the hard-developed foundations that others have built for us.