How to Drive Dynamixel AX-12A Servos (with a RaspberryPi)

62,023

155

39

I decided to use some Dynamixel AX-12A motors for a project, and ended up having to code a library for them, so I figured I would share what I learned.

Despite being a bit more expensive, this motor has a couple of advantages over the more commonly found TowerPro motors.

Mainly, the Dynamixel motors are stronger, daisy-chainable, and have a robust control system with feedback that reports position, temperature, torque, etc.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Manuals

There are two different manuals for the AX-12A motors online. This manual from 2006 is a little outdated: some of the spec values are outdated (operating voltage range, for example), and some of the initial values reported in the Control Table are not correct, but it goes into detail about how to send instructions to the motor and how to read its response.

This other manual has more accurate values for specs and initial conditions, but lacks some of the detailing of the communication protocol.

It was useful to have both of them.

Step 2: Other Resources

Step 3: The Joy of UART Communication

Unlike other servos, the Dynamixel doesn’t respond to PWM signals, but a slightly more complicated protocol of instructions for reading and writing onto its memory. This communication happens over a half-duplex UART port, using only one wire for both sending and receiving.

What this means is that we need to build a small circuit that converts full-duplex into half-duplex, if we want to use a Raspberry Pi or an Arduino (or another microcontroller with a full-duplex serial interface) to control these motors.

The AX-12 manual from 2006 recommends this circuit:

It’s basically a tri-state buffering scheme for arbitrating the bus; it makes sure that when the controller is transmitting, the bus isn’t connected to the Rx pin, and that when it’s expecting to receive, it’s not being driven by the Tx pin.

Instead of using a 74HC126 and a 74HC04, I used a 74LS241 (as recommended here), because it already has the built-in capability of enabling half of its buffers with a high signals, and the other half with a low signal.

The schematic for the circuit I ended up using, and a simple PCB design are up in 123D.circuits.

Step 4: Configure Raspberry Pi

From oppedijk blog:

Set configuration parameters in /boot/config.txt:
init_uart_clock=16000000

sudo stty -F /dev/ttyAMA0 1000000

Edit /boot/cmdline.txt and remove all options mentioning ttyAMA0.
Edit /etc/inittab and comment out any lines mentioning ttyAMA0, especially the getty one.
Reboot

UPDATE for Raspbian Jessy:

Follow this thread on SO for disabling tty terminal and getting control of ttyAMA.

Step 5: Libs and Libs

I first tested the circuit using an Arduino and the library found here.

But, because I eventually needed to connect my project to the internet, and keep track of its state between reboots, I decided to use a Raspberry Pi as the controller instead.

I started testing this library for controlling the motors, but then decide to re-write it to make it more object-oriented, and to have some of the same capabilities as the Arduino library.

The resulting AX-12A Python library for Raspberry Pi is on github.

Turns out the timing between sending a command and getting its response is pretty critical and sensitive.

Some amount of time was spent tweaking delay values to minimize the number of dropped commands, but I feel like there might still be some issues with this aspect of the library. I’m still not sure what causes some commands to never get to the motors (it might have something to do with the timing of the Rx/Tx direction signal), but for now I can decrease the number of missed commands by catching a timeout exception in the Python serial library, and resending the command.

Step 6: More Links

Some more information about the overall project, some relevantblogposts, and a list of references.

2 People Made This Project!

Recommendations

  • Indoor Lighting Contest

    Indoor Lighting Contest
  • Make It Fly Challenge

    Make It Fly Challenge
  • Growing Beyond Earth Maker Contest

    Growing Beyond Earth Maker Contest

39 Discussions

0
None
selcuky3

4 months ago

how can i change the direction of the servo( i mean clockwise, counterclockwise), because i'm using servo as a wheel

2 replies
0
None
selcuky3selcuky3

Reply 4 months ago

