Candump log replay with PyCyphal v1.9

Watch this:

candump -l any

Now we have raw CAN frames stored in the standard candump log format in candump-2022-07-15_160731.log. The file looks like this:

(1657890452.649500) slcan0 197FE625#C90EED2E661A00FB
(1657890453.650392) slcan0 197FE625#C90EED2E661A00FC
(1657890455.650491) slcan0 197FE625#C90EED2E661A00FD
(1657890458.649485) slcan0 197FE625#C90EED2E661A00FE
(1657890459.649489) slcan0 197FE625#C90EED2E661A00FF

Now we can extract Cyphal/CAN traffic from that file using the candump pseudo-media-layer:

export UAVCAN__CAN__IFACE='candump:candump-2022-07-15_160731.log'
y sub uavcan.node.heartbeat 10:reg.udral.service.common.readiness 130:reg.udral.service.actuator.common.status

Monitor what was happening on the bus using y mon.

Convert data from raw candump log to JSON for multiple topics at once:

y sub +M uavcan.node.heartbeat 10:reg.udral.service.common.readiness 130:reg.udral.service.actuator.common.status > converted.json

Check out the converted JSON:

{"7509":{"_meta_":{"ts_system":1657823551.809849,"ts_monotonic":1227765.178565,"source_node_id":125,"transfer_id":31,"priority":"nominal","dtype":"uavcan.node.Heartbeat.1.0"},"uptime":3843,"health":{"value":0},"mode":{"value":0},"vendor_specific_status_code":0}}
{"130":{"_meta_":{"ts_system":1657823551.809247,"ts_monotonic":1227765.178476,"source_node_id":125,"transfer_id":31,"priority":"low","dtype":"reg.udral.service.actuator.common.Status.0.1"},"motor_temperature":{"kelvin":331.1372985839844},"controller_temperature":{"kelvin":303.8972473144531},"error_count":0,"fault_flags":{"overload":false,"voltage":false,"motor_temperature":false,"controller_temperature":false,"velocity":false,"mechanical":false,"vibration":false,"configuration":false,"control_mode":false,"other":false}}}
{"7509":{"_meta_":{"ts_system":1657823551.918804,"ts_monotonic":1227765.184008,"source_node_id":0,"transfer_id":0,"priority":"nominal","dtype":"uavcan.node.Heartbeat.1.0"},"uptime":0,"health":{"value":0},"mode":{"value":0},"vendor_specific_status_code":0}}
{"130":{"_meta_":{"ts_system":1657823552.809019,"ts_monotonic":1227766.177856,"source_node_id":125,"transfer_id":0,"priority":"low","dtype":"reg.udral.service.actuator.common.Status.0.1"},"motor_temperature":{"kelvin":331.1372985839844},"controller_temperature":{"kelvin":303.816650390625},"error_count":0,"fault_flags":{"overload":false,"voltage":false,"motor_temperature":false,"controller_temperature":false,"velocity":false,"mechanical":false,"vibration":false,"configuration":false,"control_mode":false,"other":false}}}
{"7509":{"_meta_":{"ts_system":1657823552.810083,"ts_monotonic":1227766.178854,"source_node_id":125,"transfer_id":0,"priority":"nominal","dtype":"uavcan.node.Heartbeat.1.0"},"uptime":3844,"health":{"value":0},"mode":{"value":0},"vendor_specific_status_code":0}}

You can then print that using PlotJuggler or whatever.

P.S. if you want the command to exit automatically when the log file is fully replayed, set the environment variable PYCYPHAL_CANDUMP_YOU_ARE_TERMINATED to a non-zero value. This is expected to be improved with https://github.com/OpenCyphal/pycyphal/issues/227

1 Like