AI Training Data Pipeline¶
This page maps the end-to-end flow from collecting exoskeleton data on the XM10 board to loading it into a training framework such as PyTorch or scikit-learn. Use it as a quick-reference map while you work.
The Rev 2.0 SDK (v2.9.0) again includes the feature that lets the board save data directly to a USB memory stick (USB Memory Logging). Rev 1.1 does not have it. This feature has not been tested on the board yet. (not yet confirmed on the board)
You can decode the saved folder to CSV on a PC with XM10 Log Decoder (guide). Rows where missing samples were filled in by interpolation are not measured values, so decide how to handle them before using them for training.
The standard route on this page is Path A below (USB-CDC real-time streaming). On-board storage (SD card) is not supported at present.
Big Picture¶
[Board operation] [Collection] [Conversion] [Training]
↓ ↓ ↓ ↓
KIT H10 worn → USB-CDC real-time streaming → CSV / npy output → PyTorch DataLoader
(xm10 tool → .xmlog → export) or sklearn
There are two paths. Choose based on your goal.
| Path | Best for | Data volume | Latency |
|---|---|---|---|
| A. USB-CDC streaming capture | Offline training (most cases) | Minutes to hours | < 100 ms |
| B. On-device inference | Deploying a trained model back to the board | — | 1 ms |
Path A — USB-CDC Streaming Capture (Standard)¶
1. Board Side — Streaming Custom Channels¶
Use the examples/09_CDC_Stream/ pattern. Stream the data you want to train on over a custom channel in real time.
void Control_Setup(void) {
// Channel metadata (JSON): args are module_id, json_str
XM_SetUsbCustomMeta(0xF0, "[{\"name\":\"hip_L\",\"unit\":\"deg\"},{\"name\":\"hip_R\",\"unit\":\"deg\"}]");
}
void Control_Loop(void) {
float sample[2] = { hip_L, hip_R };
XM_SendUsbDataWithId(sample, sizeof(sample), 0xF0); // arg order: (data, len, id) — every loop
}
2. PC Side — Receive Stream + Save CSV¶
On the PC side, receive the stream with the xm10 tool.
- xm10 tool (in the repo's
pc-data-tool/) — saves the raw bytes as-is to.xmlogand lets you pull CSV out later. Since you can re-export old recordings even after changing channel names/layout, it's better suited for managing a training dataset. Build it as an executable and it works on PCs without Python too (guide).
PhAI Studio is still under development, so for now use the
xm10tool to view and save your own (custom) data structs (0xF0–0xFE).
python pc-data-tool/xm10.py recv --cli --port COM6 --log # receive to console + save .xmlog (Ctrl+C to stop)
python pc-data-tool/xm10.py export data/cdc_<timestamp>.xmlog --csv out/ # export per-channel CSV
out/ gets ..._user_0xF0.csv (your channel) and ..._total_0x20.csv (the 197 channels the board always sends — joint angle/torque, IMU, GRF). Both files carry pc_time_us (PC receive time) and seq_id (the board's send sequence, shared across all channels) columns up front so you can align the time axis.
3. Loading into a Training Framework¶
PyTorch Example¶
import pandas as pd
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
class XM10Dataset(Dataset):
def __init__(self, csv_path):
df = pd.read_csv(csv_path)
self.data = df.select_dtypes("number").values.astype("float32") # shape (N, features)
def __len__(self):
return len(self.data) - 100 # 100-step window
def __getitem__(self, idx):
x = self.data[idx : idx + 100]
y = self.data[idx + 100, 0] # predict the first channel of the next step
return torch.tensor(x), torch.tensor(y, dtype=torch.float32)
ds = XM10Dataset("cdc_phai_20260224_120000_user_0xF0.csv")
loader = DataLoader(ds, batch_size=64, shuffle=True)
For large datasets, convert the CSV once with
np.save()to.npyfor much faster loading.
scikit-learn Example (Simple Classification)¶
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
df = pd.read_csv("cdc_phai_20260224_120000_user_0xF0.csv")
X = df[["imu_ax", "imu_ay", "imu_az", "knee_angle"]].values
y = df["gait_phase"].values
clf = RandomForestClassifier(n_estimators=100)
clf.fit(X, y)
Path B — On-Device Inference (Deploying a Trained Model)¶
Take a model trained via Path A and deploy it back to the board to run inference inside the 1 ms control loop.
1. Model Compression¶
Convert a PyTorch or TensorFlow model into a format the STM32 can handle.
| Tool | Output | Suitable models |
|---|---|---|
| TensorFlow Lite Micro | .tflite |
Small CNN, MLP |
| STM32Cube.AI | Auto-generated C code | TF / PyTorch / ONNX |
| Manual implementation | Hand-written C forward pass | Very small NN (≤ 3 layers) |
2. Running Inference on the Board¶
Ex.16 TinyAI Sensor Fusion demonstrates manual implementation (3-layer NN). Ex.36 OnDevice Kinesthetic Learning goes further and covers on-device learning as well.
Core pattern:
void Control_Loop(void) {
float input[3] = { imu_ax, imu_ay, imu_az };
float output[5];
my_nn_forward(input, output); // user-defined inference function
int gait_phase = argmax(output, 5);
if (gait_phase == STANCE_PHASE) {
XM_SetAssistTorqueRH(assist_table[gait_phase]);
}
}
Measure inference time using the loop profiling pattern from Ex.18 Debug Monitor to confirm it completes within 1 ms.
Common Pitfalls¶
- CSV is too large / slow — For large datasets, convert to
.npyor.parquetfor loading. Keep CSV for human inspection only. - Packet loss while streaming — Run
python pc-data-tool/xm10.py soak --port COM6 --minutes 10to check for dropped frames. If you captured via.xmlog, the missing ranges (GAP) show up right in theexportsummary. If there's loss, reduce the data volume or trim channels. - NaN / Inf values — Add
assert(isfinite(value))on the board side. Filter withnp.isfinite()just before training. - Class imbalance — Gait phases like Stance/Swing are naturally imbalanced (roughly 7:3). Use the
class_weightoption or SMOTE. - On-board inference exceeds 1 ms — Apply model quantization (int8) or reduce the number of layers. Verify that the STM32H7's FPU is being utilized.
Next Steps¶
- Practice the custom-channel streaming pattern with
Ex.09 CDC Stream - Progress from
Ex.16 TinyAI Sensor FusiontoEx.36 OnDevice Kinesthetic Learningfor on-device inference - After deploying a trained model to the board, try the full expert demonstration → model training → playback cycle as shown in
Ex.33 Kinesthetic Teaching
If you need more detail on the xm10 tool or Python post-processing, open a request on GitHub Issues.