i managed to run ax12's on raspberry pi 3 strecth finally. i used https://github.com/horverno/deep-pilot/blob/rpi/ax12.py library for python 3 support. circuit is : https://cdn.instructables.com/FJF/UKDF/J4YFU1YG/FJFUKDFJ4YFU1YG.LARGE.jpg
you have to look at ax12.py line 131 and 142.
line 131 direction pin on your raspberry (mine 12, not 18 - BCM setting)
line 142: i set ttyAMA0 baudrate 1000000

gpio mode 15 ALT0
gpio mode 16 ALT0
sudo stty -F /dev/ttyAMA0 1000000

and

https://raspberrypi.stackexchange.com/questions/47671/why-my-program-wont-communicate-through-ttyama0-on-raspbian-jessie
------------------------------------------
same direction for ax12's

code i used:

from ax12 import Ax12
import time

leftId = 3
rightId =5

self = Ax12()

self.setMovingSpeed(leftId,100)
self.setMovingSpeed(rightId,1123) # 100 + 1023
time.sleep(1)

ps:sorry for my english.



0
None
Swann Schillingselcuky3

Reply 4 months ago

Thanks for the info...where does the following have to be applied?

gpio mode 15 ALT0
gpio mode 16 ALT0
sudo stty -F /dev/ttyAMA0 1000000

Because I am still having difficulties with the libraries...
Anyways great help, because all the other posts refer to Raspian Jessie and not Stretch!

Also Python3 support is nice!! Thanks for updating!! :)

0
None
Swann Schilling

Question 5 months ago

Hey, I am also getting the ax12.ax12.timeoutError: Timeout on servo 1,
it drives the servo and then stops with the error...
I can servos.ping(1) and servos.readPosition(1) without error...
servos.move(1,500) gives me an error!

Also I noticed my rx and tx is on alt5...dont know if that is an issue,
I am connecting with port = serial.Serial("/dev/serial0", baudrate=1000000, timeout=0.1)

If I am commenting out returnself.readData(id), everything works fine...and I can read and write to the servo.
I have only one servo connected!

0
None
Dens_26

1 year ago

Hi !

I try to control Dynamixel AX-12 with my Raspberry PI 3 running Raspbian Jessie. But it's not working !

I have connected the Ax12 like this:
Pin 2 to Pin 3 (data out to AX-12)
Pin 1 to Pin 19 (connected to RPi port 12 (GPIO 18))
Pin 18 (connected to RPi pin 10 RX)
Pin 17 (connected to RPi pin 8 TX)
Pin 10 to ground (RPi pin 6 GND)
Pin 20 to Vcc (5 Volt, RPi pin 4 5V)

And configurate following this :
https://raspberrypi.stackexchange.com/questions/47671/why-my-program-wont-communicate-through-ttyama0-on-raspbian-jessie

I use this python3 compatible code:
https://github.com/aimlabmu/dynamixel-rpi/blob/master/ax12/ax12.py

A simple test like this has no effect:

from ax12 import Ax12
import time

roby = Ax12()

while True :
roby.move(19,200)
time.sleep(5)

roby.move(19,800)
time.sleep(5)



Thank you,

3 replies
0
None
thiagohersanDens_26

Reply 1 year ago

Hello.

Have you checked that your seria port works? Maybe by connecting something else to the tx/rx terminals?

What circuit are you using to do the uart tx/rx multiplexing?

And have you double, triple, quadruple checked the circuit? That's usually a source of mistakes and it's hard to debug because there's no easy way to tell if the circuit is correct.

