Jump to content

SENSBLUE ATLAS/Datasheet: Difference between revisions

No edit summary
 
(32 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[File:SENSBLUE-ATLAS-Gateway.png|center|frameless|360x360px]]
{{DISPLAYTITLE:Datasheet}}
 


<div style="margin: 15px 0;">
<div class="buy-now-container">
<span class="atlas-btn">[[SENSBLUE ATLAS/Technical Resources|Technical Resources]]</span>
<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
|-
|-
|Paxxxxxxxx
|PA000000103
|
|ATLAS IoT SBC V1 CM4. 2GB M2.0 M0 PB0
|
|V1
|
|2GB
|
|Yes
|
|-
|-
|PAxxxxxxxx
|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": {
       "D01": {
       "DO1": {
         "state": "open"
         "state": "open"
       },
       },
       "D02": {
       "DO2": {
         "state": "open"
         "state": "open"
       }
       }
Line 686: Line 692:
   "task": {
   "task": {
     "taskResult": {
     "taskResult": {
       "D01": {
       "DO1": {
         "success": true,
         "success": true,
         "state": "open"
         "state": "open"
       },
       },
       "D02": {
       "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": {
       "D01": {
       "DO1": {
         "success": true,
         "success": true,
         "state": "open"
         "state": "open"
       },
       },
       "D02": {
       "DO2": {
         "success": true,
         "success": true,
         "state": "close"
         "state": "close"
Line 736: Line 740:
     "action": "SET",
     "action": "SET",
     "taskParams": {
     "taskParams": {
       "D01": {
       "DO1": {
         "state": "open"
         "state": "open"
       },
       },
       "D02": {
       "DO2": {
         "state": "close"
         "state": "close"
       }
       }
Line 751: Line 755:
   "task": {
   "task": {
     "taskResult": {
     "taskResult": {
       "D01": {
       "DO1": {
         "success": true,
         "success": true,
         "state": "open"
         "state": "open"
       },
       },
       "D02": {
       "DO2": {
         "success": true,
         "success": true,
         "state": "close"
         "state": "close"
Line 3,772: Line 3,776:
   "task": {
   "task": {
     "taskResult": {
     "taskResult": {
       "D01": {
       "DO1": {
         "success": true,
         "success": true,
         "state": "low"
         "state": "low"
       },
       },
       "D02": {
       "DO2": {
         "success": true,
         "success": true,
         "state": "high"
         "state": "high"
       },
       },
       "D03": {
       "DO3": {
         "success": true,
         "success": true,
         "state": "high"
         "state": "high"
       },
       },
       "D04": {
       "DO4": {
         "success": true,
         "success": true,
         "state": "high"
         "state": "high"
       },
       },
       "D05": {
       "DO5": {
         "success": true,
         "success": true,
         "state": "high"
         "state": "high"
       },
       },
       "D06": {
       "DO6": {
         "success": true,
         "success": true,
         "state": "low"
         "state": "low"
       },
       },
       "D07": {
       "DO7": {
         "success": true,
         "success": true,
         "state": "low"
         "state": "low"
       },
       },
       "D08": {
       "DO8": {
         "success": true,
         "success": true,
         "state": "low"
         "state": "low"
Line 4,198: Line 4,202:
}
}
</syntaxhighlight>'''Buzzer State'''
</syntaxhighlight>'''Buzzer State'''
[[File:5 beeps.svg|left|frameless|700x700px]]
[[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'''


=== 25. Included Software Stack ===
{| 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. Hardware Libraries ===
<br>
[IMAGE PLACEHOLDER]
 
=== 26. Software Stack and IPC Architecture ===
<br>
[[File:Hardware Peripherals Library Architecture.svg|center|frameless|1934x1934px]]


=== 27. Related Products ===
=== 27. Related Products ===