Cross-platform C++17 library to read a Resense HEX32 6-axis Force/Torque sensor via USB.
The Resense evaluation box enumerates as a USB CDC-ACM serial device, so the library opens it as a serial port (raw, 8-N-1, 2 Mbaud) and reads the same 28-byte binary frames as our Arduino library reads over UART. The API mirrors that library.
Please note that this is an unofficial library and that we are not affiliated with the Resense company. It is provided as-is under the MIT license and follows the public serial protocol used by our (likewise unofficial) Arduino library. "Resense" and "HEX" are trademarks of their respective owner.
| Platform | Serial backend | Status |
|---|---|---|
| Linux (incl. Raspberry Pi) | termios + poll |
tested on a Pi 5 |
| Windows | CreateFile + DCB + COMMTIMEOUTS |
tested (MSVC, VS2017) |
| macOS | termios + poll |
should work (same POSIX API), not hardware-tested |
| Property | Value |
|---|---|
| Baud | 2,000,000 (8-N-1) |
| Frame | 28 bytes = 7 × float32 little-endian |
| Order | fx fy fz mx my mz temperature |
| Units | force N, torque mNm, temp °C |
| Software trigger | SAMPLE\r\n → one frame back |
| Tare | TARA\r\n |
In continuous mode the sensor streams frames with no header byte, so the reader aligns to a frame boundary once (align()). In trigger mode each SAMPLE is answered by exactly one frame, so it self-aligns.
The output rate of continuous mode is set on the sensor (config buttons on the electronics, e.g. 1 kHz); it is not changed over USB.
| OS | Example |
|---|---|
| Linux | /dev/ttyACM0 or /dev/serial/by-id/usb-Resense_GmbH_HEX_6-axis_FT_Sensor_<serial>-if00 (stable, preferred) |
| macOS | /dev/cu.usbmodem<...> |
| Windows | COM7 (find it in Device Manager → Ports) |
On Linux, the user must be in the dialout group:
sudo usermod -aG dialout $USER # then re-loginThe HEX32 evaluation electronics is configured with the on-board buttons/switch — not over USB. For this library you want interface = USB (3) and a continuous sampling rate (5); zeroing is the Tara button (1).
| ID | Function | Description |
|---|---|---|
| 1 | Tara | 🔵 taring available ⚪ taring in process Holding Tara > 20 s enters bootloader mode (box appears as USB storage; drag-and-drop a .uf2 to flash firmware, then power-cycle). |
| 2 | Interface (Micro-USB) | USB: native micro-USB from the internal RP2040 (12 Mbit, full-speed), also supplies 5 V. UART: communicate with an external MCU at 2 Mbit (pinout in the manual). |
| 3 | Interface Selection | Switch selects the active interface: ⬅️ left = USB (use this for this library) ➡️ right = UART |
| 4 | Filter | Moving average of 10 unweighted samples: 🔵 enabled ⚪ disabled |
| 5 | Switch Mode | 🔵⚪⚪ Trigger ⚪🔵⚪ 1 kHz sampling ⚪⚪🔵 500 Hz sampling 🔵🔵🔵 100 Hz sampling |
| 6 | Matrix | 🔵 output is forces/torques in SI units (N, mNm) ⚪ output is raw per-axis signals |
For continuous reading with this library, set (3) → USB and (5) → 1 kHz (or 500/100 Hz). Trigger mode on (5) pairs with
triggerAndRead(). The internal RP2040 is why the box enumerates as a generic USB-serial device (VID2E8A) on Windows.
Image and settings table from our Arduino library (MIT).
cmake -S . -B build
cmake --build build -jProduces the static lib resensehex (CMake target resense::hex) plus the hex32_read and tara_test example programs. On Windows, open a Developer prompt (so MSVC is on PATH) before running CMake, or build with the VS generator.
# continuous stream, print every frame (Linux)
./build/hex32_read
# continuous, quiet: print achieved rate once per second -> confirms ~1 kHz
./build/hex32_read --quiet
# [rate] 991.0 Hz (991 frames in 1000 ms)
# log the 1 kHz stream to CSV
./build/hex32_read --quiet --csv run.csv
# zero the sensor over USB (or use the hardware button)
./build/hex32_read --tare
# Windows: pass the COM port
hex32_read.exe COM7 --quiet#include "ResenseHEX.hpp"
using namespace resense;
ResenseHEX hex("/dev/ttyACM0"); // or a by-id symlink, or "COM7" on Windows
if (!hex.open()) { /* hex.lastError() */ }
// continuous mode (the sensor streams at its configured rate):
hex.align();
HexFrame f;
while (hex.readFrameAndTimestamp(f))
printf("Fz=%.3f N T=%.2f C\n", f.fz, f.temperature);
// software-trigger mode (if the sensor is in trigger mode):
if (hex.triggerAndRead(f)) { /* ... */ }
// tare:
hex.tare(); // or hex.tareBlocking();open() / close() / isOpen()readFrame(f)/readFrameAndTimestamp(f)— continuous modealign()— find frame boundary for continuous streamingsoftwareTrigger()/triggerAndRead(f)— trigger modetare()/tareBlocking()sendCommand(str)/flushInput()validateLimits(f),setMaxForce/Torque/Temperature,setReadTimeout,setTareTimeoutlastError()— description of the last failure
include/ResenseHEX.hpp public API (HexFrame, ResenseHEX)
src/ResenseHEX.cpp platform-independent protocol (decode, align, trigger, tare)
src/SerialPort.hpp internal raw-serial backend interface
src/serial_posix.cpp Linux/macOS backend (termios + poll)
src/serial_win.cpp Windows backend (CreateFile + DCB + COMMTIMEOUTS)
examples/hex32_read.cpp streaming/CSV/rate-report demo
examples/tara_test.cpp tare diagnostic
Only the ~80 lines of raw serial I/O differ per platform; the protocol logic is shared.
- aarch64/x86/ARM are little-endian, matching the wire format, so frame decoding is a direct
memcpy. - The sensor enumerates as a full-speed USB device. If it drops off the bus (Linux
dmesgshowserror -110/-62, the device node disappears), that's a power/cable issue — use a powered USB hub and a good cable. - Taring over USB works, but on a cold / just-reconnected sensor the first
TARAmay have no effect; let it warm up and retry, or use the hardware button.
Independent C++/USB port of the protocol from TUDA-MUST/ResenseHEX (Arduino, MIT). MIT licensed — see LICENSE.
This is an unofficial project and is not affiliated with, authorized, or endorsed by Resense. All trademarks belong to their respective owners.

