| --- |
| license: cc-by-4.0 |
| tags: |
| - robotics |
| - mlp |
| - numpy |
| - obstacle-avoidance |
| - real-robot |
| - edge |
| - embedded |
| - industrial |
| - sensor-data |
| pretty_name: Real-Robot Driving MLP (NumPy) |
| --- |
| |
| # Real-Robot Driving MLP: the 101-parameter policy driving our robot's tracks on video |
|
|
| **101 learnable parameters · 2.4 KB file · 0.0073 ms per inference · 1.84 KB peak inference memory · numpy only, no framework.** |
|
|
| Inference numbers measured on a 12th-gen i7 laptop CPU, average over 100,000 runs. |
|
|
| At a 20 Hz control loop that is 0.015 % of the cycle budget: small is the point, not a limitation. |
|
|
| (An earlier revision of this card said 116 parameters. That count included the file's metadata arrays. The learnable weight and bias count is 101.) |
|
|
| Why does a company focused on predictive maintenance publish a robot driving model? |
|
|
| Because this robot is our test bed: the same recipe of tiny numpy networks, measured numbers, and self QA/QC on every stage is what we now focus on the predictive maintenance (PdM) of aging mechanical equipment. |
|
|
| This is the smaller, older sibling of |
| [NCDTech/sim-driving-mlp-numpy](https://huggingface.co/NCDTech/sim-driving-mlp-numpy). |
|
|
| A 101-parameter MLP trained not in simulation but on real driving sessions of our tracked test robot, collected through our desktop studio. |
|
|
| **This exact file is the one loaded and running in the video below.** |
|
|
| We traced it frame by frame: the load dialog in the recording shows this very filename. |
|
|
| ▶ **[Watch it run (3:18, Korean)](https://youtu.be/6DJX0T6qrtM)**: synthetic data check, analysis, training, weight transfer to the robot, and the network driving the tracks, end to end. |
|
|
| One honest detail you will notice: **the robot is propped up in the air.** |
|
|
| The LEGO-built chassis was too fragile for repeated floor runs, so for this NN test the tracks spin freely while the network drives them from live ultrasonic input. |
|
|
| The video's own thumbnail jokes about it ("hehe... right now it's floating!"). |
|
|
| ## Architecture |
|
|
|  |
|
|
| | part | meaning | |
| |------|---------| |
| | input (6) | ultrasonic distances **F**ront / **L**eft / **R**ight, plus their frame-to-frame deltas (ΔF, ΔL, ΔR). Distance tells "how far", delta tells "getting closer or not" | |
| | hidden (8) | one dense layer, leaky ReLU (α = 0.01) | |
| | output (5) | command logits: `FWD / LEFT / RIGHT / STOP / BACK` | |
|
|
| Normalization statistics (`norm_center`, `norm_scale`) are included in the file. |
|
|
| ## Metrics: an honest early scorecard |
|
|
| | command | accuracy | |
| |---------|----------| |
| | FORWARD | 76 % | |
| | LEFT | 85 % | |
| | RIGHT | 83 % | |
| | STOP / BACK | **0 %** | |
| | overall | 49 % | |
|
|
| We publish these numbers as they are. |
|
|
| The driving commands (F/L/R) worked well enough to drive the tracks in the video. |
|
|
| STOP and BACK scored zero because the training sessions barely contained those actions: class imbalance in a few minutes of real driving data. |
|
|
| Fixing exactly this kind of gap is why our current systems run self QA/QC on every stage. |
|
|
| The class-distribution check that would have flagged this dataset is now built in. |
|
|
| ## Load and run (NumPy only) |
|
|
| ```python |
| import numpy as np |
| |
| d = np.load("real_robot_mlp.npz") |
| x = np.array([[300.0, 150.0, 400.0, -5.0, -20.0, 0.0]]) # F, L, R, dF, dL, dR |
| x = (x - d["norm_center"]) / d["norm_scale"] |
| |
| h = x @ d["W0"] + d["b0"] |
| h = np.where(h > 0, h, 0.01 * h) # leaky ReLU |
| y = h @ d["W1"] + d["b1"] |
| |
| print(["FWD", "LEFT", "RIGHT", "STOP", "BACK"][int(np.argmax(y))]) |
| ``` |
|
|
| The whole file is 2.4 KB. |
|
|
| It runs on anything that runs NumPy, and the original target was an MCU-class robot controller. |
|
|
| ## The robot it drove |
|
|
| A frame from that video (2:37): the robot propped up on its support, tracks driven by **this network live at the same moment**. |
|
|
| The inference panel on the right shows the softmax over the five commands, and its judgment at this instant is STOP. |
|
|
|  |
|
|
| The hardware itself, with the ultrasonic sensors on the hand: |
|
|
|  |
|
|
| ## Sim and real, side by side |
|
|
| | | this model | [sim-driving-mlp-numpy](https://huggingface.co/NCDTech/sim-driving-mlp-numpy) | |
| |---|---|---| |
| | trained on | real driving sessions (test floor) | virtual-map simulation | |
| | inputs | 3 distances + 3 deltas | 4 distances (F/L/R/B) | |
| | size | 6→8→5, 101 params | 4→16→8→6, 270 params | |
| | extra head | none | turning-angle regression | |
| | date | 2026-04 | 2026-05 | |
|
|
| Together they show the path we actually took: drive the real robot first, feel the data problems, then build the simulation studio with self QA/QC wired into every stage. |
|
|
| That same discipline is now focused on predictive maintenance for aging mechanical equipment. |
|
|
| ## 한국어 |
|
|
| **영상 속에서 실제로 로드되어 돌던 바로 그 가중치 파일**입니다 (영상의 파일 열기 장면에서 파일명을 추적해 확인). |
|
|
| 시뮬 모델의 형뻘로, 가상 맵이 아니라 실제 주행 데이터로 학습했습니다. |
|
|
| 초음파 3방 거리 + 변화량 3개를 넣으면 주행 명령 5종이 나오는 101 파라미터 신경망(2.4 KB)입니다. |
|
|
| 추론 1회 0.0073 ms, 추론 메모리 1.84 KB, 의존성은 numpy 하나 (12세대 i7 노트북 CPU에서 10만 회 평균 실측). |
|
|
| (이전 판의 "116 파라미터"는 파일 속 메타 배열까지 센 수치였고, 학습 가중치 기준 정확한 수는 101입니다.) |
|
|
| 정직하게 밝혀둘 것 두 가지. |
|
|
| 첫째, 영상의 NN 테스트에서 **로봇은 공중에 떠 있습니다.** |
|
|
| 레고 블록 몸체라 하체가 약해 바닥 주행을 반복하기 어려웠고, 그래서 받침 위에 올려 신경망이 궤도(바퀴)를 모는 모습만 보여줍니다. |
|
|
| 영상 썸네일도 "후후.. 지금은 공중에 떠 있어요!"라고 먼저 밝히고 있습니다. |
|
|
| 둘째, 성적표 그대로: 주행 명령(전진 76%·좌 85%·우 83%)은 잘 동작했지만 **정지/후진은 0%** 입니다. |
|
|
| 몇 분짜리 실주행 데이터에 그 동작이 거의 없었기 때문입니다(클래스 불균형). |
|
|
| 바로 이런 구멍을 잡으려고 지금의 저희 시스템은 모든 단계에 셀프 QA/QC(클래스 분포 검사 포함)를 심었습니다. |
|
|
| 이 로봇은 저희의 테스트베드이고, 같은 기술을 지금은 노후 기계식 설비의 예지보전(PdM)에 집중하고 있습니다. |
|
|
| Learn more: https://huggingface.co/NCDTech · https://ncdtech.org · 주행 영상: https://youtu.be/6DJX0T6qrtM |
|
|