SENSBLUE ATLAS/Datasheet: Difference between revisions
Appearance
No edit summary |
|||
| (32 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
{{DISPLAYTITLE:Datasheet}} | |||
<div | <div class="buy-now-container"> | ||
<span class=" | <span class="button-buy-now">[https://atronia.eu/product/sensblue-atlas/ Buy Now]</span> | ||
</div> | </div> | ||
[[File:SENSBLUE-ATLAS-Gateway.png|center|frameless|360x360px]] | |||
== '''Datasheet''' == | == '''Datasheet''' == | ||
| Line 9: | Line 12: | ||
=== 1. Table of SENSBLUE ATLAS Reference ID Model Number === | === 1. Table of SENSBLUE ATLAS Reference ID Model Number === | ||
{| class="wikitable" | {| class="wikitable" | ||
| | |'''Reference Number''' | ||
| | |'''Name''' | ||
| | |'''Version''' | ||
| | |'''RAM''' | ||
| | |'''Modem''' | ||
| | |- | ||
|PA000000102 | |||
|ATLAS IoT SBC V1 CM4. 2GB M2.0 M1 PB0 | |||
|V1 | |||
|2GB | |||
|Yes | |||
|- | |- | ||
| | |PA000000103 | ||
|ATLAS IoT SBC V1 CM4. 2GB M2.0 M0 PB0 | |||
| | |V1 | ||
| | |2GB | ||
| | |Yes | ||
| | |||
|- | |- | ||
| | |PA000000104 | ||
|ATLAS IoT SBC V1 CM4. 4GB M2.0 M1 PB0 | |||
| | |V1 | ||
| | |4GB | ||
| | |No | ||
| | |||
|} | |} | ||
| Line 82: | Line 88: | ||
|- | |- | ||
|RAM | |RAM | ||
|4GB LPDDR4 | |2GB, 4GB LPDDR4 | ||
|- | |- | ||
|Storage | |Storage | ||
| Line 670: | Line 676: | ||
"task": { | "task": { | ||
"taskParams": { | "taskParams": { | ||
" | "DO1": { | ||
"state": "open" | "state": "open" | ||
}, | }, | ||
" | "DO2": { | ||
"state": "open" | "state": "open" | ||
} | } | ||
| Line 686: | Line 692: | ||
"task": { | "task": { | ||
"taskResult": { | "taskResult": { | ||
" | "DO1": { | ||
"success": true, | "success": true, | ||
"state": "open" | "state": "open" | ||
}, | }, | ||
" | "DO2": { | ||
"success": true, | "success": true, | ||
"state": "open" | "state": "open" | ||
| Line 700: | Line 706: | ||
====== b) Get all relays state ====== | ====== b) Get all relays state ====== | ||
Req-Topic: relayOutputs/runtime/in<syntaxhighlight lang="json" line="1"> | Req-Topic: relayOutputs/runtime/in<syntaxhighlight lang="json" line="1">{ | ||
{ | |||
"id": "<TIMESTAMP>", | "id": "<TIMESTAMP>", | ||
"origin": "APP", | "origin": "APP", | ||
| Line 707: | Line 712: | ||
"action": "READ" | "action": "READ" | ||
} | } | ||
} | }</syntaxhighlight>Reply-Topic: relayOutputs/runtime/out <syntaxhighlight lang="json" line="1"> | ||
</syntaxhighlight>Reply-Topic: relayOutputs/runtime/out <syntaxhighlight lang="json" line="1"> | |||
{ | { | ||
"id": "<TIMESTAMP>", | "id": "<TIMESTAMP>", | ||
| Line 714: | Line 718: | ||
"task": { | "task": { | ||
"taskResult": { | "taskResult": { | ||
" | "DO1": { | ||
"success": true, | "success": true, | ||
"state": "open" | "state": "open" | ||
}, | }, | ||
" | "DO2": { | ||
"success": true, | "success": true, | ||
"state": "close" | "state": "close" | ||
| Line 736: | Line 740: | ||
"action": "SET", | "action": "SET", | ||
"taskParams": { | "taskParams": { | ||
" | "DO1": { | ||
"state": "open" | "state": "open" | ||
}, | }, | ||
" | "DO2": { | ||
"state": "close" | "state": "close" | ||
} | } | ||
| Line 751: | Line 755: | ||
"task": { | "task": { | ||
"taskResult": { | "taskResult": { | ||
" | "DO1": { | ||
"success": true, | "success": true, | ||
"state": "open" | "state": "open" | ||
}, | }, | ||
" | "DO2": { | ||
"success": true, | "success": true, | ||
"state": "close" | "state": "close" | ||
| Line 3,772: | Line 3,776: | ||
"task": { | "task": { | ||
"taskResult": { | "taskResult": { | ||
" | "DO1": { | ||
"success": true, | "success": true, | ||
"state": "low" | "state": "low" | ||
}, | }, | ||
" | "DO2": { | ||
"success": true, | "success": true, | ||
"state": "high" | "state": "high" | ||
}, | }, | ||
" | "DO3": { | ||
"success": true, | "success": true, | ||
"state": "high" | "state": "high" | ||
}, | }, | ||
" | "DO4": { | ||
"success": true, | "success": true, | ||
"state": "high" | "state": "high" | ||
}, | }, | ||
" | "DO5": { | ||
"success": true, | "success": true, | ||
"state": "high" | "state": "high" | ||
}, | }, | ||
" | "DO6": { | ||
"success": true, | "success": true, | ||
"state": "low" | "state": "low" | ||
}, | }, | ||
" | "DO7": { | ||
"success": true, | "success": true, | ||
"state": "low" | "state": "low" | ||
}, | }, | ||
" | "DO8": { | ||
"success": true, | "success": true, | ||
"state": "low" | "state": "low" | ||
| Line 4,198: | Line 4,202: | ||
} | } | ||
</syntaxhighlight>'''Buzzer State''' | </syntaxhighlight>'''Buzzer State''' | ||
[[File: | [[File:5_beeps.svg|frameless|700x700px]] | ||
duration_s = 1.0s | duration_s = 1.0s | ||
| Line 4,227: | Line 4,226: | ||
</syntaxhighlight>'''Buzzer State''' | </syntaxhighlight>'''Buzzer State''' | ||
[[File:Infinite_Beeps.svg|frameless|606x606px]] | [[File:Infinite_Beeps.svg|frameless|606x606px]] | ||
duration_s = 1.0 | duration_s = 1.0 | ||
gap_s = 0.5 | gap_s = 0.5 | ||
| Line 5,654: | Line 5,654: | ||
|'''Required''' | |'''Required''' | ||
|'''Example''' | |'''Example''' | ||
|Description | |'''Description''' | ||
|- | |- | ||
|id | |id | ||
| Line 5,848: | Line 5,848: | ||
|'''Required''' | |'''Required''' | ||
|'''Default''' | |'''Default''' | ||
|Description | |'''Description''' | ||
|- | |- | ||
|node_id | |node_id | ||
| Line 6,564: | Line 6,564: | ||
* '''Response Parameters''' | * '''Response Parameters''' | ||
= | {| class="wikitable" | ||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|"<TIMESTAMP>" | |||
|Same request identifier received in the request. Used to correlate request andresponse. | |||
|- | |||
|origin | |||
| string | |||
|"canopen-actor" | |||
|Identifies the component that generated the response. | |||
|- | |||
|task | |||
|object | |||
|{...} | |||
|Main response object. | |||
|- | |||
|task.alias | |||
|string | |||
|"SDO_WRITE" | |||
|Alias of the command that was executed. | |||
|- | |||
|task.taskResult | |||
|object | |||
|{...} | |||
|Result object containing the SDO write result. | |||
|- | |||
|task.taskResult.success | |||
|boolean | |||
|true | |||
|Indicates whether the SDO write was successful. | |||
|- | |||
|task.taskResult.id | |||
|string | |||
|"sdo-write-node5" | |||
|Internal/request ID returned by the CANopen RPC call. | |||
Usually matches theoriginal request '''id'''. | |||
|- | |||
|task.taskResult.node_id | |||
|integer | |||
|5 | |||
|CANopen node ID that was written to. | |||
|- | |||
|task.taskResult.index | |||
|integer | |||
|24579 | |||
|Object dictionary index that was written, returned as decimal. | |||
Example: '''24579 =0x6003'''. | |||
|- | |||
|task.taskResult.subindex | |||
|integer | |||
|0 | |||
|Object dictionary subindex that was written. | |||
|- | |||
|task.taskResult.value | |||
|integer | |||
|0 | |||
|Value that was written. | |||
|- | |||
|task.taskResult.size | |||
|integer | |||
|4 | |||
|Number of bytes written. | |||
|- | |||
|task.taskResult.error | |||
|string | |||
|"SDO abort 0x6003:00 ->..." | |||
|Error description. Present only when the command fails. | |||
|} | |||
====== Read Node State ====== | |||
Reads position and returns raw value, revolutions, and angle. Internally, this reads the configured position object, defaulting to | |||
'''0x6004:00'''. '''If''' '''steps_per_rev''' is not provided, the owner reads '''0x6501:00''' to obtain it. | |||
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "APP", | |||
"task": { | |||
"alias": "READ", | |||
"taskParams": { | |||
"node_id": 5, | |||
"index": "0x6004", | |||
"subindex": "0x00", | |||
"steps_per_rev": 4096, | |||
"timeout": 2.0 | |||
} | |||
} | |||
} | |||
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "canopen-actor", | |||
"task": { | |||
"alias": "READ", | |||
"taskResult": { | |||
"success": true, | |||
"id": "read-node5", | |||
"node_id": 5, | |||
"raw": 1024, | |||
"steps_per_rev": 4096, | |||
"revolutions": 0.25, | |||
"angle_deg": 90.0, | |||
"index": 24580, | |||
"subindex": 0 | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
* '''Request Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Required''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|Yes | |||
|"<TIMESTAMP>" | |||
|Unique request identifier. The same value is returned in theresponse. | |||
|- | |||
|origin | |||
| string | |||
|No | |||
|"APP" | |||
|Identifies the sender of the request, for example '''APP, NodeRED, CLI''', or '''TestClient'''. | |||
|- | |||
|task | |||
|object | |||
|Yes | |||
|{...} | |||
|Main command object containing the command alias andparameters. | |||
|- | |||
|task.alias | |||
|string | |||
|Yes | |||
|"READ" | |||
|Defines the command to execute. For this operation, it must be '''READ'''. | |||
|- | |||
|task.taskParams | |||
|object | |||
|Yes | |||
|{...} | |||
|Contains the position read parameters. | |||
|- | |||
|task.taskParams.node_id | |||
|integer | |||
|Yes* | |||
|5 | |||
|Numeric CANopen node ID to read from. | |||
|- | |||
|task.taskParams.nodeId | |||
|integer | |||
|Yes* | |||
|5 | |||
|Alternative spelling for '''node_id'''. | |||
|- | |||
|task.taskParams.node | |||
|string | |||
|Yes* | |||
|"motor_1" | |||
|Logical node name previously configured with '''CONFIG_CANOPEN'''. | |||
|- | |||
|task.taskParams.index | |||
|integer/string | |||
|No | |||
|"0x6004" | |||
|CANopen object dictionary index used as the raw positionsource. If omitted, defaults to '''0x6004'''. | |||
|- | |||
|task.taskParams.subindex | |||
|integer/string | |||
|No | |||
|"0x00" | |||
|CANopen object dictionary subindex used as the raw positionsource. If omitted, defaults to '''0x00'''. | |||
|- | |||
|task.taskParams.steps_per_rev | |||
|integer | |||
|Recommended | |||
|4096 | |||
|Number of raw counts per mechanical revolution. Used tocalculate | |||
'''revolutions''' and '''angle_deg'''. If omitted, the ownerattempts to read '''0x6501:00'''. | |||
|- | |||
|task.taskParams.timeout | |||
|number | |||
|No | |||
|2.0 | |||
|Timeout, in seconds, used for the internal SDO reads. Ifomitted, the actor default SDO timeout is used. | |||
|- | |||
|task.taskParams.sdo_timeout | |||
|number | |||
|No | |||
|2.0 | |||
|Internal SDO timeout used when creating/updating the nodewrapper. Usually not required. | |||
|} | |||
* '''Response Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|"<TIMESTAMP>" | |||
|Same request identifier received in the request. Used to correlate request andresponse. | |||
|- | |||
|origin | |||
| string | |||
|"canopen-actor" | |||
|Identifies the component that generated the response. | |||
|- | |||
|task | |||
|object | |||
|{...} | |||
|Main response object. | |||
|- | |||
|task.alias | |||
|string | |||
|"READ" | |||
|Alias of the command that was executed. | |||
|- | |||
|task.taskResult | |||
|object | |||
|{...} | |||
|Result object containing the position read result. | |||
|- | |||
|task.taskResult.success | |||
|boolean | |||
|true | |||
|Indicates whether the position read was successful. | |||
|- | |||
|task.taskResult.id | |||
|string | |||
|"read-node5" | |||
|Internal/request ID returned by the CANopen RPC call. Usually matches theoriginal request '''id'''. | |||
|- | |||
|task.taskResult.node_id | |||
|integer | |||
|5 | |||
|CANopen node ID that was read. | |||
|- | |||
|task.taskResult.raw | |||
|integer | |||
|1024 | |||
|Raw position value read from the selected object dictionary entry. | |||
|- | |||
|task.taskResult.steps_per_rev | |||
|integer | |||
|4096 | |||
|Number of raw counts per revolution used for the conversion. | |||
|- | |||
|task.taskResult.revolutions | |||
|number | |||
|0.25 | |||
|Raw position converted into revolutions. Example: '''1024 / 4096 = 0.25'''. | |||
|- | |||
|task.taskResult.angle_deg | |||
|number | |||
|90.0 | |||
|Position inside one revolution, in degrees. Example: '''0.25 × 360 = 90°'''. | |||
|- | |||
|task.taskResult.index | |||
|integer | |||
|24580 | |||
|Object dictionary index read as the raw position source. Example: '''24580 =0x6004'''. | |||
|- | |||
|task.taskResult.subindex | |||
|integer | |||
|0 | |||
|Object dictionary subindex read as the raw position source. | |||
|- | |||
|task.taskResult.error | |||
|string | |||
|"SDO timeout0x6004:00" | |||
|Error description. Present only when the command fails. | |||
|} | |||
====== READ SDO Continuous ====== | |||
Starts continuous SDO-based position reading. | |||
The initial command returns an acknowledgement. After that, continuous samples are published repeatedly to '''canopen/runtime/out''' | |||
The continuous loop requires a single node reference and requires '''steps_per_rev'''. | |||
* '''Start request''' | |||
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "APP", | |||
"task": { | |||
"alias": "READ_CONTINUOUS", | |||
"taskParams": { | |||
"node_id": 5, | |||
"steps_per_rev": 4096, | |||
"index": "0x6004", | |||
"subindex": "0x00", | |||
"timeout": 0.2, | |||
"interval_ms": 20 | |||
} | |||
} | |||
} | |||
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1"> | |||
// Start acknowledgement | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "canopen-actor", | |||
"task": { | |||
"alias": "READ_CONTINUOUS", | |||
"taskResult": { | |||
"success": true, | |||
"running": true, | |||
"mode": "single", | |||
"interval_ms": 20 | |||
} | |||
} | |||
} | |||
</syntaxhighlight><syntaxhighlight lang="json" line="1"> | |||
// Continuous sample response | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "canopen-actor", | |||
"task": { | |||
"alias": "READ_CONTINUOUS", | |||
"taskResult": { | |||
"success": true, | |||
"node_id": 5, | |||
"angle_deg": 90.0, | |||
"steps_per_rev": 4096, | |||
"revolutions": 0.25, | |||
"raw": 1024, | |||
"index": 24580, | |||
"subindex": 0, | |||
"continuous": true, | |||
"request_id": "read-cont-node5" | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
* '''Start Request Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Required''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|Yes | |||
|"<TIMESTAMP>" | |||
|Unique request identifier. Continuous sample responses include | |||
this value as '''request_id'''. | |||
|- | |||
|origin | |||
| string | |||
|No | |||
|"APP" | |||
|Identifies the sender of the request, for example '''APP''', '''NodeRED''', | |||
'''CLI''', or '''TestClient'''. | |||
|- | |||
|task | |||
|object | |||
|Yes | |||
|{...} | |||
|Main command object containing the command alias and | |||
parameters. | |||
|- | |||
|task.alias | |||
|string | |||
|Yes | |||
|"READ_CONTINUOUS" | |||
|Defines the command to execute. For this operation, it must be | |||
'''READ_CONTINUOUS'''. | |||
|- | |||
|task.taskParams | |||
|object | |||
|Yes | |||
|{...} | |||
|Contains the continuous read parameters. | |||
|- | |||
|task.taskParams.node_id | |||
|integer | |||
|Yes* | |||
|5 | |||
|Numeric CANopen node ID to read continuously. | |||
|- | |||
|task.taskParams.nodeId | |||
|integer | |||
|Yes* | |||
|5 | |||
|Alternative spelling for '''node_id'''. | |||
|- | |||
|task.taskParams.node | |||
|string | |||
|Yes* | |||
|"motor_1" | |||
|Logical node name previously configured with '''CONFIG_CANOPEN'''. | |||
|- | |||
|task.taskParams.steps_per_rev | |||
|integer | |||
|Yes** | |||
|4096 | |||
|Number of raw counts per mechanical revolution. Required by | |||
the fast continuous read loop to calculate '''revolutions''' and | |||
'''angle_deg'''. | |||
|- | |||
|task.taskParams.index | |||
|integer/string | |||
|No | |||
|"0x6004" | |||
|CANopen object dictionary index used as the raw position | |||
source. If omitted, defaults to '''0x6004'''. | |||
|- | |||
|task.taskParams.subindex | |||
|integer/string | |||
|No | |||
|"0x00" | |||
|CANopen object dictionary subindex used as the raw position | |||
source. If omitted, defaults to '''0x00'''. | |||
|- | |||
|task.taskParams.timeout | |||
|number | |||
|No | |||
|0.2 | |||
|Timeout, in seconds, used for each fast SDO read cycle. If | |||
omitted, defaults to '''0.2'''. | |||
|- | |||
|task.taskParams.interval_ms | |||
|integer | |||
|No | |||
|20 | |||
|Delay between continuous read cycles, in milliseconds. If '''0''' , the | |||
loop runs again immediately after each cycle yields control. | |||
|- | |||
|task.taskParams.action | |||
|string | |||
|No | |||
|"START" | |||
|Optional action. If set to '''STOP''' , '''OFF''' , '''CANCEL''' , or '''DISABLE''' , the | |||
actor stops the continuous read loop instead of starting it. | |||
|} | |||
* '''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_CONTINUOUS" | |||
|Alias of the command that was executed. | |||
|- | |||
|task.taskResult | |||
|object | |||
|{...} | |||
|Result object confirming that continuous reading was started. | |||
|- | |||
|task.taskResult.success | |||
|boolean | |||
|true | |||
|Indicates whether the start command was accepted. | |||
|- | |||
|task.taskResult.running | |||
|boolean | |||
|true | |||
|Indicates that the continuous read loop is running. | |||
|- | |||
|task.taskResult.mode | |||
|string | |||
|"single" | |||
|Read mode. In this fast continuous path, a single node is used when '''node_id''' , | |||
'''nodeId''' , or '''node''' is provided. | |||
|- | |||
|task.taskResult.interval_ms | |||
|integer | |||
|20 | |||
|Configured delay between continuous read cycles, in milliseconds. | |||
|- | |||
|task.taskResult.error | |||
|string | |||
|"no configured nodes" | |||
|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 read cycle. | |||
|- | |||
|origin | |||
| string | |||
|"canopen-actor" | |||
|Identifies the component that generated the sample response. | |||
|- | |||
|task | |||
|object | |||
|{...} | |||
|Main response object. | |||
|- | |||
|task.alias | |||
|string | |||
|"READ_CONTINUOUS" | |||
|Alias of the running continuous command. | |||
|- | |||
|task.taskResult | |||
|object | |||
|{...} | |||
|Result object containing one continuous position sample. | |||
|- | |||
|task.taskResult.success | |||
|boolean | |||
|true | |||
|Indicates whether this specific read cycle was successful. | |||
|- | |||
|task.taskResult.node_id | |||
|integer | |||
|5 | |||
|CANopen node ID that was read. | |||
|- | |||
|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. | |||
|- | |||
|task.taskResult.raw | |||
|integer | |||
|1024 | |||
|Raw position value read from the node. | |||
|- | |||
|task.taskResult.index | |||
|integer | |||
|24580 | |||
|Object dictionary index read as the raw position source. Example: '''24580 =''' | |||
'''0x6004'''. | |||
|- | |||
|task.taskResult.subindex | |||
|integer | |||
|0 | |||
|Object dictionary subindex read as the raw position source. | |||
|- | |||
|task.taskResult.continuous | |||
|boolean | |||
|true | |||
|Marks this response as a continuous sample, not just the initial | |||
acknowledgement. | |||
|- | |||
|task.taskResult.request_id | |||
|string | |||
|"read-cont-node5" | |||
|Original request '''id''' that started the continuous loop. Useful to correlate | |||
samples with the start command. | |||
|- | |||
|task.taskResult.error | |||
|string | |||
|"operation failed" | |||
|Error description for a failed sample. Present only when a read cycle fails. | |||
|} | |||
====== Stop request ====== | |||
You can stop using either '''STOP_READ_CONTINUOUS''' : | |||
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "APP", | |||
"task": { | |||
"alias": "STOP_READ_CONTINUOUS", | |||
"taskParams": {} | |||
} | |||
} | |||
</syntaxhighlight>Or by sending '''READ_CONTINUOUS''' with '''action: "STOP"''' :<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "stop-read-cont", | |||
"origin": "APP", | |||
"task": { | |||
"alias": "READ_CONTINUOUS", | |||
"taskParams": { | |||
"action": "STOP" | |||
} | |||
} | |||
} | |||
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "stop-read-cont", | |||
"origin": "canopen-actor", | |||
"task": { | |||
"alias": "READ_CONTINUOUS", | |||
"taskResult": { | |||
"success": true, | |||
"running": false, | |||
"stopped": true | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
* '''Stop Request Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Required''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|Yes | |||
|"stop-read-cont" | |||
|Unique request identifier. | |||
|- | |||
|origin | |||
| string | |||
|No | |||
|"APP" | |||
|Identifies the sender of the request. | |||
|- | |||
|task.alias | |||
|string | |||
|Yes | |||
|"READ_CONTINUOUS" or | |||
"STOP_READ_CONTINUOUS" | |||
|Command used to stop the continuous read loop. | |||
|- | |||
|task.taskParams.action | |||
|string | |||
|No | |||
|"STOP" | |||
|When using '''READ_CONTINUOUS''' , set '''action''' to '''STOP''' , '''OFF''' , '''CANCEL''' , | |||
or '''DISABLE''' to stop the loop. Not required when using | |||
'''STOP_READ_CONTINUOUS'''. | |||
|} | |||
* '''Stop Response Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|"stop-read-cont" | |||
|Same request identifier received in the stop request. | |||
|- | |||
|origin | |||
| string | |||
|"canopen-actor" | |||
|Identifies the component that generated the response. | |||
|- | |||
|task.alias | |||
|string | |||
|"READ_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 read loop is no longer running. | |||
|- | |||
|task.taskResult.stopped | |||
|boolean | |||
|true | |||
|Indicates whether there was an active task that was actually stopped. If no continuous | |||
task was running, this may be '''false'''. | |||
|} | |||
====== Continuous PDO Reading ====== | |||
Starts continuous PDO-based position reading. | |||
This command does not perform repeated SDO reads. Instead, it waits for TPDO frames already being transmitted by the CANopen node. | |||
Normally, the TPDO should be configured first using '''CONFIG_POSITION_TPDO'''. | |||
The initial command returns an acknowledgement. After that, continuous sample responses are published repeatedly to: '''canopenRM8007/runtime/out''' | |||
* '''Start Request''' | |||
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "APP", | |||
"task": { | |||
"alias": "READ_PDO_CONTINUOUS", | |||
"taskParams": { | |||
"node_id": 5, | |||
"pdo_num": 1, | |||
"steps_per_rev": 4096, | |||
"offset": 0, | |||
"size": 4, | |||
"signed": false, | |||
"timeout": 1.0, | |||
"interval_ms": 20 | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
* '''Start Acknowledgement''' | |||
'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "canopen-actor", | |||
"task": { | |||
"alias": "READ_PDO_CONTINUOUS", | |||
"taskResult": { | |||
"success": true, | |||
"running": true, | |||
"mode": "pdo", | |||
"pdo_num": 1, | |||
"interval_ms": 20 | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
* '''Continuous Sample Response''' | |||
'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1"> | |||
{ | |||
"id": "<TIMESTAMP>", | |||
"origin": "canopen-actor", | |||
"task": { | |||
"alias": "READ_PDO_CONTINUOUS", | |||
"taskResult": { | |||
"success": true, | |||
"node_id": 5, | |||
"pdo_num": 1, | |||
"angle_deg": 90.0, | |||
"steps_per_rev": 4096, | |||
"revolutions": 0.25, | |||
"raw": 1024, | |||
"data": [0, 4, 0, 0], | |||
"offset": 0, | |||
"size": 4, | |||
"signed": false, | |||
"continuous": true, | |||
"request_id": "read-pdo-cont-node5" | |||
} | |||
} | |||
} | |||
</syntaxhighlight>'''Start Request Parameters''' | |||
{| class="wikitable" | |||
|'''Parameter''' | |||
|'''Type''' | |||
|'''Required''' | |||
|'''Example''' | |||
|'''Description''' | |||
|- | |||
|id | |||
| string | |||
|Yes | |||
|"<TIMESTAMP>" | |||
|Unique request identifier. Continuous sample responses include | |||
this value as '''request_id'''. | |||
|- | |||
|origin | |||
| string | |||
|No | |||
|"APP" | |||
|Identifies the sender of the request, for example '''APP , NodeRED ,''' | |||
'''CLI , or TestClient'''. | |||
|- | |||
|task | |||
|object | |||
|Yes | |||
|{...} | |||
|Main command object containing the command alias and | |||
parameters. | |||
|- | |||
|task.alias | |||
|string | |||
|Yes | |||
|"READ_PDO_CONTINUOUS" | |||
|Defines the command to execute. | |||
|- | |||
|task.taskParams | |||
|object | |||
|Yes | |||
|{...} | |||
|Contains the PDO continuous read parameters. | |||
|- | |||
|task.taskParams.node_id | |||
|integer | |||
|Yes* | |||
|5 | |||
|Numeric CANopen node ID to read from. | |||
|- | |||
|task.taskParams.nodeId | |||
|integer | |||
|Yes* | |||
|5 | |||
|Alternative spelling for '''node_id'''. | |||
|- | |||
|task.taskParams.node | |||
|string | |||
|Yes* | |||
|"motor_1" | |||
|Logical node name previously configured with '''CONFIG_CANOPEN'''. If | |||
used, the actor can reuse saved '''steps_per_rev , pdo_num ,''' | |||
'''offset , size''' , and '''signed''' values from the node configuration. | |||
|- | |||
|task.taskParams.pdo_num | |||
|integer | |||
|No | |||
|1 | |||
|TPDO number to listen to. If omitted, defaults to '''1'''. | |||
|- | |||
|task.taskParams.steps_per_rev | |||
|integer | |||
|Yes** | |||
|4096 | |||
|Number of raw position counts per mechanical revolution. Used | |||
to convert '''raw''' into '''revolutions''' and '''angle_deg'''. | |||
|- | |||
|task.taskParams.offset | |||
|integer | |||
|No | |||
|0 | |||
|Byte offset inside the PDO payload where the position value | |||
starts. | |||
|- | |||
|task.taskParams.size | |||
|integer | |||
|No | |||
|4 | |||
|Number of bytes to decode from the PDO payload. For a 32-bit | |||
position value, use '''4'''. | |||
|- | |||
|task.taskParams.signed | |||
|boolean | |||
|No | |||
|false | |||
|Defines whether the raw value should be decoded as signed or | |||
unsigned. | |||
|- | |||
|task.taskParams.timeout | |||
|number | |||
|No | |||
|1.0 | |||
|Timeout, in seconds, while waiting for each TPDO frame. If no | |||
TPDO is received within this time, the cycle fails. | |||
|- | |||
|task.taskParams.interval_ms | |||
|integer | |||
|No | |||
|20 | |||
|Delay between read cycles, in milliseconds. If '''0''' , the loop | |||
immediately starts the next cycle after yielding control. | |||
|- | |||
|task.taskParams.action | |||
|string | |||
|No | |||
|"START" | |||
|Optional action. If set to '''STOP , OFF , CANCEL , or DISABLE''' , the | |||
actor stops the continuous loop instead of starting it. | |||
|} | |||
* '''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 === | |||
<br> | |||
[[File:AtlasCode.svg|center|frameless|583x583px]] | [[File:AtlasCode.svg|center|frameless|583x583px]] | ||
=== 26. | <br> | ||
[ | |||
=== 26. Software Stack and IPC Architecture === | |||
<br> | |||
[[File:Hardware Peripherals Library Architecture.svg|center|frameless|1934x1934px]] | |||
=== 27. Related Products === | === 27. Related Products === | ||