← Back to all participants
RideScan Integration Hackathon

Builder Case Study - Project Sentinel

Finding the One Failure Channel That Matters on a 29-Joint Humanoid

Sharanya, Computer Science graduate from IIT Bombay. I worked with a Unitree G1 humanoid simulated in MuJoCo, building the inspection mission, telemetry pipeline, and RideScan integration on top of an existing robot platform rather than building the robot from scratch. I used pretrained ONNX reinforcement-learning policies for walking, crouching, and reaching, which let the mission produce realistic simulated joint and sensor telemetry for calibration. I chose the G1 because its 29 joints make it one of the toughest robots to monitor: a small actuator fault can cascade through the whole body. It is also commercially relevant because a humanoid can operate in human-designed industrial facilities and inspect equipment without major infrastructure changes.

The problem you set out to solve

The robot runs an autonomous acoustic leak-inspection patrol through a hazardous gas-processing plant. Using an 8-mic acoustic array, it listens outward for gas leaks while walking a fixed route; when it hears a leak, it turns and diverts toward that source before continuing the patrol. The mission makes it turn between stations, step up onto an inspection platform, reach to read gauges, and deep-crouch to check valves before returning to dock. Safety monitoring matters because nobody can rescue the unit mid-patrol, a failing humanoid near live equipment becomes a new hazard, and finishing the route is not the same as being healthy: the robot can complete every station while an actuator quietly wears out.

Your integration with RideScan

How I connected

Mapped the G1 MuJoCo stack onto RideScan's hierarchy: Robot → Mission → Mission Instance → Calibration → Inference. Registered the robot as Sentinel and the leak-inspection patrol as the mission. Saved each run as one CSV mission instance. Upload path: fifteen healthy files as calibration → call calibrate → upload stressed files as process files → call process → read risk scores.

What telemetry I sent (~147 columns at ~50 Hz)

  • Always present: timestamp and mission_phase_id (so runs can be compared phase by phase).
  • Body motion: base pose (x/y/z), orientation (roll/pitch/yaw), linear and angular velocity, IMU acceleration.
  • Per joint (×29): angle, velocity, torque, and command-versus-measured residual (116 columns).
  • Balance and contact: foot ground-reaction forces (both feet), centre of mass.
  • Acoustics (extra): band-power channels and direction-of-arrival. MuJoCo has no audio, so these come from a separate acoustic model. They matter because hearing the leak is the mission.

Key technical decisions

MuJoCo with a fixed seed can replay the same motion byte for byte. That is great for repeatability, but a zero-variance baseline is unrealistic for sensors. So I kept the path locked and applied a per-run sensor model only to how sensors report that path. Noise effects included: bias/scale error, axis misalignment, slow drift, saturation, quantization, pose latency, timestamp jitter, and short torque lag (~5 ms). Magnitudes follow component datasheets (BMI088-class IMU, 14-bit encoders, motor-current torque, load-cell feet), and each effect was checked in the CSV outputs before calibration.

Beyond the minimum path: a stress campaign on the same patrol

  • The mission already loads the full body: walk, turn, step-up, reach, deep crouch.
  • Experiment 1: global noise ladder (all sensors scaled together from clean to extreme).
  • Experiment 2: stress one sensing class at a time (IMU, torque, joint encoders/residuals, latency, mixed).
  • Experiment 3: joint-family ablation (corrupt only ankles, or only knees, or only hips, waist, or arms).
  • Experiment 4: DOF-budget curve (corrupt 1, then 3, then 6, then 12, then all 29 joints at the same per-joint noise).
  • Goal: show that when measurement quality gets worse, risk scores rise, and show which parts of a 29-DOF humanoid move the score most.

What the RideScan data showed

Healthy baseline (calibration)

  • Fifteen identical healthy patrols with only small zero-mean datasheet noise.
  • Risk scores: 0.0 to 0.22. That became the healthy floor for this mission.

Experiment 1: global noise ladder

What I did: kept the same patrol and scaled noise on all sensors together (0.2× to 2.5×).

Observation: as overall sensor noise went up, the risk score went up in order (3.72 → 40.3). The robot still finished the route every time, so the score is tracking signal health, not mission completion.

Noise levelMultiplierRisk score
Very Clean0.2×3.72
Low0.5×9.26
Medium-Low0.8×13.74
Moderate0.9×16.33
Baseline1.0×18.14
Medium-High1.2×22.25
High1.5×26.4
Very Noisy2.0×33.77
Extreme2.5×40.3

