T-motor Cubemars AK 80-64 arduino Spakfun CAN bus communication

how to you have it wired up?

Hello, i wanted to reply as i posted above i think. Im still having issues too to be honest ive got a steady win motor aswell as a cube mars one. Same problems
Motors work with calibration software
Used 2 can bus shields and arduinos to act as master and slave, they communicated fine with multiple codes
Tried ultra short cable lengths, resistors in every order still the same.
Ive been trying to contact skyentific on youtube to see if he can help.
Next idea when i got back to it was to ask chat gpt 4 as its meant to be up to date and better with code that chat gpt 3.
While not very helpful i hope this information is of use

This is my wiring.

You could try a 120ohm resistor between CAN H and CAN L. But ill be honest if made no difference for me. Also make sure the can lines are less than 300mm long

I checked, it seems that I'm not receiving any CAN messages from T-motor to Arduino Uno. Any idea on how to resolve this?

I had similar issues, and nothing worked until I have changed the controller to MD80...

Have u guys received my mail? did it work?

I am also facing the same issue. I have a AK80-64 motor and I am trying it with Arduino Uno and MCP2515 (will try using ESP32 and TJA-1050 later)

I tried similar code and setup from the video given. Could you please help me out with this, I have been stuck on this since a while

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

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

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

//defining LED pins
#define LED1 7
#define LED2 8

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

//Set the values
float p_in = 0.0f;
float v_in = 0.0f;
float kp_in = 20.0f;
float kd_in = 1.0f;
float t_in = 0.0f;

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

const int SPI_CS_PIN = 10;  //SCK,MOSI,MISO and CS are 52,51,50 and 53 by default in MEGA

MCP_CAN CAN(SPI_CS_PIN);  //Setting CS PIN

void setup() {
  SERIAL.begin(115200);
  delay(1000);
  while (CAN_OK != CAN.begin(CAN_1000KBPS))  // 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: OKAY!!");

  //Initializing pins
  pinMode(UP, INPUT);
  pinMode(DOWN, INPUT);
  pinMode(LEFT, INPUT);
  pinMode(RIGHT, INPUT);
  pinMode(CLICK, INPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);

  //Pull analog pins high to enable reading from input movement device
  digitalWrite(UP, HIGH);
  digitalWrite(DOWN, HIGH);
  digitalWrite(LEFT, HIGH);
  digitalWrite(RIGHT, HIGH);
  digitalWrite(CLICK, HIGH);

  //Writing LED pins low to turn them OFF by default
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
}

long previousMillis = 0;

void loop() {
  float p_step = 0.001;
  //delay(200);
  if (digitalRead(UP) == LOW) {
    //move motor forward
    p_in += p_step;
  }
  if (digitalRead(DOWN) == LOW) {
    //move motor backward
    p_in -= p_step;
  }
  p_in = constrain(p_in, P_MIN, P_MAX);

  if (digitalRead(RIGHT) == LOW) {
    //Enable
    EnterMotorMode();
    digitalWrite(LED1, HIGH);
  }
  if (digitalWrite(LEFT) == LOW) {
    //Disable
    ExitMotorMode();
    digitalWrite(LED1, LOW);
  }

  //send CAN
  pack_cmd();

  //receive CAN
  if (CAN_MSGAVAIL == CAN.checkReceive())  //checking if data is 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) for RIGHT
  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 (disable)?? for LEFT
  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 cmd, between -4pi and 4pi
  /// 12 bit velocity command, between -30 and +30 rad/s
  ///

  // 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 = fminf(fmaxf(V_MIN, v_in), V_MAX);
  float kp = fminf(fmaxf(KP_MIN, kp_in), KP_MAX);
  float kd = fminf(fmaxf(KD_MIN, kd_in), KD_MAX);
  float t_ff = fminf(fmaxf(T_MIN, t_in), T_MAX);

  // convert float to unsigned ints for module to read
  unsigned int p_int = float_to_unit(p_des, P_MIN, P_MAX, 16);
  unsigned int v_int = float_to_unit(v_des, V_MIN, V_MAX, 12);
  unsigned int kp_int = float_to_unit(kp, KP_MIN, KP_MAX, 12);
  unsigned int kd_int = float_to_unit(kd, KD_MIN, KD_MAX, 12);
  unsigned int t_int = float_to_uint(t_ff, T_MIN, T_MAX, 12);

  ///pack ints into 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 Structure ///

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

  unsigned long canId = CAN.getCanId();

  /// 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 = unit_to_float(p_int, P_MIN, P_MAX, 16);
  v_out = unit_to_float(v_int, V_MIN, V_MAX, 12);
  t_out = unit_to_float(i_int, -T_MAX, T_MAX);
}

