Example 46: Modbus Stepper Motor Control
Example 46: Modbus Stepper Motor Control
Experiment Overview
Controls an RS485 stepper motor driver via Modbus RTU protocol, enabling remote precision positioning, speed adjustment, and direction control. Suitable for industrial automation, smart agriculture (roller blinds/irrigation valves), precision positioning, and similar scenarios.
Hardware Wiring
RS485 Communication Wiring
| ESP32 Pin | TTL-to-RS485 Module | Description |
|---|---|---|
| GPIO 16 | TXD | Serial transmit |
| GPIO 17 | RXD | Serial receive |
| GPIO 4 (optional) | DE/RE | Direction control |
| 3.3V | VCC | Power |
| GND | GND | Ground |
RS485 to Stepper Motor Driver
| RS485 Module | Stepper Motor Driver | Description |
|---|---|---|
| A+ | RS485-A | Differential signal positive |
| B- | RS485-B | Differential signal negative |
Stepper Motor Driver to Motor
| Driver | Stepper Motor | Description |
|---|---|---|
| A+ | A phase + | Motor coil A |
| A- | A phase - | Motor coil A |
| B+ | B phase + | Motor coil B |
| B- | B phase - | Motor coil B |
| VCC | External Power | 12-48V DC |
Stepper motor drivers (e.g., DM542, TB6600 RS485 version) require independent power supply; voltage depends on motor model.
JSON Configuration Example
Status Read Configuration
{
"id": "modbus_stepper",
"name": "Modbus Stepper Motor",
"type": 1,
"enabled": false,
"pins": [16, 17],
"params": {
"baudRate": 9600,
"dataBits": 8,
"parity": "none",
"stopBits": 1,
"dePin": 4,
"protocol": "modbus_rtu",
"slaveId": 1,
"function": 3,
"startRegister": 0,
"registerCount": 4,
"interval": 2000,
"dataMap": [
{ "register": 0, "name": "position", "scale": 1, "unit": "steps" },
{ "register": 1, "name": "speed", "scale": 1, "unit": "RPM" },
{ "register": 2, "name": "status", "scale": 1, "unit": "" },
{ "register": 3, "name": "error", "scale": 1, "unit": "" }
]
}
}Control Write Configuration
{
"id": "modbus_stepper_ctrl",
"name": "Stepper Motor Control",
"type": 1,
"enabled": false,
"pins": [16, 17],
"params": {
"protocol": "modbus_rtu",
"slaveId": 1,
"function": 6,
"startRegister": 100,
"registerCount": 3,
"interval": 0,
"controlMap": [
{ "register": 100, "name": "target_position", "min": -32768, "max": 32767 },
{ "register": 101, "name": "target_speed", "min": 0, "max": 3000 },
{ "register": 102, "name": "command", "values": { "start": 1, "stop": 2, "home": 3, "reset": 4 } }
]
}
}Parameter Description
| Parameter | Description |
|---|---|
| slaveId | Driver slave address (DIP switch setting) |
| function | 3=read registers, 6=write single register, 16=write multiple registers |
| controlMap | Control register mapping, defines writable fields |
| target_position | Target position (steps, signed) |
| target_speed | Target speed (RPM) |
| command | Motion command: start/stop/home/reset |
Control Commands
Send control via MQTT:
[{"id": "modbus_stepper_ctrl", "value": "target_position:2048,target_speed:100,command:1"}]target_position: Target steps (positive=forward, negative=reverse)target_speed: Running speed in RPMcommand: 1=start, 2=stop, 3=home, 4=reset alarm
Slide Table Boundary Protection
When using a Modbus stepper motor for a linear slide table, it is recommended to enable soft limits in the Modbus sub-device configuration:
{
"name": "Slide Stepper Motor",
"sensorId": "slide_motor",
"deviceType": "motor",
"slaveAddress": 8,
"motorRegs": [0, 1, 2, 5, 7],
"motorMinPosition": 0,
"motorMaxPosition": 10000,
"motorCurrentPosition": 0,
"motorMoveStep": 1600,
"motorLastPulse": 1600,
"enabled": true
}motorMinPosition: Left boundary, in steps.motorMaxPosition: Right boundary, in steps.motorCurrentPosition: Current estimated position; typically set to0after homing.motorMoveStep: Default steps perforward/reversecommand.motorLastPulse: Most recentsetPulsecount; used as fallback step size when rule does not specify pulses.
When soft limits are enabled, the system calculates the next position before sending forward/reverse commands. If it would exceed the left or right boundary, the pulse count is automatically reduced to stay within bounds; if the current position is already at a boundary, the action is rejected. Hardware limit switches and emergency stop must still be retained; software limits cannot replace physical safety protection.
Peripheral Execution Linkage
Periodic Back-and-Forth Motion
{
"name": "Stepper Motor Back-and-Forth",
"enabled": true,
"triggers": [
{ "type": "timer", "params": { "interval": 10000 } }
],
"actions": [
{
"type": "modbus_write",
"params": {
"periphId": "modbus_stepper_ctrl",
"register": 100,
"value": 2048
}
},
{
"type": "modbus_write",
"params": {
"periphId": "modbus_stepper_ctrl",
"register": 102,
"value": 1
}
}
]
}Button-Triggered Homing
{
"name": "Button Homing",
"enabled": true,
"triggers": [
{
"type": "event",
"params": { "periphId": "btn1", "event": "pressed" }
}
],
"actions": [
{
"type": "modbus_write",
"params": {
"periphId": "modbus_stepper_ctrl",
"register": 102,
"value": 3
}
}
]
}Temperature Linkage (with Temperature-Controlled Roller Blind)
{
"name": "High Temp Open Blind",
"enabled": true,
"triggers": [
{
"type": "poll",
"params": {
"periphId": "modbus_th",
"field": "temperature",
"operator": ">",
"threshold": 32
}
}
],
"actions": [
{
"type": "modbus_write",
"params": { "periphId": "modbus_stepper_ctrl", "register": 100, "value": 5000 }
},
{
"type": "modbus_write",
"params": { "periphId": "modbus_stepper_ctrl", "register": 102, "value": 1 }
}
]
}Notes
- Driver Selection: Ensure the driver supports RS485 Modbus RTU protocol (not pulse/direction type)
- Register Addresses: Different brands define registers differently; always consult the corresponding manual
- Motion Safety: Limit switches are recommended to prevent mechanical damage from over-travel
- Emergency Stop: Hardware emergency stop button is essential; cannot rely on software stop alone
- Communication Timeout: Stepper motor execution takes time; polling interval should be ≥ 2000ms
- Independent Power: Motor driver power supply must be completely isolated from ESP32 power; share ground only
