Go Down

Topic: Running Dynamixel on Arduino Due (Read 3501 times) previous topic - next topic

hariharan82

Hi,

I am a robot enthusiast and have been working on arbotix controller for the past 6 months. As you may know, the robotcontroller can readily talk and control dynamixel motors. I am stepping up my project now and am needing a faster processor. I came to know about the arduino due and am interested in working with it. However, i am not sure if i will be able to control the dynamixel motors from the due. Not sure if it has the 3 pin ttl ports to control the motors. Can someone please clarrify. and if yes, what needs to be done other than using the bioloid and ax-12 libraries. Any help is much appreciated

Thanks
Hari

Grumpy_Mike

The Due does not have a TTL output, so if you want one or three then you need to buffer the output.

Arctic_Eddie

I am using the Mega to control two MX-64T servos. I see no reason why it cannot be used on the Due in the same fashion.

Here is how it's done. First, the AX-12 library didn't work. You can still #include it to get the #defines. However, I just copied the #define block and changed the compliance constants to the PID values in the correct registers. Next, copy the AX routines for register read8, write8, and write16 to appropriately name functions in your sketch. Once you have these written, you can create other functions by just writing to the appropriate registers. You won't need that many.

On the hardware side, the Mega serial1 port is used with the baud set to 57,600, the servos default. You can go much higher but I had no need to do so, therefore, have no idea where the upper limit lies. The servos have a specific set of baud values set by a series of constants. The match is not perfect but within the tolerance of RS232.

There was also a strange problem in the wiring of the half-duplex line. Fortunately, it can be fixed with a single 1K resistor. I found that I could talk to the servos but not receive any data back. The problem is that the sender in the servo cannot overcome the pullup effect of the Mega TX1 line. This can be solved with a 1K resistor between the Mega TX1 and RX1 pins. The 1K is then in series with the TX1 line going out but the input impedance of the servo receiver is high so no net effect. On receive, the 1K resistor is a pullup which the servo can overcome.

My application is a stable platform for aerial photography so I need only two servos, roll and pitch. The tilt signal comes from an ADXL345 accelerometer breakout board on I2C. The two servos are daisy chained and fed through a single cable. I like the Dynamixel servos due to their high torque, absolute position sensing, high angular resolution, and digital communication.

LuisGIII

Hello!
I think that I can help you with your problem. There is a new board called CM-900 is from ROBOTIS (Bioloid, Darwin-OP) and they are giving this board for beta-testing you just need to pay the shipment to your place!
Enter to this forum:

http://www.robotsource.org/xe/Circle_CM9_Developer_World

Create an account and ask for one! you only need to explain one of your projects and they will send it to you :)
Hope it helps! it's a good option for Ax and Rx/Mx Dynamixel series.

KurtE

