
Productive Robotics
Nonius Encoder Calibration
Implemented absolute position calibration using Nonius (Vernier) encoders in C++ — a mathematical technique that resolves exact joint position across power cycles without homing sequences. Two gears with slightly different tooth counts (51 and 49) create a beat frequency that uniquely identifies the absolute revolution from a single encoder reading at 14-bit resolution (16,384 counts/rev). The same absolute position sensing technique used in high-end industrial robots from ABB, KUKA, and Fanuc.
Implemented the Vernier calculation algorithm in C++ (nonius_encoder.cpp): two gears with slightly different tooth counts (G1=51 output gear, G2=49 nonius gear) are mechanically coupled to the joint shaft, each with its own 14-bit encoder (16,384 counts per revolution). Because the tooth counts differ by 2, the relative phase between the two encoder readings uniquely identifies which absolute revolution the joint is at — the same mathematical principle used in Vernier calipers. The core algorithm: output_counts = fmod(motor_raw_rad × COUNTS_PER_REV / (2π), COUNTS_PER_REV), then revolutions = round((nonius_counts × G2 - output_counts × G1) / (COUNTS_PER_REV × (G1 - G2))), yielding the absolute revolution count from a single pair of encoder readings.
Configured per-joint gear ratio pairs from frybot.yaml: 51:49 for the main revolute and prismatic joints (J1, J2), 15:14 for the auxiliary BRS joints (BRS_V, BRS_H). For prismatic joints, the algorithm includes linear scale conversion factors (0.02, 0.01272, 0.03048 meters per revolution) to convert the rotary encoder output into linear position in meters. The computed home offset is stored to the ROS parameter server, surviving runtime but recalculated on each power-up via the calibration sequence. Nonius board polling uses a 5-second timeout with 50 retries at 100ms intervals waiting for the encoder board hardware to report valid data.
The practical benefit is eliminating homing sequences entirely — the robot knows its exact absolute position immediately on power-up from a single encoder reading, without needing to drive to a limit switch or reference point. This matters for three critical reasons in industrial robotics: safety (no unexpected motion on startup — the robot doesn't need to move to find home), uptime (no homing delay before the robot can start working — critical in production environments where minutes of downtime cost money), and crash recovery (the robot knows exactly where it is even after an unexpected power loss or emergency stop, enabling safe recovery without operator intervention).