[CubeMars] CAN communication with CubeMars motor

Hi,

I am planning to use the CubeMars AK series motors for a robot project. I have the motors and the accompanying R-Link to set up the motors, I have tested the motors with the R-link so I know they work, but now I want to do more control using CAN Bus.

My problem is that when I try to send or receive CAN messages to and from the actuator nothing happens.

I have set up two Arduinos with CAN bus shields to test that the messages are being sent and that they can be received. So I know that the CAN bus is sending the “correct” signal through the CAN bus to the other Arduino since I can read the signal.

From the documentation (page 48 in the manual) it says that to enter the “MIT mode” one needs to send a command and then send the position command, but it is not working for me.

Can someone help me with this?


Motor: AK70-10 V1.1

SparkFun Arduino CAN shield

Arduino CAN-Bus shield: Arduino CAN Bus Shield | MYBOTSHOP.DE, 19,95 €

CubeMars manual: https://store.cubemars.com/images/file/20220225/1645777365858910.pdf

Arduino code

// demo: CAN-BUS Shield, send data
// loovee@seeed.cc

#include <mcp_can.h>
#include <SPI.h>
// #include <CAN.h>
/* core
 *  Test script for motor testing
*/

#ifdef ARDUINO_SAMD_VARIANT_COMPLIANC
    #define SERIAL SerialUSB
#else   
    //#define SERIAL Serial
#endif 

// Define joystick connection pins
#define UP      A1
#define DOWN    A3
#define LEFT    A2
#define RIGHT   A5
#define CLICK   A4

// Define LED pins
#define LED2 8
#define LED3 7

//const int SPI_CS_PIN = 10;
//MCP_CAN CAN(SPI_CS_PIN);
MCP_CAN CAN0(10);     // Set CS to pin 10


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

   
    //delay(1000);
     /*while (CAN_OK != CAN0.begin(CAN_1000KBPS))
    {
        Serial.println("CAN BUS Shield init fail");
        Serial.println("Iit CAN Bus Shield againg");
        delay(100);
    }*/ 

    // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
    if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
    else Serial.println("Error Initializing MCP2515...");

    CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
    Serial.println("CAN BUS enter normal mode");
    // Setup CAN ID
    unsigned char len = 0;
    unsigned char canId = 1;
    Serial.print("Can ID:");
    Serial.println(canId, HEX);
    
    //initialize pins
    pinMode(UP, INPUT);
    pinMode(DOWN, INPUT);
    pinMode(LED2, INPUT);
    pinMode(LED3, INPUT);

    // Pull analoge pins hig to eable reading of joystic movment
    digitalWrite(UP, HIGH);
    digitalWrite(DOWN, HIGH);
        
    // Write LED pins
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, HIGH);

    //Set to MIT mode
    unsigned char MIT[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0XFC};
    CAN0.sendMsgBuf(0x01, 0, 8, MIT);
    Serial.print("MIT mode command sent:");
    Serial.print(MIT[8], HEX); Serial.print(MIT[1], HEX); Serial.print(MIT[2], HEX); Serial.print(MIT[3], HEX);    Serial.print(MIT[4], HEX);      Serial.print(MIT[5], HEX);     Serial.print(MIT[6], HEX);     Serial.print(MIT[7], HEX); 
    
    
}


unsigned char   stmp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
void loop()
{
    long unsigned int rxId;
    unsigned char len = 0;
    unsigned char buf[8];
    unsigned char canId = 0; //CAN0.getCanId();
    //send data
    delay(50);


    
    
    stmp[0] = 0xFF;
    stmp[1] = 0x01;
    stmp[2] = 0x00;
    stmp[3] = 0x24;
    stmp[4] = 0x00;
    stmp[5] = 0x80;
    stmp[6] = 0;

    if (digitalRead(UP) == LOW)
    {
        stmp[7] = stmp[7] + 1;
        Serial.println("Input: UP");
        if (stmp[7] == 255) {
            stmp[7] = 254;
            // stmp[6] = 0;

        }
    }
    if (digitalRead(DOWN) == LOW)
    {
        stmp[7] = stmp[7] - 1;
        Serial.println("Input: DOWN");
        if (stmp[7] == 0) {
            stmp[7] = 1;
            // stmp[6] = 160;

        }
    }
    CAN0.sendMsgBuf(0x01, 0, 8, stmp);
    


    
    if(CAN_MSGAVAIL == CAN0.checkReceive())  // check incoming data
    {
        CAN0.readMsgBuf(&rxId, &len, buf); // read data
        
       // unsigned char canId = 0; //CAN0.getCanId();

        Serial.println("-----------------------");
        Serial.print("get data from ID: 0x");
        Serial.println(canId, HEX);

        for(int i = 0; i<len; i++)  //print the data
        {
            Serial.print(buf[i], HEX);
            Serial.print("\t");
            
        }
        Serial.println();

    }
}

