devdesk 63ad41970c Fix current sensor showing ~1A at idle by calibrating ADC offset
- Add zero-current offset calibration at startup (16 samples averaged)
- Store per-channel offsets (_adcOffsetRight, _adcOffsetLeft)
- Subtract calibrated offset in readCurrentSense() before conversion
- Fixes ESP32 ADC inherent offset causing false ~1A readings at idle
2026-02-05 17:56:43 +02:00

BTS7960 Motor Controller

ESP32-based DC motor controller with web interface, using BTS7960 dual H-bridge driver with current sensing and stall protection.

Hardware

Components

Component Model/Specification
Microcontroller ESP32 LOLIN32 Rev1
Motor Driver BTS7960 Dual H-Bridge Module
Power Supply 12V DC
Sense Resistors 2× 1kΩ (for current sensing)

BTS7960 Module Reference

Wiring

Motor Control Pins

BTS7960 Pin ESP32 GPIO Function
RPWM GPIO25 Forward PWM
LPWM GPIO26 Reverse PWM
R_EN GPIO27 Right Enable
L_EN GPIO14 Left Enable
VCC 3.3V Logic Power
GND GND Ground

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)  ─┼──────┬───────┤GPIO34│
│                 │      │       │      │
│                 │     [R1]     │      │
│                 │     1kΩ      │      │
│                 │      │       │      │
│  GND           ─┼──────┴───────┤GND   │
│                 │              │      │
│  L_IS (pin 8)  ─┼──────┬───────┤GPIO35│
│                 │      │       │      │
│                 │     [R2]     │      │
│                 │     1kΩ      │      │
│                 │      │       │      │
│  GND           ─┼──────┴───────┤GND   │
└─────────────────┘              └──────┘
Connection Details
R_IS → GPIO34 Through 1kΩ resistor to GND
L_IS → GPIO35 Through 1kΩ resistor to GND

Note: GPIO34 and GPIO35 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:

Setting Default Description
STALL_CURRENT_THRESHOLD 4.0A Current triggering stall detection
STALL_DETECT_TIME_MS 500ms Duration before stall confirmed
PWM_FREQ 20kHz PWM frequency (reduces motor noise)
CURRENT_SENSING_ENABLED true Enable/disable in src/motor.cpp

Network

Setting Value
WiFi SSID tami
Static IP 10.81.2.185
HTTP Port 80

Build & Upload

pio run              # Build
pio run -t upload    # Build and upload
pio device monitor   # Serial monitor (115200 baud)

Stall Protection

When motor current exceeds 4.0A for 500ms continuously:

  1. Stall is detected
  2. Motor stops immediately
  3. Serial log: STALL PROTECTION: Stopping motor (current: X.XXA)

To resume operation, send a new speed/direction command via the web interface.

Description
a walker
Readme 331 KiB
Languages
C++ 90.2%
C 9.8%