Driving AX-12

You can skip this page if you have read the spec of the AX-12 already, but please take a look at the two notes I made at the bottom.

The AX-12 uses a small piece of memory (see page 12 of the spec) to store and retrieve all settings. Part of this memory is EEPROM meaning settings remain in tact after a power cycle, part of this memory is RAM. In practice there is no difference in working with these memory area’s. There are 7 commands that can be used to access the memory (see page 19) which all work the same: send a command to a specific ID, provide the start address and the number of bytes to write or read.

 The protocol used for communications is very straight forward, see page 20 for details.

  • 0xFF
  • 0xFF
  • ID
  • Length            3 + amount of data bytes
  • Instruction       0x02 for reading the memory location, 0x03 for writing the memory location
  • Data               1 or 2 bytes, in case of 2 the first byte is the low part, the second byte the high part
  • CheckSum     The low byte of the inverted sum of Length+Instruction+Data1 (+Data n)

As a response the AX-12 replies with a similar packet with the only difference that the instruction field is replaced with an error value (see page 11 what each means if set). In case of a write the amount of data bytes are 0, in case of a read it contains the amount of bytes requested. I wrote some test code using Atmel AVR Studio (Version 4.12, Service Pack 4, Build 498) using WinAVR as compiler (Build 2060421). The code can be downloaded here.

The unit Servo.C holds the functions of working with the servo’s. There are two functions available for accessing the memory:

  • unsigned char WriteData (unsigned char ToID, unsigned char Command, unsigned int Data)
  • unsigned char ReadData (unsigned char FromID, unsigned char Command, unsigned int *Data)

The ID’s are the number of the servo, the Command is a constant value as defined in the header file Servo.h which match the first address in memory. The Data field is 2 bytes in size, when the WriteData function is called a buffer is prepared containing all the bytes to send. This buffer is called TransmitPackage and the amount of bytes vary depending the command. The amount of data bytes is found in the function DataLength which returns 1 or 2 depending the command. If only one data bytes is needed for the command only the low part of Data is used.

When TransmitPackage is filled the CheckSum is calculated and added before all bytes in the buffer are send trough the serial port. When completed the receive buffer is enabled, the receiving part is interrupt based. As soon as a byte arrives the ISR USART0_RX_vect is called. If the byte is 0xFF than the variable FirstStartByte is set to true, when the second byte arrives and is 0xFF than SecondStartByte is set to true. After this all received data is stored in the buffer ReceiveBuffer until the frame is received, for this the Length byte of the frame is used.

When the data is received the function ProcessStatus is called. This verifies if the CheckSum is correct and if no error was reported. If not, the relevant part of the frame is copied in an application buffer ReceivedPackage and a bit is set in the NetworkStatus variable indicating a package has been received.

The receive part is interrupt based, after transmitting the frame the software steps into a wait loop until the ns_DataReceived bit is set in NetworkStatus or if there is no reply within “x” ms in which case an error is reported. For now this will remain so, in the future also the transmitting part will be interrupt based so that the main application can continue to work until a response has been received. Secondly a retry will be added in case an error occurs.

Above two functions can be used for setting and retrieving each memory location but it is limited to one location per call. In case of setting positions it makes sense to set the required speed at the same time. Luckily(?) the position and speed are placed directly after each other so this can be done faster using a function that sends the required 4 bytes to memory. This is available by calling the function GotoPosition.

  • unsigned char GotoPosition (unsigned char ToID, unsigned int Position, unsigned int Speed)

For each function the return value is a boolean indicating if the command executed correctly. If not the servo causing the program can be read from LastServoID and the error is stored in LastError. Both variables are located in Error.h.

Note 1: The AX-12 takes time to process the command given, if a second command is given within 15ms the servo does not respond.
Note 2: The image explaining the goal position on page 16 is wrong. It is shown from the back of the servo while it should have been the from (which contains the disc with four screw holes).

Go back to main page