API guide¶
Send NMT commands, write objects and walk a drive through the CiA 402 state machine, with code that compiles and is checked byte for byte.
The shape of the API¶
Everything is in namespace hf::vortex; include vortex/VortexHostSession.hpp (it includes the others).
| Type | What it is |
|---|---|
VortexHostSession |
The client: sendNmt(), sdoDownloadExpedited(), transport() |
VortexCanTransport |
The interface you implement: bool send(const VortexCanFrame&) |
VortexCanFrame |
id, dlc, extended, rtr, data[8], pad() |
NmtCommand |
NMT command bytes (VortexProtocol.hpp) |
kIdx*, kSub* |
Object indices (table) |
Every call returns bool: true when your transport accepted the frame. Nothing waits for the node.
Create a session¶
The session stores a reference: keep the transport alive as long as the session. It is cheap to create one per use.
NMT¶
sendNmt(command, node) sends a two-byte NMT frame. Node 0 addresses every node on the bus.
bool reset_and_start_all(VortexHostSession& session) {
constexpr std::uint8_t kAllNodes = 0; // NMT broadcast
return session.sendNmt(NmtCommand::ResetCommunication, kAllNodes) &&
session.sendNmt(NmtCommand::Start, kAllNodes);
}
| Command | Node goes to |
|---|---|
NmtCommand::Start |
Operational: PDOs run |
NmtCommand::Stop |
Stopped: only NMT and heartbeat |
NmtCommand::PreOperational |
Pre-operational: SDO works, PDOs do not |
NmtCommand::ResetNode |
Full application reset, then boot-up |
NmtCommand::ResetCommunication |
Communication objects reset, then boot-up |
Write an object (SDO download)¶
sdoDownloadExpedited(node, index, sub, value, size) writes size bytes (1, 2 or 4) of value, low byte first.
Any other size returns false without sending.
bool write_objects(VortexHostSession& session, std::uint8_t node) {
// 1 byte: modes of operation 0x6060:00 = 1 (profile position)
if (!session.sdoDownloadExpedited(node, kIdxModesOfOperation, 0, 1, 1)) return false;
// 2 bytes: controlword 0x6040:00 = 0x0006 (CiA 402 Shutdown)
if (!session.sdoDownloadExpedited(node, kIdxControlword, 0, 0x0006, 2)) return false;
// 4 bytes: vendor device id 0x2000:01 (placeholder index, see the protocol table)
return session.sdoDownloadExpedited(node, kIdxVendorDeviceId, kSubVendorDeviceId, 0xCAFE0001u, 4);
}
Use the size of the object's data type in the EDS: UNSIGNED8 / INTEGER8 1, UNSIGNED16 / INTEGER16 2,
UNSIGNED32 / INTEGER32 4. Pass negative values as their two's-complement bit pattern.
Enable a CiA 402 drive¶
A CiA 402 drive moves through its power state machine when you write commands to the controlword (0x6040) and
reports its state in the statusword (0x6041):
stateDiagram-v2
[*] --> SwitchOnDisabled: power on, initialisation
SwitchOnDisabled --> ReadyToSwitchOn: Shutdown 0x0006
ReadyToSwitchOn --> SwitchedOn: Switch on 0x0007
SwitchedOn --> OperationEnabled: Enable operation 0x000F
OperationEnabled --> SwitchedOn: Disable operation 0x0007
OperationEnabled --> QuickStopActive: Quick stop 0x0002
QuickStopActive --> SwitchOnDisabled: Disable voltage 0x0000
OperationEnabled --> Fault: fault
Fault --> SwitchOnDisabled: Fault reset 0x0080
Disable voltage (0x0000) also returns Ready to switch on and Switched on to Switch on disabled.
// CiA 402 controlword commands (CiA 402 part 2, controlword 0x6040).
constexpr std::uint16_t kCwShutdown = 0x0006; // -> Ready to switch on
constexpr std::uint16_t kCwSwitchOn = 0x0007; // -> Switched on
constexpr std::uint16_t kCwEnableOperation = 0x000F; // -> Operation enabled
constexpr std::uint16_t kCwFaultReset = 0x0080; // Fault -> Switch on disabled (rising edge of bit 7)
bool enable_drive(VortexHostSession& session, std::uint8_t node) {
for (std::uint16_t cw : {kCwFaultReset, kCwShutdown, kCwSwitchOn, kCwEnableOperation}) {
if (!session.sdoDownloadExpedited(node, kIdxControlword, 0, cw, 2)) {
return false;
}
// The session sends only: confirm each state in the statusword (0x6041) with your
// own SDO upload or a TPDO before sending the next command.
}
return true;
}
Select the mode of operation (0x6060) before enabling: 1 profile position, 3 profile velocity, 4 profile
torque, 6 homing, 8 / 9 / 10 cyclic synchronous position / velocity / torque, as far as the device supports them.
What the session does not do¶
| Need | Use |
|---|---|
| SDO response or abort, expedited SDO upload (read an object) | Your CAN receive path with CanOpen::ParseSdoResponse() from CanOpenExtras.h in hf-utils-canopen |
| Drive state from the statusword | CanOpen::DecodeStatusWord() and CanOpen::NextControlWord() in the same header |
| Heartbeat, EMCY | CanOpen::ParseHeartbeat(), CanOpen::ParseEmergency() in the same header |
| Segmented or block SDO (more than 4 bytes), PDO, SYNC | A CANopen stack (CANopenNode); configure the node's PDO mapping with SDO writes |
| Retries and timeouts | Your application: the session sends once |
Next: Porting.