How to send an ExecuteCommand request from libcanard

Hi!

I’m currently trying to implement a c++ script using libcanard which will send an ExecuteCommand request to a remote node, but am struggling to find any examples of how to do this. I have an example of libcanard responding to an ExecuteCommand request but not sending.

Currently I have this code, which is called every 10seconds:

uavcan_node_ExecuteCommand_Request_1_1 send_cmd = {0};
send_cmd.command = 12;
uint8_t c_serialized[uavcan_node_ExecuteCommand_Request_1_1_SERIALIZATION_BUFFER_SIZE_BYTES_] = {0};
size_t c_serialized_size = sizeof(c_serialized);
const int8_t c_err = uavcan_node_ExecuteCommand_Request_1_1_serialize_(&send_cmd, &c_serialized[0], &c_serialized_size);
if (c_err>=0) {
    const CanardTransfer c_transfer = {
        .timestamp_usec = monotonic_time + MEGA,  // Set transmission deadline 1 second, optimal for heartbeat.
        .priority       = CanardPriorityNominal,
        .transfer_kind  = CanardTransferKindRequest,
        .port_id        = uavcan_node_ExecuteCommand_1_1_FIXED_PORT_ID_,
        .remote_node_id = 22,
        .transfer_id    = (CanardTransferID) (state->next_transfer_id.uavcan_node_execute_cmd++),
        .payload_size   = c_serialized_size,
        .payload        = &c_serialized[0],
    };
    (void) canardTxPush(&state->canard, &c_transfer);
}

Is it correct? Is there anything else I need for it to send a request?
When monitoring it using yakut, I cannot see it sending the command on the execute command id.

An example project which sends service requests would be really helpful.

Thanks in advance
Rebecca

It looks correct to me. There is one problem that is not going to affect your specific case: the transfer-ID counter should be maintained separately per remote node, so instead of this:

state->next_transfer_id.uavcan_node_execute_cmd++

…you should have something like this (where remote_node_id is 22 in your case):

state->next_transfer_id.uavcan_node_execute_cmd[remote_node_id]++

But as I said, this is not your problem at hand right now. Here’s what you could try:

  • Check the return value of canardTxPush().
  • Are you sure that the serialization completes successfully?
  • Try monitoring raw CAN frames using candump -decaxta any, and see if the transfer is making it to the bus.
  • Ensure the monotonic_time is correct and is not too far in the past (this would make the transfer dead on arrival).

Thanks for your quick response!

canardTxPush() is returning 1, which I think is correct.

The serialization is returning 0, so that’s successful.

When monitoring the raw CAN frames nothing its appearing on the bus from my node c++, only from 22. So its not actually transmitting the transfer.

I have the transmission deadline for the transfer set to 1 second, so should be plenty?

Yeah, it all sounds correct, so I would look for problems at the CAN layer. Maybe your driver is misbehaving. Try logging each frame as it is extracted from libcanard’s TX queue (since canardTxPush returns 1, that means that your transfer makes it to the queue but it is then lost somewhere between the queue and the bus).

Oh also, why are you using libcanard v1? Consider upgrading to v3, it comes with some important improvements (see the changelog on github).

Hi Pavel,

I think we were using v1 because that was the version we took when last working with C++. This morning I upgraded it to v3, did some other minor changes (mostly so I can monitor it) and the ExecuteCommand request is now being sent and being received by the remote node.

Thanks so much for your help!

1 Like