Fixed the problem, was wrong code and a reversed connection.

Hi Jorgensao,

I’m currently having the same problem with the AK70-10 motors. I was able to configure the motor using the upper computer program. But now when I try to send the motor commands via CAN nothing happens. I have also checked that my CAN module is working by doing a similar tutorial. I’m using a Teensy 4.0 with a MCP2515 CAN module to communicate with the motors. Can you explain what you did to get yours working?

Hi,

I made sure the CAN cables were connected correctly, I used two 120 ohm resistors for the bus as I intend to add more motors later. If I understand correctly you nothing is happening then the motor has not received the “enterMotorMode” command which is detailed in the manual. When you send the command it should make a faint sound indicating that it is on.

I would get another microcontroller to read the signal you send from your Teensy 4.0 and see if it is sending the correct input to the motor, as well as check that the MCP2515 CAN module is set to correct rate (1MHz for AK70-10 from the manual).

If the CAN message sent from the Teensy that the other microcontroller is reading is correct according to the manual, the connections are correct according to the manual and the update rate is sett correct, the problem may be the wrong CAN id.

1 Like

Hi,

Thanks for the advice, my motors are working now. The clock rate of the MCP2515 CAN module was the problem!

Hello,
I am using an AK70-10 but something went wrong here. I cannot even connect the motor with the upper software. The driver is ok, the upper sw connects, but the motor led is still blue, it is not connecting properly with the r-link. Do you have any idea what can I do? Thanks, Paulo

Also, can you please share the arduino code that you said is working now? Thanks

I’ve the same set up as yours but my T-motor (AK70-10) is not working. Can you share your updated code that was working for you?

I have a motor
AK80-9 KV 100

I have an Arduino UNO

and can bus shield RobotDyn

I tried a lot but it didn’t work yet

I have attached the code used

But the engine doesn’t start

A blue light appears in the engine

Also, when the axis is rotated manually, it adjusts the speed values via the serial screen

But when sending control commands, it does not work

Submitting my graduation project tomorrow

Please help with all thanks

// demo: CAN-BUS Shield, send data
// loovee@seeed.cc

#include <mcp_can.h>
#include <SPI.h>

/SAMD core/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
//#define SERIAL 0x0
#define SERIAL Serial
#endif

// Define Joystick connection pins
#define UP A1
#define DOWN A3
#define RIGHT A5
#define CLICK A4
#define LEFT A2

//Define LED pins
#define LED2 8
#define LED3 7

// Value Limits
#define P_MIN -12.5f
#define P_MAX 12.5f
#define V_MIN -5.0f
#define V_MAX 5.0f
#define KP_MIN 0.0f
#define KP_MAX 500.0f
#define KD_MIN 0.0f
#define KD_MAX 5.0f
#define T_MIN 0.0f
#define T_MAX 5.0f

// Set values
float p_in = 0.0f;
float v_in = 0.0f;

float kp_in = 100.0f;
float kd_in = 0.0f;

float t_in = 0.0f;
// measured values
float p_out = 0.0f;
float v_out = 0.0f;
float t_out = 0.0f;

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 10;

MCP_CAN CAN(SPI_CS_PIN); // Set CS pin

