|
| 1 | +# cl_modbus_tcp_relay |
| 2 | + |
| 3 | +SMACC2 client library for controlling Modbus TCP relay boards, specifically designed for the Waveshare 8-Channel POE ETH Relay. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +This client library provides a SMACC2-compatible interface for controlling relay boards via Modbus TCP protocol. It uses the libmodbus C library for communication and follows SMACC2's pure component-based architecture. |
| 8 | + |
| 9 | +## Target Hardware |
| 10 | + |
| 11 | +- **Device**: Waveshare 8-Channel POE ETH Relay (or compatible) |
| 12 | +- **Protocol**: Modbus TCP |
| 13 | +- **Default IP**: 192.168.1.254 |
| 14 | +- **Default Port**: 502 |
| 15 | +- **Slave ID**: 0x01 |
| 16 | +- **Coil Addresses**: 0x0000-0x0007 (channels 1-8) |
| 17 | + |
| 18 | +## Dependencies |
| 19 | + |
| 20 | +### System Dependencies |
| 21 | + |
| 22 | +```bash |
| 23 | +sudo apt install libmodbus-dev |
| 24 | +``` |
| 25 | + |
| 26 | +### ROS2 Dependencies |
| 27 | + |
| 28 | +- smacc2 |
| 29 | + |
| 30 | +## Architecture |
| 31 | + |
| 32 | +### Client: ClModbusTcpRelay |
| 33 | + |
| 34 | +Pure orchestrator that creates and configures components during initialization. Configuration is loaded from YAML parameters. |
| 35 | + |
| 36 | +### Components |
| 37 | + |
| 38 | +#### CpModbusConnection |
| 39 | + |
| 40 | +Manages libmodbus context lifecycle, TCP connection, and heartbeat monitoring. |
| 41 | + |
| 42 | +**Responsibilities:** |
| 43 | +- Create/destroy modbus_t context |
| 44 | +- Manage TCP connection state |
| 45 | +- Periodic heartbeat via ISmaccUpdatable |
| 46 | +- Emit connection state change signals |
| 47 | +- Thread-safe connection access via mutex |
| 48 | + |
| 49 | +**Signals:** |
| 50 | +- `onConnectionLost_` - Emitted when heartbeat fails |
| 51 | +- `onConnectionRestored_` - Emitted when reconnection succeeds |
| 52 | +- `onConnectionError_` - Emitted on connection errors |
| 53 | + |
| 54 | +#### CpModbusRelay |
| 55 | + |
| 56 | +Handles Modbus coil read/write operations for the 8-channel relay. |
| 57 | + |
| 58 | +**Methods:** |
| 59 | +- `writeCoil(int channel, bool state)` - Write single channel (1-8) |
| 60 | +- `writeAllCoils(bool state)` - Write all channels ON or OFF |
| 61 | +- `writeAllCoils(uint8_t mask)` - Write all channels with bitmask |
| 62 | +- `readCoil(int channel)` - Read single channel state |
| 63 | +- `readAllCoils()` - Read all channel states |
| 64 | + |
| 65 | +### Client Behaviors |
| 66 | + |
| 67 | +| Behavior | Description | |
| 68 | +|----------|-------------| |
| 69 | +| `CbRelayOn` | Turn on a specific relay channel (1-8) | |
| 70 | +| `CbRelayOff` | Turn off a specific relay channel (1-8) | |
| 71 | +| `CbAllRelaysOn` | Turn on all 8 relay channels | |
| 72 | +| `CbAllRelaysOff` | Turn off all 8 relay channels | |
| 73 | +| `CbRelayStatus` | Read the status of relay channels | |
| 74 | + |
| 75 | +### Events |
| 76 | + |
| 77 | +```cpp |
| 78 | +// Connection events (source: CpModbusConnection) |
| 79 | +EvConnectionLost<CpModbusConnection, OrRelay> |
| 80 | +EvConnectionRestored<CpModbusConnection, OrRelay> |
| 81 | + |
| 82 | +// Relay operation events (source: CpModbusRelay) |
| 83 | +EvRelayWriteSuccess<CpModbusRelay, OrRelay> |
| 84 | +EvRelayWriteFailure<CpModbusRelay, OrRelay> |
| 85 | +``` |
| 86 | + |
| 87 | +## Configuration |
| 88 | + |
| 89 | +Configuration is loaded from ROS2 parameters (typically via YAML config file): |
| 90 | + |
| 91 | +```yaml |
| 92 | +your_state_machine: |
| 93 | + ros__parameters: |
| 94 | + modbus_relay: |
| 95 | + ip_address: "192.168.1.254" # Relay board IP address |
| 96 | + port: 502 # Modbus TCP port |
| 97 | + slave_id: 1 # Modbus slave ID |
| 98 | + heartbeat_interval_ms: 1000 # Heartbeat check interval |
| 99 | + connect_on_init: true # Auto-connect on initialization |
| 100 | +``` |
| 101 | +
|
| 102 | +### Default Values |
| 103 | +
|
| 104 | +| Parameter | Default | |
| 105 | +|-----------|---------| |
| 106 | +| `ip_address` | "192.168.1.254" | |
| 107 | +| `port` | 502 | |
| 108 | +| `slave_id` | 1 | |
| 109 | +| `heartbeat_interval_ms` | 1000 | |
| 110 | +| `connect_on_init` | true | |
| 111 | + |
| 112 | +## Usage |
| 113 | + |
| 114 | +### Orthogonal Definition |
| 115 | + |
| 116 | +```cpp |
| 117 | +#include <cl_modbus_tcp_relay/cl_modbus_tcp_relay.hpp> |
| 118 | +
|
| 119 | +class OrRelay : public smacc2::Orthogonal<OrRelay> |
| 120 | +{ |
| 121 | +public: |
| 122 | + void onInitialize() override |
| 123 | + { |
| 124 | + // Configuration loaded from YAML parameters |
| 125 | + auto relay_client = this->createClient<cl_modbus_tcp_relay::ClModbusTcpRelay>(); |
| 126 | + } |
| 127 | +}; |
| 128 | +``` |
| 129 | + |
| 130 | +### State Definition |
| 131 | + |
| 132 | +```cpp |
| 133 | +#include <cl_modbus_tcp_relay/client_behaviors/cb_relay_on.hpp> |
| 134 | +#include <cl_modbus_tcp_relay/client_behaviors/cb_relay_off.hpp> |
| 135 | +
|
| 136 | +struct StActivateRelay : smacc2::SmaccState<StActivateRelay, SmExample> |
| 137 | +{ |
| 138 | + using SmaccState::SmaccState; |
| 139 | +
|
| 140 | + typedef mpl::list< |
| 141 | + Transition<EvCbSuccess<CbRelayOn, OrRelay>, StNextState>, |
| 142 | + Transition<EvCbFailure<CbRelayOn, OrRelay>, StError>, |
| 143 | + Transition<EvConnectionLost<CpModbusConnection, OrRelay>, StReconnect> |
| 144 | + > reactions; |
| 145 | +
|
| 146 | + static void staticConfigure() |
| 147 | + { |
| 148 | + // Turn on channel 1 |
| 149 | + configure_orthogonal<OrRelay, cl_modbus_tcp_relay::CbRelayOn>(1); |
| 150 | + } |
| 151 | +}; |
| 152 | +``` |
| 153 | + |
| 154 | +### Launch File |
| 155 | + |
| 156 | +```python |
| 157 | +from launch import LaunchDescription |
| 158 | +from launch_ros.actions import Node |
| 159 | +from ament_index_python.packages import get_package_share_directory |
| 160 | +import os |
| 161 | +
|
| 162 | +def generate_launch_description(): |
| 163 | + config_file = os.path.join( |
| 164 | + get_package_share_directory('your_state_machine'), |
| 165 | + 'config', |
| 166 | + 'your_config.yaml' |
| 167 | + ) |
| 168 | +
|
| 169 | + return LaunchDescription([ |
| 170 | + Node( |
| 171 | + package='your_state_machine', |
| 172 | + executable='your_state_machine_node', |
| 173 | + name='your_state_machine', |
| 174 | + output='screen', |
| 175 | + parameters=[config_file] |
| 176 | + ) |
| 177 | + ]) |
| 178 | +``` |
| 179 | + |
| 180 | +## Manual Testing with mbpoll |
| 181 | + |
| 182 | +For debugging and manual testing, you can use the `mbpoll` command-line tool: |
| 183 | + |
| 184 | +```bash |
| 185 | +# Install mbpoll |
| 186 | +sudo apt install mbpoll |
| 187 | +
|
| 188 | +# Read all 8 coil states |
| 189 | +mbpoll -m tcp -a 1 -t 0 -r 1 -c 8 192.168.1.254 |
| 190 | +
|
| 191 | +# Write single coil ON (channel 1) |
| 192 | +mbpoll -m tcp -a 1 -t 0 -r 1 192.168.1.254 1 |
| 193 | +
|
| 194 | +# Write single coil OFF (channel 1) |
| 195 | +mbpoll -m tcp -a 1 -t 0 -r 1 192.168.1.254 0 |
| 196 | +
|
| 197 | +# Write all coils ON |
| 198 | +mbpoll -m tcp -a 1 -t 0 -r 1 -c 8 192.168.1.254 1 1 1 1 1 1 1 1 |
| 199 | +
|
| 200 | +# Write all coils OFF |
| 201 | +mbpoll -m tcp -a 1 -t 0 -r 1 -c 8 192.168.1.254 0 0 0 0 0 0 0 0 |
| 202 | +``` |
| 203 | + |
| 204 | +### mbpoll Options Reference |
| 205 | + |
| 206 | +| Option | Description | |
| 207 | +|--------|-------------| |
| 208 | +| `-m tcp` | Use Modbus TCP protocol | |
| 209 | +| `-a 1` | Slave address (1) | |
| 210 | +| `-t 0` | Data type: coil (0) | |
| 211 | +| `-r 1` | Starting reference (1 = address 0x0000) | |
| 212 | +| `-c 8` | Number of coils to read/write | |
| 213 | + |
| 214 | +## Modbus Protocol Reference |
| 215 | + |
| 216 | +| Operation | Function Code | Address Range | |
| 217 | +|-----------|---------------|---------------| |
| 218 | +| Read Coils | 0x01 | 0x0000-0x0007 | |
| 219 | +| Write Single Coil | 0x05 | 0x0000-0x0007 | |
| 220 | +| Write Multiple Coils | 0x0F | 0x0000 (8 coils) | |
| 221 | + |
| 222 | +### Coil Values |
| 223 | + |
| 224 | +- ON: 0xFF00 (function 0x05) or 1 (function 0x0F) |
| 225 | +- OFF: 0x0000 |
| 226 | + |
| 227 | +## Building |
| 228 | + |
| 229 | +```bash |
| 230 | +# From workspace root |
| 231 | +colcon build --packages-select cl_modbus_tcp_relay |
| 232 | +``` |
| 233 | + |
| 234 | +## Test State Machine |
| 235 | + |
| 236 | +See `sm_modbus_tcp_relay_test_1` for a complete test state machine that exercises all behaviors. |
| 237 | + |
| 238 | +## License |
| 239 | + |
| 240 | +Apache-2.0 |
0 commit comments