# Dual BTS7960 Motor Controller ESP32-based differential drive robot controller with web interface, using two BTS7960 dual H-bridge drivers with current sensing and stall protection. ## Features - Web-based dual motor control panel with real-time current monitoring - Independent Forward/Reverse/Stop control for each motor with speed sliders (20-100%) - Current sensing on both H-bridge sides for each motor - Sample-based stall detection with automatic motor shutoff (per motor) - ADC offset calibration at startup for accurate current readings - Stall warning displayed on web interface per motor - Emergency stop for both motors ## Hardware ### Components | Component | Model/Specification | |-----------|---------------------| | Microcontroller | ESP32 LOLIN32 Rev1 | | Motor Drivers | 2× BTS7960 Dual H-Bridge Module | | Power Supply | 12V DC | | Sense Resistors | 4× 1kΩ (for current sensing) | ### BTS7960 Module Reference - [DeepBlue Embedded Guide](https://deepbluembedded.com/arduino-bts7960-dc-motor-driver/) - [BTN7960 Datasheet](https://www.infineon.com/dgdl/Infineon-BTN7960-DS-v01_01-EN.pdf) ## Wiring ### Pin Assignments Both drivers share enable pins (they enable/disable together). | 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 (RPWM) --------------------> RPWM GPIO 33 (LPWM) --------------------> LPWM GPIO 36 (R_IS) <-------------------- R_IS GPIO 39 (L_IS) <-------------------- L_IS ``` ### Current Sensing Circuit The BTS7960 has IS (Current Sense) pins that output current proportional to motor load. A resistor converts this to voltage for ESP32 ADC. ``` BTS7960 Module ESP32 ┌─────────────────┐ ┌──────┐ │ R_IS (pin 7) ─┼──────┬───────┤GPIOxx│ (34 for M1, 36 for M2) │ │ [R] │ │ │ │ 1kΩ │ │ │ GND ─┼──────┴───────┤GND │ │ │ │ │ │ L_IS (pin 8) ─┼──────┬───────┤GPIOxx│ (35 for M1, 39 for M2) │ │ [R] │ │ │ │ 1kΩ │ │ │ GND ─┼──────┴───────┤GND │ └─────────────────┘ └──────┘ ``` **Note:** GPIO34, 35, 36, 39 are input-only pins on ESP32, ideal for ADC readings. ### Current Sensing Math | Parameter | Value | Formula | |-----------|-------|---------| | Sense Ratio | 8500:1 | I_sense = I_motor / 8500 | | Sense Resistor | 1kΩ | V_sense = I_sense × R | | At 4A motor current | 0.47V | (4 / 8500) × 1000 | | Max readable current | 28A | (3.3V × 8500) / 1000 | ## Configuration Key settings in [`include/config.h`](include/config.h): | Setting | Default | Description | |---------|---------|-------------| | `STALL_THRESHOLD` | 8.0A | Current threshold for stall detection | | `STALL_CONFIRM_SAMPLES` | 3 | Number of consecutive samples to confirm stall (~300ms) | | `STALL_STABILIZE_MS` | 500ms | Ignore current spikes after direction change | | `PWM_FREQ` | 20kHz | PWM frequency (reduces motor noise) | | `MIN_PWM_PERCENT` | 20% | Minimum PWM when motor is running | | `CURRENT_LOG_INTERVAL_MS` | 100ms | Current sampling/logging interval | | `CURRENT_SENSING_ENABLED` | true | Enable/disable in [`src/motor.cpp`](src/motor.cpp) | ## Network | Setting | Value | |---------|-------| | WiFi SSID | tami | | Static IP | 10.81.2.185 | | HTTP Port | 80 | ## Build & Upload ```bash pio run # Build pio run -t upload # Build and upload pio device monitor # Serial monitor (115200 baud) ``` ## Web Interface Access the control panel at `http://10.81.2.185` (or the IP shown on serial monitor). ### Features - **Dual Motor Panels**: Side-by-side controls for Motor 1 (Left) and Motor 2 (Right) - **Current Display**: Real-time forward (FWD) and reverse (REV) current readings per motor - **Direction Status**: Shows FORWARD, REVERSE, or STOPPED per motor - **Speed Sliders**: Adjustable from 20% to 100% per motor - **Stall Warning**: Red banner per motor when stall is detected - **Emergency Stop**: Global button to stop both motors immediately ### API Endpoints | Endpoint | Method | Parameters | Description | |----------|--------|------------|-------------| | `/` | GET | - | Control panel HTML page | | `/status` | GET | - | JSON with both motors' status | | `/motor1/speed` | GET | `value` (0-100) | Set motor 1 speed percentage | | `/motor1/direction` | GET | `value` (-1, 0, 1) | Set motor 1 direction | | `/motor1/stop` | GET | - | Stop motor 1 | | `/motor2/speed` | GET | `value` (0-100) | Set motor 2 speed percentage | | `/motor2/direction` | GET | `value` (-1, 0, 1) | Set motor 2 direction | | `/motor2/stop` | GET | - | Stop motor 2 | | `/stop` | GET | - | Emergency stop (both motors) | | `/speed` | GET | `value` | Legacy: maps to motor1 | | `/direction` | GET | `value` | Legacy: maps to motor1 | ### Status JSON Format ```json { "motor1": { "speed": 50, "direction": 1, "currentR": 2.35, "currentL": 0.00, "stalled": false }, "motor2": { "speed": 50, "direction": -1, "currentR": 0.00, "currentL": 1.87, "stalled": false } } ``` ## Stall Protection The stall detection uses a sample-based approach for reliability (independent per motor): 1. **Threshold**: Current above 8.0A indicates potential stall (based on observed ~2A running vs ~17A stalled) 2. **Debounce**: 3 consecutive samples above threshold confirms stall (~300ms at 100ms intervals) 3. **Stabilization**: Ignores current spikes for 500ms after direction changes When stall is confirmed on a motor: 1. That motor stops immediately 2. Serial log: `MotorX STALL DETECTED! Current=X.XXA (threshold=8.0A)` 3. Web interface shows red "STALL!" warning on that motor's panel To resume operation, send a new direction command via the web interface.