devdesk 241d1ae457 Fix stall oscillation loop in pingpong mode
When pingpong detected a stall and switched direction, only _stalled
and _stallStartTime were reset, leaving _stallCandidateCount and
_motorStartTime unchanged. This caused motor inrush current after
direction change to immediately trigger another stall, creating an
infinite oscillation loop.

Now calls resetStallDetection() which properly resets all stall state
including triggering the STALL_STABILIZE_MS grace period to ignore
inrush current.
2026-02-05 20:49:59 +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%