Files
walker_control/plans/dual-motor-driver.md
devdesk f157d3abc5 feat: add dual BTS7960 motor driver support
- Refactor MotorController to parameterized class with MotorPins struct
- Add motor1 and motor2 instances with shared enable pins (GPIO 14, 27)
- Motor 2 uses GPIO 32/33 for PWM, GPIO 36/39 for current sense
- Update web UI with side-by-side dual motor control panels
- Add per-motor API endpoints (/motor1/*, /motor2/*)
- Add emergency stop button for both motors
- Legacy endpoints map to motor1 for backwards compatibility
- Update readme and AGENTS.md documentation
2026-02-06 15:05:13 +02:00

3.1 KiB

Dual BTS7960 Motor Driver Integration Plan

Overview

Add a second BTS7960 motor driver for differential drive robot, sharing enable pins between both drivers.

Hardware Configuration

Pin Assignments

Function Motor 1 Motor 2 Notes
R_EN GPIO 27 GPIO 27 (shared) Both drivers enable together
L_EN GPIO 14 GPIO 14 (shared) Both drivers enable together
RPWM GPIO 25 GPIO 32 Forward PWM
LPWM GPIO 26 GPIO 33 Reverse PWM
R_IS GPIO 34 GPIO 36 (VP) Current sense - input only
L_IS GPIO 35 GPIO 39 (VN) Current sense - input only

Wiring Diagram

ESP32 LOLIN32          BTS7960 #1         BTS7960 #2
--------------         ----------         ----------
GPIO 27 (R_EN) ------> R_EN -----------> R_EN
GPIO 14 (L_EN) ------> L_EN -----------> L_EN
GPIO 25 (RPWM) ------> RPWM
GPIO 26 (LPWM) ------> LPWM
GPIO 34 (R_IS) <------ R_IS
GPIO 35 (L_IS) <------ L_IS
GPIO 32 (RPWM2) --------------------> RPWM
GPIO 33 (LPWM2) --------------------> LPWM
GPIO 36 (R_IS2) <-------------------- R_IS
GPIO 39 (L_IS2) <-------------------- L_IS

Code Changes

1. config.h - Add Motor 2 pin definitions

// Motor 2 BTS7960 Pin Definitions
#define RPWM2_PIN 32    // Right PWM Motor 2
#define LPWM2_PIN 33    // Left PWM Motor 2
#define R_IS2_PIN 36    // Right Current Sense Motor 2
#define L_IS2_PIN 39    // Left Current Sense Motor 2

// Motor 2 PWM Channels
#define PWM_CHANNEL_R2 2
#define PWM_CHANNEL_L2 3

2. motor.h - Parameterized MotorController

struct MotorPins {
    uint8_t rpwm;
    uint8_t lpwm;
    uint8_t r_is;
    uint8_t l_is;
    uint8_t pwm_channel_r;
    uint8_t pwm_channel_l;
};

class MotorController {
public:
    MotorController(const MotorPins& pins, const char* name);
    void begin();
    // ... existing methods unchanged
private:
    MotorPins _pins;
    const char* _name;
    // ... existing members
};

extern MotorController motor1;
extern MotorController motor2;

3. motor.cpp - Use parameterized pins

  • Constructor stores pin config
  • begin() uses _pins.rpwm instead of RPWM_PIN, etc.
  • Serial output includes motor name for debugging

4. webserver.cpp - Dual motor API

New endpoints:

  • /motor1/speed, /motor1/direction, /motor1/stop
  • /motor2/speed, /motor2/direction, /motor2/stop
  • /status - returns both motors data

Keep legacy endpoints mapping to motor1 for backwards compatibility.

5. main.cpp - Initialize both controllers

void setup() {
    motor1.begin();
    motor1.setStallCallback(onMotor1Stall);
    motor2.begin();
    motor2.setStallCallback(onMotor2Stall);
    // ...
}

void loop() {
    handleWebServer();
    motor1.update();
    motor2.update();
    delay(1);
}

Notes

  • Enable pins are set HIGH once in motor1.begin - both drivers share them
  • GPIO 36 and 39 are valid for ADC input - they are input-only pins
  • GPIO 32 and 33 support both PWM and ADC, using them for PWM only
  • Web UI will need expansion to show both motors - consider tabbed interface or side-by-side layout