unsigned int float_to_unit(float x, float x_min, float x_max, int bits) {
  /// converts unsigned int to float, for lower and upper range, and no.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;
}

Hello, did you get a solution to your issue? I am also trying to communicate with the AK motor with an Arduino.

Thanks in advance!

Hi,

I'm also having the same issue of not receiving any topics from the motor over CAN. I have two Teensy's which can communicate over the CAN at 2000bps (the max CAN Baud rate for the motor). The Motor works with the same power supply, but with the app that they created (called upper computer download) using MIT Mode only.

However, I'm not getting anything on the CAN from the motor when on the teensy network (all I am doing is repeatedly sending out the "Enter MIT Mode command" message).

For this wiring you need to add ground to the CAN (i.e. from the CAN transceiver to the UART port on the motor) as your arduino and motor do not have a common ground.

Next I plan to try probing the CAN network (with the teensy) when driving the motor with the app. I will put an update on here if I find anything out.

My wiring with talking teensy's:

P.s. I know this isn't quite Arduino, but I think this is the best place to discuss this as I am pretty sure we all have the same issue.

My issue was my Baud rate, needs to be 1,000,000, when the motor is set to 1000Hz. I can now move the motor

Hello,
I am using an Arduino MKR WiFi 1010 with CAN shield to operate the TMotor AK 60-6.
I am working with CAN communication and referred to your code, but the motor does not seem to work.
When I press the buttons to change p_in, the output values change as shown below, but the motor itself does not appear to respond...

  • My code starts sending CAN messages after entering active motor mode.

Below is my full code.
Could you please help me with this issue? I would greatly appreciate your assistance.

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

// Joystick pin definitions
#define UP A1
#define DOWN A2
#define LEFT A3
#define RIGHT A4

// Value range 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

// Initialization of input values
float p_in = 0.0f;
float v_in = 0.0f;
float kp_in = 2.0f;
float kd_in = 1.0f;
float t_in = 0.0f;

// Initialization of output values
float p_out = 0.0f;
float v_out = 0.0f;
float t_out = 0.0f;

// CAN-BUS CS pin definition
const int SPI_CS_PIN = 3; // MKR CAN: CS to pin 3, INT to pin 7
MCP_CAN CAN(SPI_CS_PIN);  // Create CAN-BUS object

void setup() {
  // Initialize Serial communication
  Serial.begin(115200);
  delay(1000);

  // Initialize CAN-BUS
  while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ)) {
    Serial.println("CAN BUS Shield init fail");
    delay(100);
  }
  Serial.println("CAN BUS Shield is ok!");

  // Configure pin modes
  pinMode(UP, INPUT);
  pinMode(DOWN, INPUT);
  pinMode(LEFT, INPUT);
  pinMode(RIGHT, INPUT);

  // Set joystick input pins to pull-up
  digitalWrite(UP, HIGH);
  digitalWrite(DOWN, HIGH);
  digitalWrite(LEFT, HIGH);
  digitalWrite(RIGHT, HIGH);
}

bool motorModeActive = false;
long previousMillis = 0;
bool right_prev_state = HIGH; // Store previous state of the RIGHT pin
bool left_prev_state = HIGH;  // Store previous state of the LEFT pin
unsigned long previousTime = 0; // Store previous time
const unsigned long interval = 1000; // 1-second interval (1000ms)
unsigned long currentTime = 0;

