Skip to main content

Overview

Calibration is the process of finding the correct PWM (Pulse Width Modulation) pulse values that make your car’s steering servo and ESC (Electronic Speed Controller) respond properly to commands. Without proper calibration, your car may not steer correctly or may have incorrect throttle response.

Why Calibration Matters

  • Steering accuracy: Ensures the car steers the correct amount for each input
  • Throttle control: Sets proper stopped, forward, and reverse speeds
  • Safety: Prevents unexpected behavior during autonomous driving
  • Training quality: Accurate control produces better training data

Understanding PWM Values

What is PWM?

PWM controls servos and ESCs using electrical pulses:
  • Standard servo pulses: 1ms (full reverse) to 2ms (full forward)
  • Neutral position: 1.5ms (centered/stopped)
  • Frequency: Typically 50-60Hz (every 16-20ms)

PWM in Donkeycar

Donkeycar uses 12-bit PWM values (0-4095) based on the PCA9685 controller:
  • Typical range: 200-500 for most servos/ESCs
  • Neutral: ~370 (varies by hardware)
  • Left/Forward: ~460-500
  • Right/Reverse: ~220-290
These are example values. Your hardware will have different values. Never use values from examples without testing - always calibrate for your specific hardware.

Calibration Methods

Donkeycar provides two calibration approaches:
  1. Command-line calibration (donkey calibrate): Test individual channels
  2. Web-based calibration (calibrate.py): Real-time adjustment with visual feedback

Method 1: Command-Line Calibration

For PCA9685 Motor Controller

