Disable CAN heartbeat

I’m looking to talk to and control multiple ODrives over CANbus with an Arduino Due. I got a basic script going that just reads the heartbeat that the ODrive periodically sends, but now that I"ve confirmed the CAN communication is working, I want to disable the heartbeat. I read on a previous post that setting odrv0.axis0.config.can_heartbeat_rate_ms = 0 would disable the heartbeat, but I still get a heartbeat after setting that parameter and saving the config. The message I get for the heartbeat is:

ID: 0x21 Len: 8 Data: 0x0 0 0 0 1 0 0 0

This message is a bit confusing to me since I expected ID to be either 0x700 for the CMD ID as listed in the protocol docs or 0x01 for the CAN node ID I set for the ODrive (1). Could someone explain what exactly I’m looking at with this message?

My Arduino test code is below:

/**
 * Experimentation script using https://github.com/collin80/due_can/blob/master/examples/CAN_AutoBaud/CAN_AutoBaud.ino
 * as guidance.
 * 
 * ============= SEQUENCE THAT NEEDS TO BE IMPLEMENTED IN CAN PROTOCOL
 * 1) odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE (startup)
 * 2) odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL (startup)
 * 3) odrv0.axis0.controller.input_pos = <float> (repeat)
 * 
 * documentation of ODrive CAN protocol -> https://docs.odriverobotics.com/can-protocol
 * example of data frame for pos control -> https://discourse.odriverobotics.com/t/can-interface-available-for-testing/1448/8?u=andrew_103
 * 
 */

#include <due_can.h>
// #include <DueTimer.h>

void setup() {
  Serial.begin(115200);
  Can0.begin(CAN_BPS_250K);

  for (int filter = 0; filter < 3; filter++) {
    Can0.setRXFilter(filter, 0, 0, true);
  }
  for (int filter = 3; filter < 15; filter++) {
    Can0.setRXFilter(filter, 0, 0, false);
  }
}

void print_frame(CAN_FRAME &frame) {
  Serial.print("ID: 0x");
  Serial.print(frame.id, HEX);
  Serial.print(" Len: ");
  Serial.print(frame.length);
  Serial.print(" Data: 0x");
  for (int count = 0; count < frame.length; count++) {
    Serial.print(frame.data.bytes[count], HEX);
    Serial.print(" ");
  }
  Serial.print("\r\n");  
}

void loop() {
  if (Can0.available() > 0) {
    CAN_FRAME incoming;
    Can0.read(incoming);
    print_frame(incoming);
  }
}

Why? :thinking:

You can change the heartbeat frequency in the config, send it once a second if you want. But it’s useful to know that nothing has died, that’s what it’s for.

I agree that a heartbeat is useful, but for my application I won’t be using or checking for it. In that case, it just becomes bloat. I could filter for the specific ID of what I want but as I mentioned the ID for the heartbeat isn’t what it was in the docs so I’m not sure how to go about this from here or what message IDs to send/expect for other commands.

Should just have to set it to 0.

CANOpen heartbeat isn’t used. Just the “regular” heartbeat at 0x001.

** Note: These CANOpen messages are reserved to avoid bus collisions with CANOpen devices. They are not used by CAN Simple.

Thanks for the responses. As it turns out, I did successfully disable the heartbeat by setting it to 0 but only for axis0. The heartbeat was still active for axis1 which is what I was reading with my script. After setting the axis1 heartbeat to 0, I didn’t get a heartbeat message anymore.

If you are still interested, the id is fine it consists of the node_id and the command_id in your case you set the node_id to 1 and the heartbeat message_id is also 1. The command id get the lower 5 bits, the node id the later upper 6. Thus, your encoded id is 0b100001 or 0x21. I hope this helped. I am currently trying to get the heartbeat message working on my odrv as well, however my odrv starts spamming it (no break in between messages, looked at it with signal analyzer) when I haven’t sent anything in a while, has anybody an idea why?