Overview
- Connect the two plates with the plate-to-plate cable, then plug the USB cable into one of them. That plate sends the data for both.
-
Open the serial port at 1,000,000 baud, 8N1, no flow control.
It shows up as a normal USB serial device, for example
/dev/cu.usbserial-…on macOS,/dev/ttyUSB0on Linux or a COM port on Windows. - Read lines. The plate starts streaming on its own about 10 seconds after power-up.
- Zero each channel with nobody on the plates, then convert to newtons.
Only one program can have the port open at a time. If ForceMate is connected, disconnect it first.
This page describes PlateMate firmware 1.9.0. Last updated 21 October 2026.
Data format
One line of ASCII text per sample, separated by single spaces and ending with \r\n.
# Two plates (83 bytes)
TTTTTTTTT AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE FFFFFFFF GGGGGGGG HHHHHHHH\r\n
# One plate (47 bytes)
TTTTTTTTT AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD\r\n
# Example
000184213 00012845 -0000312 00010022 00009871 00011534 00010498 00012003 00009960\r\n - T: timestamp, 9 digits, milliseconds since the plate with the USB cable was powered up.
- A–D: the plate with the USB cable. E–H: the plate connected to it by cable.
- Load cell order on each plate: back-left, back-right, front-right, front-left. The same order as ForceMate's CSV export.
- Each value is a signed integer, 8 characters including the minus sign.
- A line is always 83 bytes (two plates) or 47 bytes (one plate). Throw away any other line.
Commands
Every command is exactly 3 bytes: [command, value 1, value 2].
Unused values are 0. The plate passes commands on to the second
plate itself.
| Bytes (hex) | Command | What it does |
|---|---|---|
0D 01 00 | Start streaming | Streaming is on by default after power-up. Only needed after a stop. |
0D 00 00 | Stop streaming | Stops sending lines. |
0A 00 00 | Get plate info | Replies with 5 bytes: firmware major, minor, build, second plate connected (1/0), ADC type (1). |
01 RR 00 | Set sample rate | RR: 0A = 960 Hz (default), 0B = 480 Hz, 0C = 240 Hz, 00 = 120 Hz, 01 = 60 Hz. Not saved; back to 960 Hz after power-up. |
0E 01 00 | Load cell power on | On by default. |
0E 00 00 | Load cell power off | No valid readings until it is on again. |
Rules
- Wait at least 300 ms between commands. The plate pauses briefly after each one and ignores commands that arrive meanwhile.
- Stop streaming and empty the input buffer before Get plate info. Otherwise the 5-byte reply is mixed into the data.
- Don't send Start streaming to a plate that is already streaming.
Converting to newtons
The values are counts with each load cell's factory calibration already applied. They aren't zeroed. Per load cell:
newtons = (value - zero) × 0.004566577 zero is the channel's average over about a second
with nobody on the plates. There is no zero command; do it in
your software before each measurement, like ForceMate does. A
plate's total vertical force is the sum of its four load cells.
Where that number comes from: a 1,000 kg, 2 mV/V load cell on a 24-bit ADC at gain 128 gives 2,147.48 counts per kg, and 9.80665 N / 2,147.48 = 0.004566577 N per count.
Timing and two plates
- Time axis: use sample number ÷ sample rate. Sampling is driven by a 4.9152 MHz crystal oscillator (±50 ppm), so this is the precise clock. The timestamp has 1 ms resolution and comes from the microcontroller's internal RC oscillator (about ±1 %), so don't use it as the time axis. ForceMate also uses a fixed 1/960 s between samples.
- Missed samples: there is no sample counter. Count lines with the wrong length; those are the usual losses. The timestamp normally steps 1 or 2 ms per line, so a step of 3 ms or more also means lines were lost.
- Synchronisation: each plate samples on its own crystal. The plate with the USB cable pairs each of its samples with the latest one from the second plate, so the two are within one sample (about 1 ms) of each other. On firmware older than 1.9.0 the second plate lags by one sample.
- Power-up: the plate looks for a second plate only in its first second after power-up. Connect the plate-to-plate cable before the USB cable. If the second plate is unplugged while streaming, its last values repeat.
Example (Python)
import time
import serial # pip install pyserial
PORT = "/dev/cu.usbserial-XXXX" # Windows: "COM3", Linux: "/dev/ttyUSB0"
NEWTON_PER_COUNT = 0.004566577
def send(ser, *command):
ser.write(bytes(command))
time.sleep(0.3) # the plate ignores commands sent closer together
with serial.Serial(PORT, 1_000_000, timeout=1) as ser:
send(ser, 0x0D, 0x00, 0x00) # stop streaming
ser.read(ser.in_waiting) # throw away buffered lines
send(ser, 0x0A, 0x00, 0x00) # plate info
major, minor, build, dual, _ = ser.read(5)
print(f"Firmware {major}.{minor}.{build}, two plates: {bool(dual)}")
send(ser, 0x0D, 0x01, 0x00) # start streaming
ser.readline() # first line may be partial
def read_sample():
while True:
line = ser.readline()
if len(line) in (47, 83): # skip damaged lines
t_ms, *counts = map(int, line.split())
return t_ms, counts
# Zero: average 1 s with nobody on the plates
first = [read_sample()[1] for _ in range(960)]
zero = [sum(ch) / len(first) for ch in zip(*first)]
while True:
t_ms, counts = read_sample()
newtons = [(c - z) * NEWTON_PER_COUNT for c, z in zip(counts, zero)]
print(t_ms, round(sum(newtons[:4])), round(sum(newtons[4:]))) Not covered
Firmware updates and the calibration commands are not part of the public protocol. They can overwrite a plate's factory calibration or leave it unusable. Please don't send command numbers that aren't listed on this page.
Going wireless instead? See the BLE protocol. GroinMate and NordicMate use a different format; email [email protected] for details.
If something doesn't work as described here, email [email protected]. Include the plate's serial number and firmware version, and what you sent and received.