Files
walker_control/readme.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

189 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.