void loop() {

  // Joystick input handling
  float p_step = 0.1;
  if (digitalRead(UP) == LOW) {
    p_in += p_step;  // Increase position value
    Serial.println("up");
    delay(100);
  }
  if (digitalRead(DOWN) == LOW) {
    p_in -= p_step;  // Decrease position value
    Serial.println("down");
    delay(100);
  }
  p_in = constrain(p_in, P_MIN, P_MAX);  // Limit position value to defined range

  // Handle RIGHT and LEFT button inputs
  bool right_current_state = digitalRead(RIGHT);
  bool left_current_state = digitalRead(LEFT);

  // Detect both edges of the RIGHT pin
  if (right_prev_state != right_current_state) {
    if (right_current_state == HIGH) {
      Serial.println("right: rising edge, motor activated");
      motorModeActive = true;
      EnterMotorMode();
    } else {
      Serial.println("right: falling edge");
    }
    delay(100);
  }

  // Detect both edges of the LEFT pin
  if (left_prev_state != left_current_state) {
    if (left_current_state == HIGH) {
      Serial.println("left: rising edge, motor deactivated");
      motorModeActive = false;
      ExitMotorMode();  // Deactivate motor
    } else {
      Serial.println("left: falling edge");
    }
    delay(100);
  }
  // Update states
  right_prev_state = right_current_state;
  left_prev_state = left_current_state;
  
  if (!motorModeActive) {
    Serial.println("Waiting for EnterMotorMode...");
    delay(1000); // Interval for waiting message output
    return; // Do not execute the rest of the loop code, remain in waiting state
  }

  // Send CAN message
  pack_cmd();

  // Receive and process CAN messages
  if (CAN_MSGAVAIL == CAN.checkReceive()) {
    unpack_reply();
  }

  // Output data at regular intervals
  currentTime = millis();
  // Output Serial message every second
  if (currentTime - previousTime >= interval) {
    previousTime = currentTime; // Update previous time to current time

    Serial.print(" ");
    Serial.print(p_in);
    Serial.print(" ");
    Serial.print(p_out);
    Serial.print(" ");
    Serial.print(v_out);
    Serial.print(" ");
    Serial.println(t_out);
  }
}

// Process received CAN message data
void unpack_reply() {
  byte len = 0;
  byte buf[8];
  unsigned long canId;

  // Receive CAN message
  CAN.readMsgBuf(&canId, &len, buf);

  // Extract values from CAN data
  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 integer data to floating-point values
  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);
}

// Activate motor mode
void EnterMotorMode() {
  byte buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC};
  CAN.sendMsgBuf(0x01, 0, 8, buf);
}

// Deactivate motor mode
void ExitMotorMode() {
  byte buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD};
  CAN.sendMsgBuf(0x01, 0, 8, buf);
}

// Create and send CAN command packet
void pack_cmd() {
  byte buf[8];

  // Limit input values to defined ranges
  float p_des = constrain(p_in, P_MIN, P_MAX);
  float v_des = constrain(v_in, V_MIN, V_MAX);
  float kp = constrain(kp_in, KP_MIN, KP_MAX);
  float kd = constrain(kd_in, KD_MIN, KD_MAX);
  float t_ff = constrain(t_in, T_MIN, T_MAX);

  // Convert floating-point values to integers
  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);

  // Insert values into CAN packet
  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;

  // Send CAN message
  if (CAN.sendMsgBuf(0x01, 0, 8, buf) == CAN_OK) {
    // Serial.println("Message Sent!");
  } else {
    Serial.println("Error Sending Message.");
  }
}

// Convert floating-point value to integer
unsigned int float_to_uint(float x, float x_min, float x_max, int bits) {
  float span = x_max - x_min;
  unsigned int max_int = (1 << bits) - 1;
  return (unsigned int)((x - x_min) * max_int / span);
}

// Convert integer value to floating-point
float uint_to_float(unsigned int x_int, float x_min, float x_max, int bits) {
  float span = x_max - x_min;
  unsigned int max_int = (1 << bits) - 1;
  return ((float)x_int * span / max_int) + x_min;
}

@sreade
Did you mean that you change the code like below??

from: CAN.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ)
to: CAN.begin(MCP_ANY, CAN_1000KBPS, MCP_16MHZ)

I am using a different library (FlexCAN_T4), but definitely do that, as the motor is set to 1000KBPS baud rate