7.0 KiB
Motor Control Module
This module provides safe and reliable control of water pumps using the TB6612FNG motor driver.
Features
- Dual Motor Control: Independent control of 2 DC water pumps
- PWM Speed Control: Variable speed from 20% to 100%
- Safety Features:
- Maximum runtime protection (default 30 seconds)
- Minimum interval between runs (default 5 minutes)
- Soft-start to reduce current spikes
- Emergency stop functionality
- Runtime Statistics: Track usage, runtime, and error counts
- MQTT Integration: Full remote control and monitoring
- NVS Persistence: Statistics survive reboots
Hardware Connections
ESP32-S3 to TB6612FNG Wiring
| ESP32-S3 | TB6612FNG | Function |
|---|---|---|
| GPIO4 | AIN1 | Pump 1 Direction |
| GPIO5 | AIN2 | Pump 1 Direction |
| GPIO6 | BIN1 | Pump 2 Direction |
| GPIO7 | BIN2 | Pump 2 Direction |
| GPIO8 | PWMA | Pump 1 Speed (PWM) |
| GPIO9 | PWMB | Pump 2 Speed (PWM) |
| GPIO10 | STBY | Standby (Active High) |
| GND | GND | Ground |
| 3.3V | VCC | Logic Power |
Power Connections
- VM on TB6612FNG: Connect to pump power supply (12V typical)
- Pump 1: Connect to AOUT1 and AOUT2
- Pump 2: Connect to BOUT1 and BOUT2
Usage
Basic Control
// Initialize the motor control system
motor_control_init();
// Start pump at default speed (80%)
motor_start(MOTOR_PUMP_1, MOTOR_DEFAULT_SPEED);
// Start pump at specific speed
motor_start(MOTOR_PUMP_2, 60); // 60% speed
// Stop pumps
motor_stop(MOTOR_PUMP_1);
motor_stop_all(); // Stop all pumps
// Emergency stop (immediate)
motor_emergency_stop();
Timed Operations
// Run pump for specific duration
motor_start_timed(MOTOR_PUMP_1, 80, 10000); // 80% speed for 10 seconds
// Pulse operation
motor_pulse(MOTOR_PUMP_1, 90, 2000, 1000, 5); // On 2s, off 1s, repeat 5x
Speed Control
// Change speed while running
motor_set_speed(MOTOR_PUMP_1, 50); // Change to 50%
// Set speed limits
motor_set_speed_limits(MOTOR_PUMP_1, 30, 90); // Min 30%, Max 90%
Safety Configuration
// Set maximum runtime (prevents pump from running too long)
motor_set_max_runtime(MOTOR_PUMP_1, 60000); // 60 seconds max
// Set minimum interval between runs (prevents frequent cycling)
motor_set_min_interval(MOTOR_PUMP_1, 300000); // 5 minutes
Status and Statistics
// Check if pump is running
if (motor_is_running(MOTOR_PUMP_1)) {
uint32_t runtime = motor_get_runtime_ms(MOTOR_PUMP_1);
ESP_LOGI(TAG, "Pump has been running for %d ms", runtime);
}
// Check if in cooldown
if (motor_is_cooldown(MOTOR_PUMP_1)) {
ESP_LOGI(TAG, "Pump is in cooldown period");
}
// Get statistics
motor_stats_t stats;
motor_get_stats(MOTOR_PUMP_1, &stats);
ESP_LOGI(TAG, "Total runtime: %d seconds", stats.total_runtime_ms / 1000);
ESP_LOGI(TAG, "Total runs: %d", stats.run_count);
MQTT Commands
Basic Control
- Topic:
plant_watering/pump/[1-2]/set - Payload:
on- Start pump at default speedoff- Stop pumppulse- Run pump for 5 seconds
Speed Control
- Topic:
plant_watering/pump/[1-2]/speed - Payload:
0-100(percentage)
Test Commands
- Topic:
plant_watering/commands/test_pump/[1-2] - Payload: Duration in milliseconds (max 10000)
Emergency Stop
- Topic:
plant_watering/commands/emergency_stop - Payload: Any value
MQTT Status Publishing
The system publishes the following status information:
Pump State
- Topic:
plant_watering/pump/[1-2]/state - Values:
on,off
Runtime (when running)
- Topic:
plant_watering/pump/[1-2]/runtime - Value: Current runtime in milliseconds
Statistics (on connect and periodically)
- Topic:
plant_watering/pump/[1-2]/stats - Format: JSON
{
"total_runtime": 123456,
"run_count": 42,
"last_duration": 5000
}
Errors
- Topic:
plant_watering/alerts/pump_error/[1-2] - Value: Error description string
Testing
Hardware Test Program
A standalone test program is provided in motor_test.c. To use it:
- Replace
app_main()in your main.c with the test version - Build and flash
- Monitor serial output
- Verify each pump responds correctly
Test Sequence
- Individual pump ON/OFF test
- PWM speed ramping
- Timed operations
- Dual pump operation
- Safety features (cooldown, max runtime)
- Emergency stop
- Statistics verification
Manual Testing via MQTT
# Start pump 1
mosquitto_pub -h <broker> -t "plant_watering/pump/1/set" -m "on"
# Change speed
mosquitto_pub -h <broker> -t "plant_watering/pump/1/speed" -m "50"
# Stop pump
mosquitto_pub -h <broker> -t "plant_watering/pump/1/set" -m "off"
# Test run for 3 seconds
mosquitto_pub -h <broker> -t "plant_watering/commands/test_pump/1" -m "3000"
# Emergency stop all
mosquitto_pub -h <broker> -t "plant_watering/commands/emergency_stop" -m "1"
Troubleshooting
Pump Not Starting
- Check cooldown period hasn't been violated
- Verify power connections (12V to VM)
- Check STBY pin is HIGH
- Verify PWM signal on oscilloscope
Pump Runs Continuously
- Check safety timer is working
- Verify MQTT commands are being received
- Check for stuck relay/MOSFET
Low Power/Speed
- Check power supply voltage and current capacity
- Verify PWM duty cycle
- Check for voltage drop in wiring
- Ensure pumps aren't clogged
Error Messages
- "Cooldown period not elapsed": Wait for minimum interval
- "Maximum runtime exceeded": Safety timer triggered
- "Motor not initialized": Call
motor_control_init()first
Design Considerations
Soft Start
The module implements a 500ms soft-start sequence, ramping PWM from 0 to target speed in 5% increments. This reduces current spikes and mechanical stress.
Unidirectional Operation
While the TB6612FNG supports bidirectional control, pumps are configured for forward operation only. The direction pins are set but typically won't be changed.
Power Management
The STBY pin is used to enable/disable the motor driver. During emergency stop, STBY is pulled low momentarily to ensure immediate motor shutdown.
Statistics Persistence
Runtime statistics are saved to NVS every 10 pump cycles to minimize flash wear while preserving useful data across reboots.
Integration Example
// In your main application
void app_main() {
// Initialize subsystems
wifi_manager_init();
mqtt_client_init();
motor_control_init();
// Configure safety limits from Kconfig
motor_set_max_runtime(MOTOR_PUMP_1, CONFIG_WATERING_MAX_DURATION_MS);
motor_set_min_interval(MOTOR_PUMP_1, CONFIG_WATERING_MIN_INTERVAL_MS);
// Register callbacks
motor_register_state_callback(on_motor_state_change);
motor_register_error_callback(on_motor_error);
// Start your application...
}
// Automation example
void water_if_dry() {
if (soil_moisture < 30 && !motor_is_cooldown(MOTOR_PUMP_1)) {
motor_start_timed(MOTOR_PUMP_1, 70, 15000); // 15 seconds at 70%
}
}