Experiment 2: one sensing class at a time

What I did: stressed only IMU, or only torque, or only joint encoders/residuals, or only latency, or a mixed case. First at about 2× intensity, then again at 5×.

In plain terms: the robot still walked the same route; I only made selected sensor columns in the CSV noisier or more delayed (IMU readings, torque readings, joint angle/velocity/residuals, or pose timing), so the score reacts to measurement quality, not a changed mission.

At about 2×, scores sat in a narrow band (roughly 9.8 to 13.7). Differences across sensing classes were hard to read. At 5×, the picture was clear:

Observation: for this humanoid patrol, joint-channel problems dominate. Corrupting joint feedback alone pushed risk near 43, while IMU, torque, and latency stayed near 3.

What was stressedRisk score
Torque only2.93
IMU only2.94
Latency only2.96
Mixed (IMU + torque + latency)2.96
Joint encoders / residuals only43.03

Experiment 3: joint-family ablation

What “family ablation” means in plain terms: I keep the same mission, but I add strong noise to only one group of joints at a time (for example only the ankles), and leave the other joints alone. That shows which body region the risk score cares about most. At 5× joint-channel noise:

Observation: which family fails matters. Ankles (4 joints) scored higher than hips (6 joints), so it is not only “more joints = more risk.” On a biped, distal support joints can matter a lot.

Joint familyHow many jointsRisk score
Knees23.95
Hips614.43
Ankles422.47
Waist323.1
Arms1424.62

Experiment 4: DOF-budget curve

What I did: used the same per-joint noise, but increased how many joints were corrupted: 1 → 3 → 6 → 12 → all 29.

Observation: risk rises as more of the body is corrupted. Full-body joint corruption (~43) matches the all-joint subsystem result from Experiment 2.

Joints corruptedRisk score
1 (left ankle pitch)4.82
3 (left ankle + knee)15.73
6 (full left leg)19.54
12 (both legs)26.84
29 (full body)43.09

Simple takeaway across all four experiments

  • More sensor noise → higher risk score.
  • On this 29-DOF humanoid, joint feedback is the most sensitive channel.
  • Both which joints fail and how many joints fail move the score.

Limitations and honest findings

MuJoCo / simulation edge

With the same policy and seed, MuJoCo can produce byte-identical telemetry every run. That is why I added data sheet-like sensor noise: to make the baseline closer to real sensor reporting. Even then, the sim does not account for weather, facility radio dropouts, mounting flex, true ultrasonic plant acoustics (I use an in-band proxy), or on-robot compute jitter on real hardware.

I also did not know in advance which sensor-noise range to use. I validated magnitudes from component references (Bosch BMI088-class IMU, 14-bit absolute encoders, motor-current torque estimates, and load-cell foot sensors) and used those data sheet-grounded values in the sensor model rather than picking noise levels at random.

What did not work cleanly at first

  • At about 2× stress, many scores sat close together (about 9.8 to 13.7), so failure modes looked almost the same.
  • At 5×, gaps opened: joint-only stress ~43 versus other subsystems ~3; DOF curve from ~5 to ~43.

What surprised me

  • Joint feedback outranked IMU, torque, and latency once stress was large enough.
  • Ankles (4 DOF) scored higher than hips (6 DOF).

What I would do differently

  • Choose stress intensity against the score range earlier, before uploading a flat 2× set.
  • Run the silent actuator-wear case next (mission still succeeds, one joint quietly degrades following a function map). The noise campaign proves sensitivity; it is not that full fault story yet.

RideScan edge

  • The upload path is schema-strict: column names, types, and required fields need to match exactly, which keeps the data contract clear once the mapping is locked.
  • Risk is returned as one score per run. To see which channels or joint groups mattered most, I used controlled ablation experiments on top of that score.

Results and what is next

What this Phase 3 work delivered

  • End-to-end humanoid integration: robot and mission registration, fifteen-run healthy calibration, and four live stress experiments.
  • Clear score patterns for global noise, sensing subsystem, joint family, and number of corrupted joints.

What I would build next

  • Phase-conditioned joint stress: add noise only during walk, or only during step-up, or only during crouch.
  • Left–right asymmetry: corrupt one leg only and compare to the other.
  • Silent ankle-wear inference: patrol still completes, but one actuator quietly degrades.
  • External-effects simulation: payload shifts, contact impacts, and acoustic-field changes in the plant.
  • A thin ROS 2 bridge so the same adapter can publish /joint_states and /imu for real fleets.