DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Introduction

This is a servo motor with decent performance… mainly it’s expensive.

Believing that expensive means good, they bought several XM430-W210 servos to build a robotic arm.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

First, they controlled the servos through the ROS interface, which worked fine. However, due to the poor real-time performance of ROS itself, they began the porting journey.

The DYNAMIXEL SDK is mainly documented at: https://emanual.robotis.com/docs/en/software/dynamixel/dynamixel_sdk/overview/

Code repository: https://github.com/ROBOTIS-GIT/DynamixelSDK

A host computer is also needed: https://emanual.robotis.com/docs/en/software/dynamixel/dynamixel_wizard2/

If you’re interested in ROS control, you can check: https://emanual.robotis.com/docs/en/software/dynamixel/dynamixel_workbench/

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

C++ Interface of DYNAMIXEL

The directory of the program files downloaded from GitHub is as follows

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Its C++ program structure is quite good and easy to port. The documentation generated by Doxygen is also clear.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

There are no driver programs for microcontrollers in the source code; they have an OpenCR based on Arduino.

The required programs are in the src and include folders.

As you can see, there are mainly two types: one for port operations on serial devices and the other for packet operations on data.

The PortHandler and PacketHandler classes provide many virtual functions that are inherited and overridden.

Then, by using getPortHandler and getPacketHandler, object pointers are returned. The final result is that it seems we only called the interfaces of PortHandler and PacketHandler during usage.

In short, just follow their specifications.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Rewriting Port Operations

Since it does not have the microcontroller support I wanted (Arduino does not count), I need to rewrite the communication port operations myself.

I directly copied port_handler_arduino.cpp and renamed it to port_handler_stm32.cpp.

Key functions to rewrite include getBytesAvailable(), readPort(uint8_t _packet, int length), and writePort(uint8_t _packet, int length).

For other functions, I just left them empty.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile
DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Modifying Packet Program

The corresponding file is protocol2_packet_handler.cpp

The data protocol specification is at: https://emanual.robotis.com/docs/en/dxl/protocol2/

At the beginning of the program, there is

#define TXPACKET_MAX_LEN    (1*1024)#define RXPACKET_MAX_LEN    (1*1024)

Change the values after this to (1*40).

In some programs, functions like malloc are used. Using malloc and free frequently in microcontrollers can lead to memory fragmentation on the RAM heap, and prolonged runtime may cause memory overflow.

uint8_t *rxpacket           = (uint8_t *)malloc(RXPACKET_MAX_LEN);.........free(rxpacket);

I changed it to something like the following, so that during runtime, the variable is stored in the stack corresponding to the current function (in bare-metal development, it’s the stack of the main function), and the function automatically releases it after completion, avoiding memory fragmentation issues.

uint8_t rxpacket[14]        = {0};

All the above modifications do not affect normal usage.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Microcontroller Porting

Using CubeMX, I generated the corresponding project, which simply configured a serial port and enabled serial port receive interrupts.

Then I added an irq.cpp file.

The main purpose is simple: to fill in the serial port receive interrupt function, placing the data received from the serial port interrupt into a designated container.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Then I wrote a buffer.cpp file to handle the data received from the serial port in the container.

In the previously mentioned file for rewriting port operations, I called/inherited functions from buffer.cpp. For specifics, see port_handler_stm32.cpp in the attached project.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Finally, I organized the program and left out interfaces.

Refer to the example files in the example folder.

In the stm32_hander.cpp file, I left a test function at the end.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

In the C8T6 (master branch) project, the chip used is STM32F103C8T6, which is the initial version. The code structure and interfaces have not been thoroughly reviewed.

In the RCT6 (RCT6 branch) project, the chip used is STM32F103RCT6, which has some extended interfaces, and the code structure has been slightly organized.

Regarding interface issues, there are some macro definitions in the code and the called packet functions that need attention as each servo model is different.

Specifically, you need to find the corresponding servo on the DYNAMIXEL website. For example, I currently use the XM430-W210 servo, and the website is: https://emanual.robotis.com/docs/en/dxl/x/xm430-w350/

Here you can find the corresponding addresses, ranges, and data byte sizes. The addresses need to be modified in the macro definitions.

Pay attention to the value ranges when you call them.

The data byte sizes correspond to the choices of write1ByteTxRx, write4ByteTxRx, read2ByteTxRx, and read4ByteTxRx in the program.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Mixed C/C++ Programming for Microcontrollers

In Keil, to support C++ programming, you need to change Target -> Code Generator -> ARM Compiler to Use default compiler version 6.

At the same time, on Linux, with the help of the Makefile generated by CubeMX, slight modifications can support C++ programming.

The main lines added are

CXX_SOURCES = 
.........
CXX = $(PREFIX)g++
.........
CXX_INCLUDES =  
.........
CXXFLAGS = -lstdc++ $(CFLAGS) $(CXX_DEFS) $(CXX_INCLUDES) -g -ggdb3 -fno-rtti -fno-exceptions 
-fverbose-asm -fdata-sections -ffunction-sections -fpermissive -Wa,-ahlms=$(BUILD_DIR)/$(notdir $(<:.cpp=.lst))
.........
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(CXX_SOURCES:.cpp=.o)))
vpath %.cpp $(sort $(dir $(CXX_SOURCES)))

And finally, note that when linking the .o files at $(BUILD_DIR)/$(TARGET).elf, you need to add -lstdc++ -specs=nosys.specs, otherwise, some C++ features will not be supported.

After modification, it looks like

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile    $(CC) $(OBJECTS) $(LDFLAGS) -lstdc++ -specs=nosys.specs -o $@     $(SZ) $@

Of course, you also need to refer to the startup files and link scripts for the GUN cross-compiler; see the makefile file and GCC folder in the project for specifics.

Using this makefile, we can compile our project in Linux, provided that the cross-compiler gcc-arm-none-eabi is properly installed.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile
DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

When performing mixed C/C++ programming, note that C++ files can call functions from C files, but if C++ functions want to be called from C, they need to be marked as extern “C”.

Many people online directly change the .c extension of the code generated by CubeMX to .cpp; while this can compile successfully and does not affect bare-metal, I do not recommend this approach. If it is a .c file, it should remain a C file.

Then, ensure that C++ and C files are decoupled in their calls. For example, if the main.c file needs to call servo control, create a DynamixelTest function, then mark it as extern “C”, and it can be called from main.c.

This way, logically, it separates the low-level code from the application-oriented C++ code, avoiding unnecessary conflicts. It’s better to keep the low-level drivers in C, and it will be easier to organize when compiling under Linux using makefile.

For specific makefile and project files, refer to the code on Gitee, at https://gitee.com/TerryAAA/dynamixel-sdk.git

It has two branches: master is for STM32F102C8T6, and the RCT6 branch corresponds to STM32F102RCT6.

Record completed~

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

Robot Grasping Based on Deep Learning

This course will guide everyone to learn the concepts and classifications of robot grasping algorithms based on deep learning, and build a grasp detection dataset from scratch, train the classic grasp detection network GGCNN, and gradually integrate GGCNN with the PyBullet simulation environment and Kinova robotic arm.

DYNAMIXEL Servos: Mixed C/C++ Programming with Keil and Makefile

(Scan to view course details)

Leave a Comment