Close

The Protocol

A project log for Sly Bug

Fluffbug but with smart servos

dehipudeʃhipu 04/02/2023 at 19:501 Comment

To talk to a smart servo you use a half-duplex UART protocol – meaning both RX and TX is done over the same wire, just not at the same time. The microcontroller sends a command, and then releases the pin and switches it to input to let the servo reply. Many microcontrollers have a special UART mode for this, but since it's not supported in CircuitPython, for now I just connected the RX and TX pins together with 10kΩ resistors (to avoid having a short when both sides try to speak at the same time), and ignoring the looped back data whenever we send anything. I decided to use a raspberry pi pico for this, so later on I may implement proper half-duplex UART with the PIO assembly. For now this will do.

The datasheet for SCS0009 specifies the baudrate for the serial as 1000000 – it seems strange, not being a power of two or anything close, but it seems to work.

Now, there is a higher level protocol on top of that serial communication. We send and receive frames of data, and those frames have a well defined structure. An outgoing frame looks like this:

Once you send your frame, you switch to receiving, and wait for a reply frame. The reply frame has a slightly different, albeit similar structure:

This protocol is share by all of the FeeTech servos, and probably many other smart servos out there. The examples in the documentation are invaluable for implementing the details, because they are not immediately clear from the descriptions.

Now that you have the higher level protocol, you will need one more thing: the register map of the particular servo you want to control. This is also part of the documentation, and it's different for the different models of the servos. The most interesting registers for the SCS0009 are:

There are of course many more, including settings that are saved in the internal EPROM for the servo ID, its PID parameters or safety protections. We will not need those for now.

Now, let's talk more about commands.

Ping is simple – it just makes the given servo send a response. It can be useful to test the communication, check the ID of the servo (if you only connect one and send a ping to the broadcast ID), or get its status.

Read and write let you get or set the content of the registers. The read takes the number of the register and the number of bytes to read from it (some registers are 2 bytes long), and write takes the number of the register and the values to write. Easy.

The regwrite is interesting, because it lets you schedule a change in the register without actually committing it yet. You can do it for several servos, and then when you are ready, confirm the change by sending the action command to the broadcast ID. This is useful when you need to move several servos together at once.

Reset is self-explanatory. It resets the servo to the settings it has saved in its EPROM.

Finally, syncwrite is a command that lets you send to the broadcast ID a big chunk of data, and each servo will fish from it the data for its registers. It's faster then the regwrite+action way, but basically serves the same purpose – moving all the servos together at the same time.

That is pretty much all we will need. I will be making a CircuitPython library with all of this stuff next.

Special thanks to Abby from FeeTech for sending me all the necessary documentation! I would never figure it all out myself.

Discussions

sana.seo8060 wrote 01/17/2024 at 09:09 point

Great. Thanks a lot for sharing. https://ehallpass.us/

  Are you sure? yes | no