Running Dynamixel on Arduino Due

Hi, I have succeeded in controlling an AX-12A Dynamixel servo with an Arduino Due.
My Method is the following : I use a digital pin, in my case pin 20 because it is just near RX1 (19).
For transmitting to the servo, I create an artificial serial communication on pin 20 as serial output. The reception from the servo is made with a normal serial port of the Arduino Due. I have chosen Serial1.
For each byte to transmit in the message, I send a start-bit, then the data byte and then a stop bit.
I have adjusted the duration of each bit to 1µs using "asm("NOP");" for communication at 1 Mbps as required by the servo. When no message has to be transmitted to the servo, pin 20 is configured as input for not disturbing the reception of data coming from the servo.
Arduino Due admits only 3.3V on its pins but the servo produces 4V pulses when it is sending data, that is why I have placed a 3.3V zener diode and the 150 ohms resistor. I have tested without the zener diode and it worked but it is better to take no risk for your Arduino. A simple divider with two resistor might be enough but I have not tested it.
My program is only a test program for validating my method. The program asks the servo to come to central position and waits for the answer from the servo. It is working perfectly and make the answer from the servo appear in the terminal of the Arduino IDE.
A library (a class)should be written for a complete control of the servo, I'll try to do it later but I have not enough time at the moment. May be someone could do it by just modifying an existing library for Arduino Uno or Mega because only the transmission part has to be adapted. Then the library could be made accessible for everybody.

My commentary in the program are in french, If you don't understand you can ask me to translate.

//
/
Programme de test pour commander un servomoteur Dynamixel AX12A /
/
par une carte Arduino Due. /
/
Ce programme demande à l'AX-12A de se placer en position médiane et affiche /
/
sa réponse dans le terminal Arduino /
/
Porgramme fait et validé par Fabrice 24/12/2013 /
/
Câblage : sortie digitale 20 reliée à RX1 (19) et reliée aussi à la cathode /
/
d'une diode zener 3,3V. De ce point part une résistance de 150 ohms en série /
/
avec le fil DATA vers l'AX-12A. L'anode de la diode zener est à la masse. /
/
La carte Arduino est alimentée par le Jack noir sous environ 9V et /
/
l'alimentation du servomoteur se fait par la broche Vin et la masse /
/
/

// Méthode utilisée : lorsqu'on demande à la Arduino Due de communiquer à 1MBauds "(Serial1.begin(1000000);", la fréquence bit est
// supérieure et est hors tolérance par rapport à ce qu'attend l'AX-12A. De ce fait la communication ne peut pas être établie.
// Ma solution consiste à utiliser une sortie digitale, dans le cas présent, j'ai pris la broche 20 située juste à côté de la broche RX1 de Serial1.
// Par cette sortie digitale 20, je transmet la trame série créée artificiellement à l'AX-12A en ajustant la durée des bits à 1µs par des "asm("NOP");"
// La majorité du temps la broche digitale 20 est en entrée, sauf quand on emet une trame série, et aussitôt cela fini on la remet en entrée.

int Sortie_Serie = 20; // Sortie pour simuler la broche TX (
// Tableau d'octets
byte Trame_Recue[20]; // Pour stocker les octets renvoyés par le servomoteurs
byte Table_position_180[] = {0xFF, 0xFF, 0x01, 0x07, 0x03, 0x1E, 0x00, 0x02, 0x00, 0x02, 0xD2}; // (LEN:011) pour demander au servo de prendre la position médiane
bool Valeur_Bit = 0; // Pour envoyer la trame série bit par bit
void setup()
{
Serial.begin(115200);
pinMode(Sortie_Serie, INPUT); // TX digital ne prend pas la ligne DATA
}
// Pour avoir digitalWriteDirect qui est beaucoup plus rapide que digitalWrite
inline void digitalWriteDirect(int pin, boolean val)
{
if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
else g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

void loop(){

Serial.println("Debut du programme");
int i = 0;
// Remise à zéro des octets du tableau Trame_Recue

  • for( i = 0 ; i < 20 ; i++)*
  • {*
    Trame_Recue = 0x00;
    _
    }
    _
    * i = 0;*
    * pinMode(Sortie_Serie, OUTPUT); // TX digital prend la ligne DATA pour pouvoir transmettre à l'AX-12A*
    * //digitalWrite(Sortie_Serie, HIGH); // Met DATA à 1*
    * delayMicroseconds(10);*
    * int k = 0;*
    * // Envoi de la table comportant les octets à envoyer*
    * for (i = 0 ; i < 11 ; i++)*
    * { *
    * digitalWriteDirect(Sortie_Serie, LOW); // Bit de Start*
    * for(k = 0 ; k < 13 ; k++) { asm("nop"); } // Pour faire la durée de bit de 1µs*
    * for(int j = 0 ; j < 8 ; j++)*
    * {*
    Valeur_Bit = bitRead(Table_position_180*, j);
    digitalWriteDirect(Sortie_Serie, Valeur_Bit);
    _ for(k = 0 ; k < 13 ; k++) {asm("nop"); } // Pour faire la durée de bit de 1µs*
    * }_
    digitalWriteDirect(Sortie_Serie, HIGH); // Bit de Stop*

    * for(k = 0 ; k < 13 ; k++) { asm("nop"); } // Pour faire la durée de bit de 1µs*
    * }*
    * pinMode(Sortie_Serie, INPUT); // TX digital laisse la ligne DATA pour pouvoir recevoir par RX Serial1 de l'AX-12A *

* Serial1.begin(1000000); // Initialise à 1Mbps pour recevoir la réponse (pas mis avant pour ne pas recevoir ce qui est émis vers l'AX-12A*
* i = 0;*
* while(Trame_Recue[5]==0) // Réception des caractères*
* {*

* if (Serial1.available() > 0) // S'il y a quelque chose dans le buffer de réception*
* {*
Trame_Recue = Serial1.read();; // lire le caractère reçu sur la liaison série venant de l'UC
_ i++; // Préparer pour l'octet suivant

* }
}
Serial1.end();*_

* // Envoi vers le PC de la trame reçue du servo*
* for(i = 0 ; i < 6 ; i++)*
* {*
Serial.println(Trame_Recue*,DEC);*

* } *

while(1) { } // Ne plus rien faire

}
Arduino Due to AX-12A.jpg