I usually build 3 of them to end up with 1 that works. And then when I know that the software is correct I fix the other circuits. I usually forget to solder a wire, or short something, or use the wrong IC... (there's a difference between the 74LS241 and the 74HC241, for exemple).

Hope this helps.
Good luck

0
None
Dens_26thiagohersan

Reply 1 year ago

Thanks for your quick response.

It's OK now: I can control the servo but I have a problem with the function "readData".

All functions wich use readData works a litle time and crash!

I can give orders to the servomotor but I can't read data.

I use this library modified for python3
https://github.com/aimlabmu/dynamixel-rpi/blob/master/ax12/ax12.py

Below, the function wich raises problem
def readData(self,id):
self.direction(Ax12.RPI_DIRECTION_RX)
reply = Ax12.port.read(5) # [0xff, 0xff, origin, length, error]
try:
# assert ord(reply[0]) == 0xFF
assert reply[0] == 0xFF
except:
e = "Timeout on servo " + str(id)
raise Ax12.timeoutError(e)

try:
# length = ord(reply[3]) - 2
# error = ord(reply[4])
length = reply[3] - 2
error = reply[4]

if(error != 0):
print("Error from servo: " + Ax12.dictErrors[error] + ' (code ' + hex(error) + ')')
return -error
# just reading error bit
elif(length == 0):
return error
else:
if(length > 1):
reply = Ax12.port.read(2)
# returnValue = (ord(reply[1]) returnValue = (reply[1] else:
reply = Ax12.port.read(1)
returnValue = reply[0]
return returnValue
except:
pass
# except Exception, detail:
# raise Ax12.axError(detail)

0
None
Dens_26Dens_26

Reply 1 year ago

Waouhh !!!!!

I don't understand!

It was OK. I had the port ttyS0 and now I have an error message "No such file or directory /dev/ttyS0

0
None
Jason30_07

1 year ago

Hi ! Thanks for the article. Anyway, i'm trying to control Dynamixel RX-24 using RaspberryPi or Arduino, is there anyone can help me?? or any recommended website to learn from? Please let me know, Thankyou for help anyway :D

1 reply
0
None
NicolásB77Jason30_07

Reply 1 year ago

Hey Jason!

I'll try too with an RX-24 with RaspberryPi. Could you solve how to do it? I would be very grateful if you could share any information. Thank you :)

0
None
mynameishamish

2 years ago

Hi There,

Please help! I'm trying to build out a circuit with multiple AX-12A's and was running into some issues that I was hoping you could help with. I'm able to drive one servo with the circuit you described, but I can't figure out how to drive more. When I send this code it runs both servo's during the move(1, ) commands and no motors during the move(2, ) commands, am I doing something wrong? Do I have to declare each servo id somewhere?

It behaves the same way (moving both servos at once most of the time, timing out sometimes) without the learnservos command in there.

Thanks so much!

6 replies
0
None
mynameishamishmynameishamish

Reply 2 years ago

Oops, it didn't attach my image, here is the code I'm trying to run. I also tried your multiple servo code from Github and that was giving the same issue.

from ax12 import Ax12

import time

self = Ax12();

self.learnServos(1,2)

while True:

self.move(1,200)
time.sleep(4)
self.move(1,800)
time.sleep(4)

self.move(2,200)
time.sleep(4)
self.move(2,800)
time.sleep(4)

Screen Shot 2017-03-08 at 3.05.20 PM.png
0
None
thiagohersan

Reply 2 years ago

That's a good circuit. But have you double, triple, quadruple checked the circuit? That's usually a source of mistakes and it's hard to debug because there's no way to tell if the circuit is correct.

I usually build 3 of them to end up with 1 that works. And then when I know that the software is correct I fix the other circuits. I usually forget to solder a wire, or short something, or use the wrong IC... (there's a difference between the 74LS241 and the 74HC241, for exemple).

0
None
thiagohersan

Reply 2 years ago

What circuit are you using to do the uart tx/rx multiplexing?

And it really shouldn't be a problem, but just in the interest of debugging, have you tried moving a motor with ID 0?

0
None
thiagohersan

Reply 2 years ago

Hi Katherine.
Did you look through some of the other comments here?

One common problem that people have been having is that configuring the serial port on newer Raspian versions is different than when I wrote the instructable. First thing I'd try is check if ttyAMA0 is working.

Then, also make sure the code reflects the number of motors you have, and each motor has its own address. If you try to run the code for 6 motors with less motors, it will probably crash when it waits for the response.

0
None
HarithA1

3 years ago

I have used your code to drive the motor at github, but the program will throw timeout exception after a few seconds. is it a problem related to timing? (i use the default setting, 1Mhz Baud rate)