SENSBLUE ATLAS/Datasheet: Difference between revisions
Appearance
No edit summary |
No edit summary |
||
| Line 7,514: | Line 7,514: | ||
* '''Start Acknowledgement Response Parameters''' | * '''Start Acknowledgement Response Parameters''' | ||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|"<TIMESTAMP>" | |||
|Same request identifier received in the start request. | |||
|- | |||
|origin | |||
| string | |||
|"canopen-actor" | |||
|Identifies the component that generated the response. | |||
|- | |||
|task | |||
|object | |||
|{...} | |||
|Main response object. | |||
|- | |||
|task.alias | |||
|string | |||
|"READ_PDO_CONTINUOUS" | |||
|Alias of the command that was executed. | |||
|- | |||
|task.taskResult | |||
|object | |||
|{...} | |||
|Result object confirming whether the continuous PDO read | |||
was started. | |||
|- | |||
|task.taskResult.success | |||
|boolean | |||
|true | |||
|Indicates whether the start command was accepted. | |||
|- | |||
|task.taskResult.running | |||
|boolean | |||
|true | |||
|Indicates that the continuous PDO read loop is running. | |||
|- | |||
|task.taskResult.mode | |||
|string | |||
|"pdo" | |||
|Indicates that the loop is using PDO reception mode. | |||
|- | |||
|task.taskResult.pdo_num | |||
|integer | |||
|1 | |||
|TPDO number being listened to. | |||
|- | |||
|task.taskResult.interval_ms | |||
|integer | |||
|20 | |||
|Configured delay between read cycles, in milliseconds. | |||
|- | |||
|task.taskResult.error | |||
|string | |||
|"'''READ_PDO_CONTINUOUS''' requires a single | |||
node" | |||
|Error description. Present only when the start command | |||
fails. | |||
|} | |||
* '''Continuous Sample Response Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| integer/string | |||
|1777041089180 | |||
|Sample response ID generated by the actor for each PDO read cycle. | |||
|- | |||
|origin | |||
| string | |||
|"canopen-actor" | |||
|Identifies the component that generated the sample. | |||
|- | |||
|task | |||
|object | |||
|{...} | |||
|Main response object. | |||
|- | |||
|task.alias | |||
|string | |||
|"READ_PDO_CONTINUOUS" | |||
|Alias of the running continuous command. | |||
task. | |||
|- | |||
|task.taskResult | |||
|object | |||
|{...} | |||
|Result object containing one decoded PDO position sample. | |||
|- | |||
|task.taskResult.success | |||
|boolean | |||
|true | |||
|Indicates whether this specific PDO read cycle was successful. | |||
|- | |||
|task.taskResult.node_id | |||
|integer | |||
|5 | |||
|CANopen node ID that produced the TPDO. | |||
|- | |||
|task.taskResult.pdo_num | |||
|integer | |||
|1 | |||
|TPDO number received and decoded. | |||
|- | |||
|task.taskResult.angle_deg | |||
|number | |||
|90.0 | |||
|Position inside one revolution, in degrees. | |||
|- | |||
|task.taskResult.steps_per_rev | |||
|integer | |||
|4096 | |||
|Number of raw counts per revolution used for conversion. | |||
|- | |||
|task.taskResult.revolutions | |||
|number | |||
|0.25 | |||
|Raw position converted into revolutions. Example: '''1024 / 4096 = 0.25''' . | |||
|- | |||
|task.taskResult.raw | |||
|integer | |||
|1024 | |||
|Decoded raw position value from the PDO payload. | |||
|- | |||
|task.taskResult.data | |||
|array | |||
|[0, 4, 0, 0] | |||
|Raw PDO payload bytes received from the CANopen node. | |||
|- | |||
|task.taskResult.offset | |||
|integer | |||
|0 | |||
|Byte offset used to extract the raw position value from '''data.''' | |||
|- | |||
|task.taskResult.size | |||
|integer | |||
|4 | |||
|Number of bytes decoded from '''data'''. | |||
|- | |||
|task.taskResult.signed | |||
|boolean | |||
|false | |||
|Indicates whether the raw value was decoded as signed or unsigned. | |||
|- | |||
|task.taskResult.continuous | |||
|boolean | |||
|true | |||
|Marks this response as a continuous sample. | |||
|- | |||
|task.taskResult.request_id | |||
|string | |||
|"read-pdo-cont-node5" | |||
|Original request '''id''' that started the continuous loop. Useful to | |||
correlate samples with the start command. | |||
|- | |||
|task.taskResult.error | |||
|string | |||
|"pdo operation failed" | |||
|Error description. Present only when a sample fails. | |||
|} | |||
====== Stop Request ====== | |||
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "stop-pdo-cont", | |||
"origin": "APP", | |||
"task": { | |||
"alias": "STOP_READ_PDO_CONTINUOUS", | |||
"taskParams": {} | |||
} | |||
} | |||
</syntaxhighlight>Alternative stop request using '''READ_PDO_CONTINUOUS''':<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "stop-pdo-cont", | |||
"origin": "APP", | |||
"task": { | |||
"alias": "READ_PDO_CONTINUOUS", | |||
"taskParams": { | |||
"action": "STOP" | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
====== '''Stop Response''' ====== | |||
'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "stop-pdo-cont", | |||
"origin": "canopen-actor", | |||
"task": { | |||
"alias": "READ_PDO_CONTINUOUS", | |||
"taskResult": { | |||
"success": true, | |||
"running": false, | |||
"stopped": true | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
* '''Stop Response Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|"stop-pdo-cont" | |||
|Same request identifier received in the stop request. | |||
|- | |||
|origin | |||
| string | |||
|"canopen-actor" | |||
|Identifies the component that generated the response. | |||
|- | |||
|task.alias | |||
|string | |||
|"READ_PDO_CONTINUOUS" | |||
|Alias returned by the stop handler. | |||
|- | |||
|task.taskResult.success | |||
|boolean | |||
|true | |||
|Indicates whether the stop request was processed successfully. | |||
|- | |||
|task.taskResult.running | |||
|boolean | |||
|false | |||
|Indicates that the continuous PDO loop is no longer running. | |||
|- | |||
|task.taskResult.stopped | |||
|boolean | |||
|true | |||
|Indicates whether there was an active continuous task that was actually stopped. If | |||
no task was running, this may be '''false'''. | |||
|} | |||
====== Decode Logic ====== | |||
The received PDO payload is decoded using: | |||
* '''offset''': first byte to read from the PDO payload; | |||
* '''size''': number of bytes to read; | |||
* '''signed''': whether the value is signed or unsigned; | |||
* '''steps_per_rev''': scaling factor used to calculate revolutions and angle. | |||
The raw value is decoded as little-endian: | |||
'''raw = int.from_bytes(data[offset : offset + size], byteorder="little", signed=signed)''' | |||
Then: | |||
'''revolutions = raw / steps_per_rev''' | |||
'''angle_deg = ((raw % steps_per_rev) / steps_per_rev) * 360.0''' | |||
===== 24.14.4 Design Principles ===== | |||
* '''Protocol-Only Actor''' | |||
The CANopen Actor is responsible for: | |||
- CAN frame encoding/decoding; | |||
- SDO communication; | |||
- PDO reception (raw); | |||
- NMT control; | |||
- Heartbeat monitoring. | |||
* '''No Device Semantics''' | |||
The actor: | |||
'''Does NOT know''': | |||
- What 0x6004 represents; | |||
- Units (RPM, mm, °C, etc.); | |||
- Device-specific logic. | |||
'''Only returns''': | |||
- Raw values; | |||
- Protocol-level responses. | |||
* '''Node Management''' | |||
- Nodes must be defined via configuration; | |||
- Actor maintains node state internally; | |||
- Supports multiple nodes simultaneously. | |||
===== Summary ===== | |||
The CANopen Actor: | |||
- Implements '''CANopen protocol communication;''' | |||
- Provides '''generic MQTT interface;''' | |||
- Supports '''multi-node networks;''' | |||
- Keeps '''strict separation between transport and semantics.''' | |||
=== 25. Included Software Stack === | === 25. Included Software Stack === | ||