I have been playing around with trying to use an Arduino Due to try to control some Robotis AX-12 servos.  I am currently trying it by using an AX-12 CDS55xx Driver board by DFRobot (http://www.dfrobot.com/index.php?route=product/product&filter_name=dynamixel&product_id=579#.UUisLsrCs3g)

I am not sure if their board will try to drive the RX line at 5v or not, but I am going through a TTL Level converter chip on my Shield.

The problem I am running into is I don't believe the USARTs on the Due can run the Dynamixels at their full buss speed of 1000000.
That is, if I understand the baud rates on the Due, when  I ask for a baud rate of 1000000, the actually generated baud rate is: 84000000/(n*16). Best fit n=5, so actual baud rate is: 1050000 so off by about 5%,
which is not close enough.  I believe the spec for the servos is it can handle a delta of up to 3%

I believe if I wish to continue down this route, I could potentially reprogram the servos to run at a baud rate of 666666, as you can set the baud rate to 2000000/(n+1).  On the Due, the closest to this would be I believe on the due to the nearest  baud rate would be  at 656,250 or ((656250-666666)/666666)*100=-1.56% which may work...

Suggestions?  Also my quick look over the the Due code base, my impression is I may have to fiddle with the Baud rate I pass in as I think it only truncates a division of the baud into the CPU speed.  It does not do any rounding...

Thanks
Kurt



cmaglie


The problem I am running into is I don't believe the USARTs on the Due can run the Dynamixels at their full buss speed of 1000000.
That is, if I understand the baud rates on the Due, when  I ask for a baud rate of 1000000, the actually generated baud rate is: 84000000/(n*16). Best fit n=5, so actual baud rate is: 1050000 so off by about 5%, which is not close enough.  I believe the spec for the servos is it can handle a delta of up to 3%


Are the servos sending data back to the Due?
If the answer is no, you can try to set the USART in synchronous mode, where the baudrate is generated directly from the master clock, and you can use a divider of 84.
(in the SAM3X datasheet is chapter 36.7.1.3)
C.

KurtE

Thanks,

Unfortunately (or fortunately) the servos provide feedback, so that probably won't work.

But thanks again
Kurt

ephesus

Hi what do mean of the connection of the 1k resistor between TX and RX.How do you connect it in series after that.Can you provide a schematic of this connection.Thank you for your help.Appreciate it.


I am using the Mega to control two MX-64T servos. I see no reason why it cannot be used on the Due in the same fashion.

Here is how it's done. First, the AX-12 library didn't work. You can still #include it to get the #defines. However, I just copied the #define block and changed the compliance constants to the PID values in the correct registers. Next, copy the AX routines for register read8, write8, and write16 to appropriately name functions in your sketch. Once you have these written, you can create other functions by just writing to the appropriate registers. You won't need that many.

On the hardware side, the Mega serial1 port is used with the baud set to 57,600, the servos default. You can go much higher but I had no need to do so, therefore, have no idea where the upper limit lies. The servos have a specific set of baud values set by a series of constants. The match is not perfect but within the tolerance of RS232.

There was also a strange problem in the wiring of the half-duplex line. Fortunately, it can be fixed with a single 1K resistor. I found that I could talk to the servos but not receive any data back. The problem is that the sender in the servo cannot overcome the pullup effect of the Mega TX1 line. This can be solved with a 1K resistor between the Mega TX1 and RX1 pins. The 1K is then in series with the TX1 line going out but the input impedance of the servo receiver is high so no net effect. On receive, the 1K resistor is a pullup which the servo can overcome.

My application is a stable platform for aerial photography so I need only two servos, roll and pitch. The tilt signal comes from an ADXL345 accelerometer breakout board on I2C. The two servos are daisy chained and fed through a single cable. I like the Dynamixel servos due to their high torque, absolute position sensing, high angular resolution, and digital communication.



KurtE

Hi,

I have not tried this, as I was trying using a device that properly handled making a half duplex setup, but How I read this was:

TX ----1K Resistor------+----------To Servos
RX-----------------------+

That is there is a 1K resistor between the TX line and the servos, and the RX line is directly connected to the servos.

Again I have not tried, but that is how I read it and it made some sense.  This helped the receiving of data back from the servos as the TX line was probably still in a high state, but through the resistor it acted more like a Pull up resistor, which the servos could still pull low when needed...

Kurt

fablagrenouille

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
 
}

MarkT

Please edit that with code tags.
[ I won't respond to messages, use the forum please ]

Danishmo

Hey fablagrenouille

It looks great with your code, though I dont understand the french :)

I am curious how you get to turn different motors with different ID's?

Also I tried your code, but I get some errors. Since I am new to Arduino I am not sure if I there is something I need to add for it work?

Errors in short:
sketch_jan07a.ino: In function 'void loop()':
sketch_jan07a:44: error: incompatible types in assignment of 'int' to 'byte [20]'
sketch_jan07a:59: error: invalid operands of types 'byte [11]' and 'int' to binary 'operator>>'
sketch_jan07a:76: error: incompatible types in assignment of 'int' to 'byte [20]'
sketch_jan07a:85: error: call of overloaded 'println(byte [20], int)' is ambiguous

Go Up