A cyclic redundancy check (CRC) is a calculated value used to detect errors in transmitted data. RoboClaw motor controllers append a 16-bit CRC, called a CRC16, to every packet serial command and response. The CRC16 uses the CCITT polynomial 0x1021 with an initial value of zero.
When data moves between two digital systems, there is always a chance that it arrives changed. Electrical noise on a serial line, a loose connection, or a power fluctuation can flip bits in transit. For a motor controller that risk matters: a corrupted command could set the wrong speed or drive the wrong channel. RoboClaw motor controllers validate every packet serial command with a CRC16 checksum and only act on packets that pass the check.
If you control your RoboClaw with the official Basicmicro libraries for Arduino, Python, or ROS 2, the CRC16 is calculated for you. The libraries handle the checksum, byte formatting, and packet structure on every command, whether your code runs on an Arduino, a Raspberry Pi, or a desktop PC. This article explains how the calculation works for anyone implementing packet serial directly, and includes working code in C, Python, and C#.
What Is a Cyclic Redundancy Check?
A cyclic redundancy check runs the bytes of a message through a fixed mathematical procedure and produces a short value, the CRC, that acts as a fingerprint of the message. The sender calculates the CRC and appends it to the end of the message. The receiver runs the same calculation on the bytes it received and compares its result to the CRC that arrived with the message. If the two values match, the data is intact. If they differ, the message was corrupted somewhere in transit and should be discarded.
A 16-bit CRC is a strong error detector for short messages. It catches every single-bit error, and it catches every burst error up to 16 bits long. Most other corruption patterns change the CRC as well, although no 16-bit check can distinguish every possible corruption. This makes it far more robust than a simple additive checksum, where two errors can cancel each other out and pass undetected. That robustness is why RoboClaw uses a CRC16 rather than a basic checksum to keep corrupted data from causing unintended behavior.
How Is the CRC16 Calculated?
The CRC16 processes the message one byte at a time, updating a running 16-bit value that starts at zero. Each byte is shifted left by 8 bits and XOR’d into the current CRC. The 8 bits of that byte are then handled one at a time. If the highest bit of the CRC is a 1, the CRC is shifted left by one bit and XOR’d with the polynomial 0x1021. If the highest bit is a 0, the CRC is only shifted left. After every byte of the message has been processed, the final CRC value is complete.
This exact combination of parameters has a name. RoboClaw’s checksum is the CRC-16/XMODEM variant: the CCITT polynomial 0x1021, an initial value of zero, and no final transformation of the result.
| Parameter | Value |
|---|---|
| Width | 16 bits |
| Polynomial | 0x1021 (CCITT) |
| Initial value | 0x0000 |
| Final XOR | None |
| Common name | CRC-16/XMODEM |
Online CRC calculators list dozens of CRC16 variants. RoboClaw’s checksum matches the variant usually labeled CRC-16/XMODEM. The similarly named CRC-16/CCITT-FALSE uses the same polynomial but starts at 0xFFFF, so it produces a different result for the same data. If a calculator’s output does not match your code, check which variant is selected.
Here is the calculation applied to a short test message:
Message: "Hello World" (11 bytes)
Polynomial: 0x1021
Initial value: 0x0000
crc16("Hello World", 11) = 0x992A
Running the same message through any of the code samples below produces the same value. A known test string like this is a quick way to confirm a new CRC implementation is correct before wiring it into packet code.
How Does RoboClaw Use the CRC16?
Every packet serial command follows the same basic structure: an address byte, a command byte, any data bytes the command requires, and the CRC16 appended as two bytes.
Send: [Address, Command, Data bytes, CRC16 (2 bytes)]
Receive: [Data bytes, CRC16 (2 bytes)]
The CRC16 is used in both directions. For incoming commands, the RoboClaw checks the CRC16 and only processes the packet when the data is valid. After a valid write command, such as a motor control or settings command, the controller replies with an acknowledgment byte of 0xFF. If the packet was corrupted, no acknowledgment is sent.
Responses from the RoboClaw carry a CRC16 as well, and validating them has one detail that is easy to miss. The CRC of a response is calculated over the address byte and command byte you sent, plus all of the data bytes received, excluding the final two CRC16 bytes. If your calculated value matches the received CRC16, the data arrived without error. An implementation that checks only the received data bytes will never match.
Two related details of the protocol matter when implementing it by hand. Values larger than one byte are sent in big-endian order, most significant byte first. And the RoboClaw enforces a 10 ms timeout between the bytes of a packet: if a byte arrives more than 10 ms after the previous one, everything received so far is discarded. Pausing at least 10 ms before retransmitting after a communication error puts the controller back in a clean state, ready for the next packet.
The official libraries handle all of this automatically: the CRC16 on every command and response, the acknowledgment byte, and the byte ordering. See Using the RoboClaw Arduino Library and Using the RoboClaw Python Library to get started with them.
CRC16 Code Examples
The three samples below implement the same algorithm in C, Python, and C#. Each one calculates the CRC16 of an example packet consisting of an address byte of 0x80 followed by a command byte of 0x00, which produces a result of 0x1B98.
C and Arduino
The sketch below is a complete Arduino program that prints the CRC16 of the example packet to the serial monitor. The crc16() function itself is plain C and compiles unchanged in any C or C++ project; only the setup() and Serial code are Arduino-specific.
// Calculates the CRC16 used by RoboClaw packet serial communication.
// CRC16 of nBytes of data in the packet array.
// Polynomial 0x1021, initial value 0.
uint16_t crc16(unsigned char *packet, int nBytes) {
uint16_t crc = 0;
for (int byteIndex = 0; byteIndex < nBytes; byteIndex++) {
crc = crc ^ ((uint16_t)packet[byteIndex] << 8);
for (unsigned char bit = 0; bit < 8; bit++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ 0x1021;
} else {
crc = crc << 1;
}
}
}
return crc;
}
void setup() {
Serial.begin(9600);
// Example packet: address byte 0x80 followed by command byte 0x00
unsigned char testData[] = {0x80, 0x00};
uint16_t result = crc16(testData, 2);
// Prints: CRC16 result: 0x1B98
Serial.print("CRC16 result: 0x");
Serial.println(result, HEX);
}
void loop() {
}
Python
The Python version below works byte by byte in the same way. The masking with 0xFFFF keeps the running value within 16 bits, which C handles naturally through the uint16_t type. The Basicmicro Python library performs the same calculation internally, using a precomputed lookup table for speed, so a script that uses the library never needs this function directly.
#!/usr/bin/env python3
# Calculates the CRC16 used by RoboClaw packet serial communication.
def crc16(data):
"""Return the CRC16 of the given bytes using polynomial 0x1021, initial value 0."""
crc = 0
for value in data:
crc = crc ^ (value << 8)
for _ in range(8):
if crc & 0x8000:
crc = ((crc << 1) ^ 0x1021) & 0xFFFF
else:
crc = (crc << 1) & 0xFFFF
return crc
if __name__ == "__main__":
# Example packet: address byte 0x80 followed by command byte 0x00
packet = bytes([0x80, 0x00])
print(f"CRC16 result: 0x{crc16(packet):04X}")
C#
The C# version follows the same pattern and suits desktop applications that talk to the RoboClaw over a USB serial port. The casts back to ushort after each operation keep the value at 16 bits. The complete console program below prints the same example result.
// Calculates the CRC16 used by RoboClaw packet serial communication.
using System;
class Crc16Example
{
static ushort Crc16(byte[] packet, int nBytes)
{
ushort crc = 0;
for (int i = 0; i < nBytes; i++)
{
crc = (ushort)(crc ^ (packet[i] << 8));
for (int bit = 0; bit < 8; bit++)
{
if ((crc & 0x8000) != 0)
{
crc = (ushort)((crc << 1) ^ 0x1021);
}
else
{
crc = (ushort)(crc << 1);
}
}
}
return crc;
}
static void Main()
{
// Example packet: address byte 0x80 followed by command byte 0x00
byte[] packet = { 0x80, 0x00 };
// Prints: CRC16 result: 0x1B98
Console.WriteLine($"CRC16 result: 0x{Crc16(packet, 2):X4}");
}
}
Next Steps
The CRC16 is one piece of the packet serial protocol. RoboClaw Packet Serial with the Pololu A-Star 32U4 walks through building and sending complete packets from a microcontroller. To skip the low-level work entirely, Using the RoboClaw Arduino Library and Using the RoboClaw Python Library cover the official libraries that handle the CRC16 for you, with complete working examples.



