Raspberry Pi and AX-12A - No Response

Hello all,

I recently purchased a Dynamixel AX-12A to build a robot arm with my Raspberry Pi V4. Unfortunately I am unable to move the motor and I am a bit lost at how to debug further.

I have currently wired up a circuit as below:
https://github.com/jeremiedecock/pyax12/raw/master/docs/images/breadboard.png

I have followed the instructions on this blog (Configuring The GPIO Serial Port On Raspbian Jessie and Stretch Including Pi 3 and 4 - Spell Foundry) to make sure I can communicate through ttyAMA0 serial port. This is needed because on Raspberry Pi V3 onwards, bluetooth takes over the ttyAMA0. (Note I am not entirely sure what this means so hopefully someone here does.)

I then use the following Python code to send an instruction to the motor but I receive no response.

import serial
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
GPIO.setwarnings(False)

port = serial.Serial("/dev/ttyAMA0", baudrate=1000000, timeout=3.0)

while True:
    GPIO.output(18, GPIO.HIGH)
    port.write(bytearray.fromhex("FF FF 00 04 03 20 FF D8"))
    time.sleep(0.1)
    GPIO.output(18, GPIO.LOW)
    time.sleep(3)

As far as I know there are three areas to confirm are working:
1- signals are being sent out through Raspberry Pi
2- the circuit is wired correctly and working
3- the motor is able to recieve signals and react

I have tested 1) by connecting the RX pin straight onto the TX pin (like some feedback loop) and I notice that I can send and recieve messages.

I then tried to wire the TX from the raspberry Pi (as in the below image) straight into the Dynamixel DATA port to see if the motor will response but that doesn’t work either.
https://forum.arduino.cc/index.php?topic=384104.0

I am at a lost at what to do - can anyone advise?

Thank you

Again hard to know exactly what you are trying to do, with these bytes.

That is:
0xff 0xff - is the start of a packet
0x00 - ID… Not sure if this is valid ID ? looks like it might be, but I never tried it. Dynamixels ship with ID=1

0x04 - length
0x03 Instruction write
20 - starting register 0x20 32) Moving Speed
FF - first data byte? Moving speed is 2 byte so not sure what will happen
D8 - Checksum? Did not compute it to see if right.

But again not sure what you are trying to do as this is only setting one byte of moving speed? Which is used when you set a goal position.

You might try using one of Robotis libraries to help you out. Something like Dynamixel SDK or Dynamixel Workshop… More information up on their e-manual pages, like: DYNAMIXEL SDK

Note: I don’t use Python so probably much more help here.

Thank you for such a quick response.

This is the whole script that I am trying to run

import serial
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

port = serial.Serial('/dev/ttyAMA0', baudrate=1000000, timeout=3.0)
# port = serial.Serial('/dev/ttyS0', baudrate=1000000, timeout=3.0)
# port = serial.Serial('/dev/serial0', baudrate=1000000, timeout=1.0)

while True:
    GPIO.output(18, GPIO.HIGH)
    port.write(bytearray.fromhex('FF FF 01 05 03 1E 32 03 A3'))
    # port.write(bytearray.fromhex('FF FF 00 04 03 20 FF D8'))
    
    time.sleep(0.1)

    GPIO.output(18, GPIO.LOW)
    time.sleep(3)
    response = port.readlines(None)
    print(response)

    GPIO.output(18,GPIO.HIGH)
    port.write(bytearray.fromhex('FF FF 01 05 03 1E CD 00 0b'))
    time.sleep(0.1)
    GPIO.output(18,GPIO.LOW)
    time.sleep(3)
    print('looped')

It is taken from this blog post which says these commands do the following:

This is an example Python program, no wrapper for the AX12 exists? The values are hardcoded to move Dynamixel 1, Execute an action (5), send 3 bytes of data, MOVE command(1E) and 2 positions(32 03) followed by the CRC (A3). I needed a small sleep(0.1), the port.write takes more time and the output was already LOW.

I am familiar with a few Python SDKs and I have tried to use this one GitHub - jeremiedecock/pyax12: Python library to control Dynamixel AX-12 actuators. which seems like the most up to date. However, when calling the function (as below) which pings for a variety of motors across varying ids, I get no response.

from pyax12.connection import Connection
import RPi.GPIO as GPIO

# Connect to the serial port
serial_connection = Connection(port="/dev/serial0", baudrate=1000000, rpi_gpio=True)

# Ping the dynamixel unit(s)
print('starting scan')
ids_available = serial_connection.scan()
print('scan complete')

print()
print(ids_available)

# Close the serial connection
serial_connection.close()

I have tried a few instruction packets used in these libraries to no avail :frowning:

Sorry I am not much help when it comes to python. But for libraries. For c/c++ I used my own earlier, which was based off of the older bioloid library that Trossen Robotics (Interbotix) used.

But for most newer things would migrate over to use ones that Robotis developed and maintained as it is their servos.

And if it were me, the first things I would try include:

a) Hook up Logic Analyzer to the RPI ttl TX pin, RX pin, your direction pin and to the half duplex signal going to the servos. And see what is getting where. Note: I have a few Logic Analyzers by Saleae so this makes it easy.

b) Your last script shows: port="/dev/serial0"
Is that the correct port? Note in your previous post you showed: /dev/ttyAMA0

c) Not sure if everything is setup properly to give you access to the Serial port? I don’t know if you need any udev rules and/or if your user is part of the dialout group? Assuming that the device owner is dialout.
Note: I am mainly a windows person and it has been awhile since I did much with RPI.

Thanks again for your detailed response.

