Motor trimNEORACER DOCS
NEORACER DOCS
These docs are public and open source.Edit on GitHub
CALIBRATION / MOTOR TRIM

MOTOR TRIM.

When you call rc.drive.set_speed_angle(0, 0) the car should sit still, and a full command should give a speed you chose on purpose. Both of those are decided by the driver: the neutral is fixed, and the speed you actually get comes from a couple of constants you can read and change.

~0 minutesBeginnerneoracer_ros2_driverconfig/throttle.yaml + config/controller.yaml
FIG. A / WHAT YOU'RE CHECKING
// UNTRIMMEDDrifts ~30 cm in 5 s// TRIMMEDStationary, 5 s testrc.drive.set_speed_angle(0, 0): what should happen vs what does
Left: car at "0 speed" drifting forward on flat ground. Right: a correct neutral leaves the same command still for the full 5 second verify window.
01 / HOW IT WORKS

HOW IT WORKS.

The drive pipeline ends at the controller node, which owns the USB-CDC link to the OSCORE ESP32 and writes the per-tick command v <m/s> <deg> as a normalized request. The ESP32 turns that into the actual for the ESC. Neutral lives on the ESP32 itself, so when speed is zero the controller writes a zero command and the wheels should be still. If the car creeps at zero on a charged pack and a flat floor, the cause is the ESC's own neutral or mechanical drag in the drivetrain, covered in Hardware · Drivetrain, not a number you set here.

What you do control is how far a command goes. A speed of 1.0 does not send the ESC to full throttle; it is scaled down hard, on purpose, so a first program cannot launch the car across the room.

02 / YOU'LL NEED

WHAT YOU'LL NEED.

01

Open floor

At least 2 m wide.
Hardwood or sealed concrete is ideal for the verify run. Carpet introduces stiction that masks a real creep, so it is the wrong surface to judge neutral on.
02

Charged pack

Battery above half.
Below half charge the ESC's voltage compensation shifts, so a creep you see on a low pack may vanish on a fresh one. Judge neutral on a reasonably charged battery.
03

SSH to the Jetson

Where the driver lives.
The constants you tune are source files in the workspace on the car. You reach them over SSH, covered in Networking.
ssh racecar@neoracer
04

A way to stop

Release the bumpers.
The drive mux only forwards commands while a bumper is held. Let go and it publishes a stop, which is your fastest manual halt during a verify run.
FIG. B / FIVE STEPS, START TO FINISH
1
$_
SSH in
to the Jetson
2
Hold zero
watch for creep
3
Tune caps
throttle.yaml + controller.yaml
4
colcon build
apply the change
5
Verify
5 s stationary check
Read the neutral, change the caps if you want more speed, rebuild, and verify. The change is a couple of edited lines, not a separate tool.
03 / THE PROCEDURE

THE PROCEDURE.

bash
# 1. SSH into the Jetson (see Networking for the address). ssh racecar@neoracer # 2. Open the YAML the driver loads at launch. # config/throttle.yaml is the single source of truth for the speed # and steering caps. config/controller.yaml holds the ESP32 m/s # mapping and the steering trim in degrees. $EDITOR ~/ros2_ws/src/neoracer_ros2_driver/config/throttle.yaml $EDITOR ~/ros2_ws/src/neoracer_ros2_driver/config/controller.yaml # 3. Bump the top-speed cap a little if you want more headroom. # Small steps. The ESC response is not linear near the bottom of the # range, so a small change near zero can mean a large change at the # wheel. # 4. Re-launch teleop. Configs are read on launch, no colcon build needed. racecar teleop
04 / VERIFY

VERIFY THE NEUTRAL.

From the car, this holds a zero command for five seconds so you can watch for creep. The same script runs in the Playground first if you want to see the expected behaviour before trying it on hardware.

python
import racecar_core rc = racecar_core.create_racecar() HOLD_S = 5.0 timer = 0.0 def start(): global timer timer = 0.0 rc.drive.stop() print("Trim verify: holding zero for 5 s, watch for creep") def update(): global timer timer += rc.get_delta_time() rc.drive.set_speed_angle(0, 0) if timer > HOLD_S: rc.drive.stop() print("Moved? Check the ESC neutral and drivetrain drag, not software.") rc.set_start_update(start, update) rc.go()

Less than a centimetre of motion over five seconds is a pass. More than that points at the ESC neutral or mechanical drag, since the software is already sending exact neutral.

05 / WHERE IT LIVES

WHERE IT LIVES.

Both files are plain YAML the launch system reads on startup. Edit, re-launch racecar teleop, and the new caps are live. No colcon build, no firmware reflash. They live under the driver workspace at ~/ros2_ws/src/neoracer_ros2_driver/config/.

yaml
# ~/ros2_ws/src/neoracer_ros2_driver/config/throttle.yaml # Single source of truth for the top speed and steering caps. # All values are normalized to [-1, 1] across the pipeline. throttle: ros__parameters: max_forward: 0.25 # the speed /drive is measured against max_reverse: 0.25 max_steer: 1.00
yaml
# ~/ros2_ws/src/neoracer_ros2_driver/config/controller.yaml # ESP32 serial port, the normalized -> m/s drive mapping, the # steering trim, and the Flysky RC channel map. controller: ros__parameters: port: /dev/osrbot_base max_speed_mps: 2.0 steering_trim_deg: 0.0 throttle_channel: 2 steering_channel: 0 mode_channel: 4
  • A higher max_forward in throttle.yaml means more top speed for the same command.
  • Neutral is owned by the ESP32 firmware, not the YAML, so a creep at zero is the ESC neutral or drivetrain drag, not a value you set here.
  • Every student script that calls rc.drive.set_speed_angle() gets your caps for free on the next racecar teleop.