void setup()
{
Serial.begin(115200);
delay(1000);
while (CAN_OK != CAN.begin(MCP_ANY,CAN_1000KBPS, MCP_16MHZ)) // init can bus : baudrate = 500k
{
Serial.println(“CAN BUS Shield init fail”);
Serial.println(" Init CAN BUS Shield again");
delay(100);
}
Serial.println(“CAN BUS Shield init ok!”);

// Initialize pins as necessary
pinMode(UP,INPUT);
pinMode(DOWN,INPUT);
pinMode(LEFT,INPUT);
pinMode(RIGHT,INPUT);
pinMode(CLICK,INPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);

// Pull analog pins high to enable reading of joystick movements
digitalWrite(UP, HIGH);
digitalWrite(DOWN, HIGH);
digitalWrite(LEFT, HIGH);
digitalWrite(RIGHT, HIGH);
digitalWrite(CLICK, HIGH);

// Write LED pins low to turn them off by default
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);

CAN.setMode(MCP_NORMAL); // Change to normal mode to allow messages to be transmitted
}

long previousMillis = 0;
void loop()
{
//do something
float p_step = 0.01;
if (digitalRead(UP)==LOW)
{
//move motor forward
p_in = p_in + p_step;
}
if (digitalRead(DOWN)==LOW)
{
//move motor backward
p_in = p_in - p_step;
}
p_in = constrain(p_in, P_MIN, P_MAX);
if (digitalRead(RIGHT)==LOW)
{
// Enable
EnterMotorMode();
digitalWrite(LED2, HIGH);
}
if (digitalRead(LEFT)==LOW)
{
// Disable
ExitMotorMode();
digitalWrite(LED2, LOW);
}

// send CAN
pack_cmd();

// receive CAN
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
{
unpack_reply();
}

//print data
Serial.print(millis()-previousMillis);
previousMillis = millis();
Serial.print(" “);
Serial.print(p_in);
Serial.print(” “);
Serial.print(p_out);
Serial.print(” “);
Serial.print(v_out);
Serial.print(” ");
Serial.println(t_out);
}

void EnterMotorMode(){
// Enter Motor Mode (enable)
byte buf[8];
buf[0] = 0xFF;
buf[1] = 0xFF;
buf[2] = 0xFF;
buf[3] = 0xFF;
buf[4] = 0xFF;
buf[5] = 0xFF;
buf[6] = 0xFF;
buf[7] = 0xFC;
CAN.sendMsgBuf(0x01, 0, 8, buf);
}

void ExitMotorMode(){
// Enter Motor Mode (enable)
byte buf[8];
buf[0] = 0xFF;
buf[1] = 0xFF;
buf[2] = 0xFF;
buf[3] = 0xFF;
buf[4] = 0xFF;
buf[5] = 0xFF;
buf[6] = 0xFF;
buf[7] = 0xFD;
CAN.sendMsgBuf(0x01, 0, 8, buf);
}

void Zero(){
// Enter Motor Mode (enable)
byte buf[8];
buf[0] = 0xFF;
buf[1] = 0xFF;
buf[2] = 0xFF;
buf[3] = 0xFF;
buf[4] = 0xFF;
buf[5] = 0xFF;
buf[6] = 0xFF;
buf[7] = 0xFE;
CAN.sendMsgBuf(0x01, 0, 8, buf);
}

void pack_cmd(){
byte buf[8];

/// CAN Command Packet Structure ///
/// 16 bit position command, between -4pi and 4pi
/// 12 bit velocity command, between -30 and + 30 rad/s
/// 12 bit kp, between 0 and 500 N-m/rad
/// 12 bit kd, between 0 and 100 N-m*s/rad
/// 12 bit feed forward torque, between -18 and 18 N-m
/// CAN Packet is 8 8-bit words
/// Formatted as follows. For each quantity, bit 0 is LSB
/// 0: [position[15-8]]
/// 1: [position[7-0]]
/// 2: [velocity[11-4]]
/// 3: [velocity[3-0], kp[11-8]]
/// 4: [kp[7-0]]
/// 5: [kd[11-4]]
/// 6: [kd[3-0], torque[11-8]]
/// 7: [torque[7-0]]

/// limit data to be within bounds ///
float p_des = constrain(p_in, P_MIN, P_MAX); //fminf(fmaxf(P_MIN, p_in), P_MAX);
float v_des = constrain(v_in, V_MIN, V_MAX); //fminf(fmaxf(V_MIN, v_in), V_MAX);
float kp = constrain(kp_in, KP_MIN, KP_MAX); //fminf(fmaxf(KP_MIN, kp_in), KP_MAX);
float kd = constrain(kd_in, KD_MIN, KD_MAX); //fminf(fmaxf(KD_MIN, kd_in), KD_MAX);
float t_ff = constrain(t_in, T_MIN, T_MAX); //fminf(fmaxf(T_MIN, t_in), T_MAX);
/// convert floats to unsigned ints ///
unsigned int p_int = float_to_uint(p_des, P_MIN, P_MAX, 16);
unsigned int v_int = float_to_uint(v_des, V_MIN, V_MAX, 12);
unsigned int kp_int = float_to_uint(kp, KP_MIN, KP_MAX, 12);
unsigned int kd_int = float_to_uint(kd, KD_MIN, KD_MAX, 12);
unsigned int t_int = float_to_uint(t_ff, T_MIN, T_MAX, 12);
/// pack ints into the can buffer ///

buf[0] = p_int >> 8;
buf[1] = p_int & 0xFF;
buf[2] = v_int >> 4;
buf[3] = ((v_int & 0xF) << 4) | (kp_int >> 8);
buf[4] = kp_int & 0xFF;
buf[5] = kd_int >> 4;
buf[6] = ((kd_int & 0xF) << 4) | (t_int >> 8);
buf[7] = t_int & 0xFF;
CAN.sendMsgBuf(0x01, 0, 8, buf);
}

void unpack_reply(){

/// CAN Reply Packet Structure ///
/// 16 bit position, between -4pi and 4pi
/// 12 bit velocity, between -30 and + 30 rad/s
/// 12 bit current, between -40 and 40;
/// CAN Packet is 5 8-bit words
/// Formatted as follows. For each quantity, bit 0 is LSB
/// 0: [position[15-8]]
/// 1: [position[7-0]]
/// 2: [velocity[11-4]]
/// 3: [velocity[3-0], current[11-8]]
/// 4: [current[7-0]]

byte len = 0;
byte buf[8];
/*CAN.readMsgBuf(&len, buf);

unsigned long canId = CAN.getCanId();

*/
///newly added from verified skyentific code initial one
unsigned long canId;
CAN.readMsgBuf(&canId, &len, buf); // The readMsgBuf() functions bring in the message ID. The getCanId() function is obsolete and no longer exists, don’t use it.

/// unpack ints from can buffer ///
unsigned int id = buf[0];
unsigned int p_int = (buf[1] << 8) | buf[2];
unsigned int v_int = (buf[3] << 4) | (buf[4] >> 4);
unsigned int i_int = ((buf[4] & 0xF) << 8) | buf[5];
/// convert uints to floats ///
p_out = uint_to_float(p_int, P_MIN, P_MAX, 16);
v_out = uint_to_float(v_int, V_MIN, V_MAX, 12);
t_out = uint_to_float(i_int, -T_MAX, T_MAX, 12);
}

unsigned int float_to_uint(float x, float x_min, float x_max, int bits){
/// Converts a float to an unsigned int, given range and number of bits ///
float span = x_max - x_min;
float offset = x_min;
unsigned int pgg = 0;
if (bits == 12){
pgg = (unsigned int) ((x-offset)*4095.0/span);
}
if (bits == 16){
pgg = (unsigned int) ((x-offset)*65535.0/span);
}
return pgg;
}

float uint_to_float(unsigned int x_int, float x_min, float x_max, int bits){
/// converts unsigned int to float, given range and number of bits ///
float span = x_max - x_min;
float offset = x_min;
float pgg = 0;
if (bits == 12){
pgg = ((float)x_int)*span/4095.0 + offset;
}
if (bits == 16){
pgg = ((float)x_int)*span/65535.0 + offset;
}
return pgg;
}

// END FILE

@Azib perhaps you can check?

@jorgensao @Nate Would Hi guys,

I’ve been trying to connect to the same motors as you guys and havent had any luck. Ive tried the changes that fixed it you guys but still cant get any response back. Would you guys be able to send the code that you finally got to work? Any help or advice is greatly appreciated.

hi nate,
I have the same problem as you
can you help me?
My cube mars cannot receive commands from the can bus module

can i see your program code and circuit? that would be very helpful, thank you