a) a logic analyser seems to be exactly what I am looking for. The key thing for me to figure out is whether the problem is hardware or software related and this seems like it will help. I’ve looked at Saleae and it is way above my budget - would this be suitable for a Raspberry Pi? Also, do you know what software people typically use to interact with Logic Analysers?

b) On my Pi, it looks like the /dev/serial0 “points to” /dev/ttyAMA0 so they function in the same way.

c) User access issues also came to mind and I did have to fiddle a bit to get the TX / RX pins working. I’ve tested that I am able to access / send data through these pins by hooking up the RX and TX pins together, sending a signal and confirming I get the response back, and this works.

Thanks again and if the Logic Analyser is okay to use, I think I will buy that and test the circuit.

Update: decided I am going to buy this analyser due to seemingly better software support.

Another Update

I’ve somehow managed to make the Dynamixel respond to commands. I’m not sure what change caused it but it is now able to move. However, I am unable to receive a response packet from the servo. I have attached a screenshot of the signals being sent around the circuit where the DATA line is connected to the DATA port of the Dynamixel. You can see that the signal sent from the Raspberry Pi is sent to the DATA port but nothing is returned back.

![Screenshot 2021-02-21 at 14.53.03|636x500](upload://eDU7S1bHfHpvB4Rb9yEcRpj37Gm.jpeg) 

I’m also unsure what the GPIO18 pin is used for.

The code I am running is the following (sending a PING to the motor)

import serial
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

port = serial.Serial('/dev/ttyAMA0', baudrate=1000000, timeout=3.0)

while True:
    GPIO.output(18,GPIO.HIGH)
    port.write(bytearray.fromhex('FF FF 01 02 01 FB'))
    time.sleep(0.1)
    GPIO.output(18,GPIO.LOW)
    r = port.readlines(None)
    print(r)
    time.sleep(3)

Does anyone know why the motor is not sending any data back?

Thank you.

Sorry again I do not use Python, so maybe someone who uses it can help.

I believe the issue is that your GPIO line is not being properly used.

That is depending on how your wiring works, it needs to be setup to be either HIGH when writing data out and LOW when trying to get data back or visa-versa. The pin is to direct which direction things should go…

Also you need to make sure it is properly setup to know when… I think you may have some better luck with something like:

import serial
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

port = serial.Serial('/dev/ttyAMA0', baudrate=1000000, timeout=3.0)

while True:
    GPIO.output(18,GPIO.HIGH)
    port.write(bytearray.fromhex('FF FF 01 02 01 FB'))
    port.flush()
    GPIO.output(18,GPIO.LOW)
    r = port.readlines(None)
    print(r)
    time.sleep(3)

But I have no idea what the readlines does or what the none is… That is how does it know what a line is with binary data, that has some specific format? But hopefully maybe you will see a response on scope…

EDIT: I forgot to mention the flush(), I think python has this? It supposed to wait until the pending tx have output. Not sure if it will properly wait until it fully completes outputting the last bits or not… Again scope will show hopefully

A quick note from your packet that reads AX-12A ID#1 model number(2 byte) will be :
FF FF 01 04 02 00 02 F6

Referring from the packet feature of DYNAMIXEL Wizard 2.0.

Kurt - thanks for clearing up the need for GPIO 18 - totally makes sense know that you’ve said it and looking at the code. Feel a bit silly not realising this myself.

Thank you also for the flush command as this seems to have got it working. The full script I am using to move the dynamixel is the following.

import serial
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

port = serial.Serial('/dev/ttyAMA0', baudrate=1000000, timeout=3.0)

while True:
    GPIO.output(18, GPIO.HIGH)
    port.write(bytearray.fromhex('FF FF 01 05 03 1E 32 03 A3'))

    port.flushOutput()
    GPIO.output(18,GPIO.LOW)
    
    num_bytes_available = port.inWaiting()
    print('Bytes Available:', num_bytes_available)

    status_packet_bytes = port.read(num_bytes_available)
    print('Status Packet: ', status_packet_bytes)

    time.sleep(1.5)

    GPIO.output(18,GPIO.HIGH)
    port.write(bytearray.fromhex('FF FF 01 05 03 1E CD 00 0b'))
    
    port.flushOutput()
    GPIO.output(18,GPIO.LOW)
    
    num_bytes_available = port.inWaiting()
    print('Bytes Available:', num_bytes_available)

    status_packet_bytes = port.read(num_bytes_available)
    print('Status Packet: ', status_packet_bytes)

    time.sleep(1.5)

This script will (most of the time) alternate setting the angle of a motor between two points. I say most of the time as for some reason it takes 5 a few loops before the motors respond and other times it responds straight away.

Robotis Will Son - thank you, I’m not entirely sure what i’m doing wrong. I’ve tried to find a version of the DYNAMIXEL Wizard 2.0 that works on the Raspberry Pi (Raspbian) but haven’t had any luck.

A slight comment also on the offical Python Dyanmixel SDK, I’ve noticed that there is no setting of the GPIO 18 (or any number) meaning that the SDK is not for use on the Raspberry Pi with my setup (using UART and GPIO).

Anyway, I’ll continue tinkering and post any problems and solutions I find in the process as it may help other people in the same situation as me.

Thank you!

@Escher
You can download the DYNAMIXEL Wizard 2.0 for Raspberry Pi which works on the latest Raspbian OS.
https://www.robotis.com/service/download.php?no=2004

In order to use DYNAMIXEL SDK without any modification, you can use DYNAMIXEL Starter Set to connect DYNAMIXEL and your SBC as described in the following video.