This is the most common setup for Donkeycar.
1
Start calibration tool
2
donkey calibrate --channel=0
3
Options:
4
  • --channel=<0-15>: PCA9685 channel number (0 for throttle, 1 for steering)
  • --address=<0x40>: I2C address (default: 0x40)
  • --bus=<1>: I2C bus number (default: autodetect)
  • --pwmFreq=<60>: PWM frequency in Hz (default: 60)
  • 5
    Test steering (Channel 1)
    6
    donkey calibrate --channel=1 --bus=1
    
    7
    You’ll see:
    8
    init PCA9685 on channel 1 address 0x40 bus 1
    Using PWM freq: 60
    
    Enter a PWM setting to test ('q' for quit) (0-1500):
    
    9
    Find steering values
    10
    Enter PWM values to test the servo:
    11
    370   # Start at neutral (should be centered)
    460   # Test left - wheels should turn fully left
    290   # Test right - wheels should turn fully right
    
    12
    Fine-tune by increments:
    13
    # If 460 is too far left, try:
    450
    440
    # Keep adjusting until you find the exact full-left position
    
    14
    Record your values:
    15
  • STEERING_LEFT_PWM: Full left turn (e.g., 460)
  • STEERING_RIGHT_PWM: Full right turn (e.g., 290)
  • 16
    Test throttle (Channel 0)
    17
    donkey calibrate --channel=0 --bus=1
    
    18
    Put your car on a stand or hold it so the wheels don’t touch the ground during throttle calibration!
    19
    Find throttle values
    20
    370   # Start at neutral - wheels should NOT spin
    400   # Gradually increase - note when wheels start moving
    500   # Test forward - wheels should spin forward
    220   # Test reverse - wheels should spin backward
    
    21
    ESC Reverse Setup:
    22
    Many ESCs require a special sequence to enable reverse:
    23
  • Set to neutral (370)
  • Set to full reverse (220) for 1 second
  • Return to neutral - reverse is now enabled
  • 24
    Record your values:
    25
  • THROTTLE_STOPPED_PWM: Neutral/stopped (e.g., 370)
  • THROTTLE_FORWARD_PWM: Maximum forward (e.g., 500)
  • THROTTLE_REVERSE_PWM: Maximum reverse (e.g., 220)
  • 26
    Update myconfig.py
    27
    Add your calibrated values:
    28
    PWM_STEERING_THROTTLE = {
        "PWM_STEERING_PIN": "PCA9685.1:40.1",
        "PWM_STEERING_SCALE": 1.0,
        "PWM_STEERING_INVERTED": False,
        "PWM_THROTTLE_PIN": "PCA9685.1:40.0",
        "PWM_THROTTLE_SCALE": 1.0,
        "PWM_THROTTLE_INVERTED": False,
        "STEERING_LEFT_PWM": 460,      # Your calibrated value
        "STEERING_RIGHT_PWM": 290,     # Your calibrated value
        "THROTTLE_FORWARD_PWM": 500,   # Your calibrated value
        "THROTTLE_STOPPED_PWM": 370,   # Your calibrated value
        "THROTTLE_REVERSE_PWM": 220,   # Your calibrated value
    }
    

    For Direct PWM Pins

    If using Raspberry Pi GPIO pins directly:
    donkey calibrate --pwm-pin="RPI_GPIO.BOARD.33"
    
    Pin format examples:
    • RPI_GPIO.BOARD.33: Board pin numbering
    • RPI_GPIO.BCM.13: BCM (Broadcom) numbering
    • PIGPIO.BCM.13: Using pigpio daemon

    For Arduino

    donkey calibrate --arduino --channel=9
    
    Use PWM values in range 0-180 (servo angle in degrees).

    Method 2: Web-Based Calibration

    The web interface provides real-time calibration with visual feedback.
    1
    Start calibration server
    2
    cd ~/mycar
    python calibrate.py drive
    
    3
    Access web interface
    4
    Open your browser to:
    5
    http://<your-car>.local:8887/calibrate
    
    6
    Replace <your-car> with your Raspberry Pi’s hostname.
    7
    Adjust steering
    8
  • Find the Steering section
  • Click + or - to adjust left/right values in increments of 10
  • Observe the servo movement in real-time
  • Use arrow keys for quick testing:
    • Left Arrow: Test left steering
    • Right Arrow: Test right steering
  • 9
    Adjust throttle
    10
  • Find the Throttle section
  • Click + or - to adjust forward throttle
  • Press Up Arrow to test: runs at full throttle for 5 seconds
  • Press Down Arrow to test reverse briefly
  • 11
    Ensure your car is on a stand or held off the ground when testing throttle!
    12
    Save values
    13
    The interface shows updated values in the text area. Copy these values to your myconfig.py:
    14
    STEERING_LEFT_PWM = 460
    STEERING_RIGHT_PWM = 290  
    THROTTLE_FORWARD_PWM = 500
    THROTTLE_STOPPED_PWM = 370
    
    The web interface is great for fine-tuning after initial command-line calibration. You can adjust values while seeing the camera feed and car response simultaneously.

    Configuration for Other Drive Trains

    I2C_SERVO (Legacy PCA9685)

    Older configuration style:
    DRIVE_TRAIN_TYPE = "I2C_SERVO"
    STEERING_CHANNEL = 1
    STEERING_LEFT_PWM = 460
    STEERING_RIGHT_PWM = 290
    THROTTLE_CHANNEL = 0  
    THROTTLE_FORWARD_PWM = 500
    THROTTLE_STOPPED_PWM = 370
    THROTTLE_REVERSE_PWM = 220
    PCA9685_I2C_ADDR = 0x40
    PCA9685_I2C_BUSNUM = 1
    
    I2C_SERVO drive train type is deprecated. Use PWM_STEERING_THROTTLE for new installations.

    MM1 (RoboHat MM1)

    donkey calibrate --channel=1  # for MM1
    
    Configuration:
    DRIVE_TRAIN_TYPE = "MM1"
    MM1_STEERING_MID = 1500
    MM1_MAX_FORWARD = 2000
    MM1_STOPPED_PWM = 1500
    MM1_MAX_REVERSE = 1000
    

    Differential Drive

    For tank-style steering, calibrate each motor separately:
    DRIVE_TRAIN_TYPE = "DC_TWO_WHEEL"
    DC_TWO_WHEEL = {
        "LEFT_FWD_DUTY_PIN": "RPI_GPIO.BOARD.18",
        "LEFT_BWD_DUTY_PIN": "RPI_GPIO.BOARD.16",
        "RIGHT_FWD_DUTY_PIN": "RPI_GPIO.BOARD.15",
        "RIGHT_BWD_DUTY_PIN": "RPI_GPIO.BOARD.13",
    }
    
    No PWM pulse calibration needed - uses duty cycle (0.0-1.0).

    Calibration Tips

    Steering

    • Start conservative: Begin with small steering angles
    • Check mechanical limits: Don’t force the servo past its physical limits
    • Test both directions: Ensure equal response left and right
    • Watch for binding: Wheels should move freely without catching

    Throttle

    • Find true neutral: Wheels should not move at all when stopped
    • Gradual acceleration: Find the minimum PWM where wheels just start moving
    • ESC calibration: Some ESCs need their own calibration procedure (check manual)
    • Reverse setup: Test that reverse works after enabling it

    Common PWM Ranges

    Steering servo (typical):
    • Left: 420-500
    • Center: 350-380
    • Right: 220-300
    ESC throttle (typical):
    • Forward: 400-550
    • Neutral: 350-380
    • Reverse: 200-280
    These ranges vary widely by manufacturer. Always calibrate your specific hardware.

    Testing Calibration

    Test steering

    cd ~/mycar
    python manage.py drive
    
    Access the web interface at http://<your-car>.local:8887
    1. Set mode to User
    2. Move the steering slider left/right
    3. Verify wheels turn to full lock in both directions
    4. Check that center position is straight

    Test throttle

    1. Lift car off ground
    2. Set mode to User
    3. Gradually increase throttle slider
    4. Verify:
      • Wheels don’t spin at zero throttle
      • Smooth acceleration forward
      • Reverse works (if equipped)
    Always test throttle with car elevated or held. Never test on the ground until you verify neutral/stopped works correctly.

    Troubleshooting

    Servo jitters or buzzes

    Cause: Stopped PWM value not at true neutral Solution: Fine-tune THROTTLE_STOPPED_PWM in smaller increments:
    THROTTLE_STOPPED_PWM = 370  # Try 369, 371, 372, etc.
    

    Steering reversed

    Solution: Swap the PWM values:
    "STEERING_LEFT_PWM": 290,   # Was 460
    "STEERING_RIGHT_PWM": 460,  # Was 290
    
    Or use the invert flag:
    "PWM_STEERING_INVERTED": True,
    

    Throttle reversed

    Solution: Swap forward/reverse or use invert flag:
    "PWM_THROTTLE_INVERTED": True,
    

    Limited steering range

    Check:
    1. Servo arm is properly attached (perpendicular at center)
    2. Mechanical linkages aren’t binding
    3. PWM values are at servo’s actual limits
    Adjust: Increase the difference between left/right values

    ESC not responding

    Check:
    1. ESC is powered (battery connected)
    2. Correct channel (usually 0)
    3. ESC is properly initialized (some need a startup sequence)
    4. PWM frequency matches ESC (typically 60Hz)

    Throttle works but reverse doesn’t

    ESCs require reverse activation:
    1. Set to neutral (stopped PWM)
    2. Set to full reverse for 1-2 seconds
    3. Return to neutral
    4. Reverse should now work

    Advanced: PWM Frequency Scaling

    If using non-standard PWM frequency:
    "PWM_STEERING_SCALE": 1.2,  # Adjust pulse width for different frequency
    
    Calculation:
    scale = actual_frequency / 60
    
    For 50Hz: scale = 50/60 = 0.833 For 75Hz: scale = 75/60 = 1.25

    Next Steps

    Once calibration is complete:
    1. Test drive: Learn to drive and collect data
    2. Collect training data: Drive manually and record good laps
    3. Train your model: Use collected data to train an autopilot

    Additional Resources

    Build docs developers (and LLMs) love