One wire, many servos, no second chance
DYNAMIXEL devices share a single half-duplex line. Every byte can be lost or corrupted, every node must frame, check and answer packets exactly as the specification says — on a microcontroller with a few kilobytes of RAM and, often, a safety argument to make.
Noisy, shared bus
Bytes arrive in any chunking, with noise and gaps. DXL2-C finds headers in the stream, checks Length and CRC, removes byte stuffing and resynchronizes by itself.
Tight embedded budgets
About 550 bytes of RAM per bus and a fixed, measured stack. No allocation, no globals, no OS: the same code runs bare metal, under an RTOS and on a PC.
Code you can certify
Zero MISRA C:2012 violations, a documented deviation register, 100 % line and branch coverage and static analysis in CI — reviewable in an afternoon.
A small library with a clear job
Two layers and ten functions: a codec for the wire format and a link that connects it to any transport through two callbacks.
Codec and link
Incremental parser, encoder with byte stuffing, CRC-16 and a transport-independent link that dispatches packets to your handler.
Any transport
UART, RS-485, USB, TCP or a simulator: pass received bytes in, provide a write function. Threading stays under your control.
Working examples
A bare-metal device tested in CI on a simulated board, a serial-port PING tool for Linux, macOS and Windows, and a Zephyr application.
DXL2 Studio
A desktop GUI on the same library: simulate a device, talk to real hardware and inspect every packet field by field.
Complete documentation
How it works, how to use and extend it, the wire format, a full API reference and a printable PDF manual.
Quality gates in CI
Every pull request runs the unit tests with a 100 % coverage gate, the MISRA check, Cppcheck, CodeQL and the examples.
Quick start
A minimal device in one file¶
Two callbacks connect the library to your hardware: a write function for the UART and a handler for received packets. This device answers PING with its model number and firmware version.
#include "dxl2.h"
static struct dxl2_link link;
static int uart_write(void* context, const uint8_t* data, size_t length)
{
(void) context;
return board_uart_write(data, length); /* 0 on success */
}
static void on_packet(const struct dxl2_packet* packet, void* context)
{
static const uint8_t ping_reply[] = {0x06, 0x04, 0x26}; /* model 1030, firmware 38 */
(void) context;
if ((packet->id == 1U) && (packet->instruction == DXL2_INST_PING))
{
(void) dxl2_link_send_status(&link, 1U, DXL2_ERR_NONE, ping_reply, sizeof(ping_reply));
}
}
int main(void)
{
const struct dxl2_link_config config = {.write = uart_write, .handler = on_packet};
(void) dxl2_link_init(&link, &config);
for (;;)
{
uint8_t bytes[32];
const size_t count = board_uart_read(bytes, sizeof(bytes));
dxl2_link_receive(&link, bytes, count);
}
}
board_uart_write() and board_uart_read() stand for your board's UART driver. The
examples are complete programs for bare metal, Zephyr and a PC serial port.
Find your way¶
| If you want to… | Read |
|---|---|
| Understand what the library does and does not do | Introduction |
| Build it, run the tests, add it to your project | Getting Started |
| Understand the layers, data flow and parser | How It Works |
| Write a device or a controller with it | Using the Library |
| Add instructions, transports or contribute | Extending the Library |
| Look up the bytes on the wire | Protocol |
| Look up a function | API Reference |
| Read everything offline or print it | PDF user manual |
SystemFromScratch®
Part of an open-source embedded portfolio
DXL2-C is developed by Anton Vynohradov under SystemFromScratch® — embedded software and hardware built from the first schematic to certification.
SystemFromScratch® is a registered trademark. DYNAMIXEL and ROBOTIS are trademarks of ROBOTIS Co., Ltd. DXL2-C is an independent implementation of the publicly documented protocol and is not affiliated with or endorsed by ROBOTIS.