VESC & CAN Bus communication to another MCU (NOT VESC)

General topics and discussions about the VESC and its development.
ExiD
Posts: 6
Joined: 28 Nov 2017, 12:41
Location: Russia

Re: VESC & CAN Bus communication to another MCU (NOT VESC)

Postby ExiD » 28 Nov 2017, 12:46

I need control my vesc 4.12 by arduino by CAN with MCP2515 shield and library fot it. I was able to receive can status data, but when im try to send command vesc does not reacts. How can i solve my problem? Perhaps i need another lib for 2515 or send wrong command?
code

Code: Select all

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

bool sendPacket(uint32_t id, uint8_t packet[], int32_t len);
void vesc_can_set_duty(uint8_t controller_id, float duty);
void comm_can_set_rpm(uint8_t controller_id, float rpm);

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];                        // Array to store serial string

typedef enum {
   CAN_PACKET_SET_DUTY = 0,
   CAN_PACKET_SET_CURRENT,
   CAN_PACKET_SET_CURRENT_BRAKE,
   CAN_PACKET_SET_RPM,
   CAN_PACKET_SET_POS,
   CAN_PACKET_FILL_RX_BUFFER,
   CAN_PACKET_FILL_RX_BUFFER_LONG,
   CAN_PACKET_PROCESS_RX_BUFFER,
   CAN_PACKET_PROCESS_SHORT_BUFFER,
   CAN_PACKET_STATUS
} CAN_PACKET_ID;


#define CAN0_INT 2                              // Set INT to pin 2
MCP_CAN CAN0(10);     // Set CS to pin 10

void buffer_append_int32(uint8_t* buffer, int32_t number, int32_t *index) {
   buffer[(*index)++] = number >> 24;
   buffer[(*index)++] = number >> 16;
   buffer[(*index)++] = number >> 8;
   buffer[(*index)++] = number;
}

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

   // 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_8MHZ) == 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
}

void loop()
{
   //vesc_can_set_duty(1, 0.5);
   delay(30);
   comm_can_set_rpm(1, 3000);
   int erpm = 0;
   if (!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
   {
      CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)

      if ((rxId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
         sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (rxId & 0x1FFFFFFF), len);
      else
         sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", rxId, len);

      Serial.print(msgString);

      if ((rxId & 0x40000000) == 0x40000000) {    // Determine if message is a remote request frame.
         sprintf(msgString, " REMOTE REQUEST FRAME");
         Serial.print(msgString);
      }
      else {
         for (byte i = 0; i<len; i++) {
            if (i >= 0 && i <= 3)
            {
               erpm = erpm << 8 | rxBuf[i];
            }
            sprintf(msgString, " 0x%.2X", rxBuf[i]);
            Serial.print(msgString);
         }
      }
      
      Serial.println(erpm);
   }
}


void vesc_can_set_duty(uint8_t controller_id, float duty)
{
   int32_t send_index = 0;
   uint8_t buffer[4];
   buffer_append_int32(buffer, (int32_t)(duty * 100000.0), &send_index);
   sendPacket(controller_id | ((uint32_t)CAN_PACKET_SET_DUTY << 8), buffer, send_index);
}
void comm_can_set_rpm(uint8_t controller_id, float rpm) {
   int32_t send_index = 0;
   uint8_t buffer[4];
   buffer_append_int32(buffer, (int32_t)rpm, &send_index);
   sendPacket(controller_id | ((uint32_t)CAN_PACKET_SET_RPM << 8), buffer, send_index);
}

bool sendPacket(uint32_t id, uint8_t packet[], int32_t len)
{
   // send data:  ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
   byte data[4] = { 0x00, 0x00, 0x0F, 0xFF };
   byte sndStat = CAN0.sendMsgBuf(id, 0, 4, data);
   if (sndStat == CAN_OK) {
      //Serial.println("Message Sent Successfully!");
   }
   else {
      //Serial.println("Error Sending Message...");
   }
}

pf26
Posts: 286
Joined: 28 Mar 2016, 14:37
Location: FR Valence

Re: VESC & CAN Bus communication to another MCU (NOT VESC)

Postby pf26 » 29 Nov 2017, 13:19

I think your sendPacket function has flaws:
- your need to send extended packets, not standard ones. (ie: the IDE bit in the CAN frame should be set)
- you seem to send only your "data" array, not the packet bytes.

ExiD
Posts: 6
Joined: 28 Nov 2017, 12:41
Location: Russia

Re: VESC & CAN Bus communication to another MCU (NOT VESC)

Postby ExiD » 29 Nov 2017, 14:53

pf26 wrote:- you seem to send only your "data" array, not the packet bytes.

"data" array is is the same as the buffer. I tried to set the array manually.

pf26 wrote:- your need to send extended packets, not standard ones. (ie: the IDE bit in the CAN frame should be set)

How format right extended ID?

skipper762
Posts: 9
Joined: 13 May 2017, 06:08

Re: VESC & CAN Bus communication to another MCU (NOT VESC)

Postby skipper762 » 29 Nov 2017, 20:56

HI ExiD,

Here is my code, for controlling the VESC using the MCP2515 and associated Arduino libraries

Code: Select all




#include <SPI.h>
#include "mcp_can.h"
#include "datatypes.h"
#include "buffer.h"
#include "crc.h"
#include "bldc_interface.h"
#define CAN_STATUS_MSGS_TO_STORE  10

#define DEBUG true
#define DEBUG_EN 1
const int SPI_CS_PIN = 9;
#define RX_BUFFER_SIZE 25
uint8_t rx_buffer[RX_BUFFER_SIZE];
unsigned int rx_buffer_last_id;
static mc_values values;
MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin

unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[10];


void buffer_append_int32(uint8_t* buffer, int32_t number, int32_t *index) {
        buffer[(*index)++] = number >> 24;
        buffer[(*index)++] = number >> 16;
        buffer[(*index)++] = number >> 8;
        buffer[(*index)++] = number;
}


void comm_can_set_duty(uint8_t controller_id, float duty) {
        int32_t send_index = 0;
        uint8_t buffer[4];
        buffer_append_int32(buffer, (int32_t)(duty*100000), &send_index);

        CAN.sendMsgBuf(controller_id | ((uint32_t)CAN_PACKET_SET_DUTY << 8), 1, send_index, buffer);
}

void comm_can_set_rpm(uint8_t controller_id, float rpm) {
        int32_t send_index = 0;
        uint8_t buffer[4];
        buffer_append_int32(buffer, (int32_t)rpm, &send_index);
        CAN.sendMsgBuf(controller_id | ((uint32_t)CAN_PACKET_SET_RPM << 8), 1, send_index, buffer);
}

//Puts the VESC in current control mode and sets the current
void comm_can_set_cur(uint8_t controller_id, float current){
        int32_t send_index = 0;
        uint8_t buffer[4];
        buffer_append_int32(buffer, (int32_t)(current*1000.0), &send_index);
        CAN.sendMsgBuf(controller_id | ((uint32_t)CAN_PACKET_SET_CURRENT << 8), 1, send_index, buffer);
}

//sets the break current of the VESC
void comm_can_set_break_cur(uint8_t controller_id, float current){
        int32_t send_index = 0;
        uint8_t buffer[4];
        buffer_append_int32(buffer, (int32_t)(current*1000.0), &send_index);
        CAN.sendMsgBuf(controller_id | ((uint32_t)CAN_PACKET_SET_CURRENT_BRAKE << 8), 1, send_index, buffer); 
}

void com_can_full_break(uint8_t controller_id){
  comm_can_set_duty(controller_id,0.0);
}

void comm_can_release(uint8_t controller_id){
  comm_can_set_cur(controller_id,0.0);
}

void comm_can_get_values(uint8_t controller_id){
   int32_t send_index = 0;
   uint8_t buffer[4];
   buffer[send_index++] =0 ;
   buffer[send_index++] = 0;         // make bollean send to false on VESC
   buffer[send_index++] = COMM_GET_VALUES;
   CAN.sendMsgBuf(controller_id | ((uint32_t)CAN_PACKET_PROCESS_SHORT_BUFFER << 8), 1, send_index, buffer);
 
}


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

START_INIT:

    if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
    {
        Serial.println("CAN BUS Shield init ok!");
    }
    else
    {
        Serial.println("CAN BUS Shield init fail");
        Serial.println("Init CAN BUS Shield again");
        delay(100);
        goto START_INIT;
    }

    attachInterrupt(0, MCP2515_ISR, FALLING); // start interrupt
   
     comm_can_set_rpm(1,0000);
     comm_can_set_rpm(2,0000);
     comm_can_set_rpm(3,0000);
     comm_can_set_rpm(4,0000);
   
}

can_status_msg stat_msgs[CAN_STATUS_MSGS_TO_STORE];

//Interrupt service routine for CAN shield
void MCP2515_ISR(){
  int ijk=0;
  uint32_t ind=0;
  unsigned int rxbuf_len;
  unsigned int rxbuf_ind;
  uint8_t crc_low;
  uint8_t crc_high;
  CAN.readMsgBuf(&len, buf);
   if(CAN.isExtendedFrame()){
      uint8_t id = CAN.getCanId() & 0xFF;
      CAN_PACKET_ID cmd = (CAN_PACKET_ID) (CAN.getCanId() >>8);
      if(DEBUG){
        Serial.println("The ID is: " + String(id));
        Serial.println("The CMD is: " + String(cmd));
      }
      can_status_msg *stat_tmp;  //tempoary status mesage
     
          switch(cmd){
            case CAN_PACKET_SET_DUTY:
              ind = 0;
            break;
            case CAN_PACKET_SET_CURRENT:
              ind = 0;
            break;
            case CAN_PACKET_SET_CURRENT_BRAKE:
              ind = 0;
            break;
            case CAN_PACKET_SET_RPM:
              ind = 0;
            break;
            case CAN_PACKET_SET_POS:
              ind = 0;
            break;
            case CAN_PACKET_FILL_RX_BUFFER:
            Serial.println("FILL_RX_BUFFER");
            delay(20);
              memcpy(rx_buffer + buf[0], buf + 1, len - 1);
              Serial.println("Memcpy_sucess");

            break;
            case CAN_PACKET_FILL_RX_BUFFER_LONG:
              rxbuf_ind = (unsigned int)buf[0] << 8;
              rxbuf_ind |= buf[1];
               if (rxbuf_ind < RX_BUFFER_SIZE) {
                  memcpy(rx_buffer + rxbuf_ind, buf + 2, len - 2);
               }
            break;
            case CAN_PACKET_PROCESS_RX_BUFFER:
              ind = 0;
              rx_buffer_last_id = buf[ind++];
              buf[ind++];
              rxbuf_len = (unsigned int)buf[ind++] << 8;
              rxbuf_len |= (unsigned int)buf[ind++];
     
              if (rxbuf_len > RX_BUFFER_SIZE) {
                break;
              }
              crc_high = buf[ind++];
              crc_low = buf[ind++];
     
              if (crc16(rx_buffer, rxbuf_len)== ((unsigned short) crc_high << 8| (unsigned short) crc_low)) {
                can_process_packet(rx_buffer, rxbuf_len);
              }
            break;
            case CAN_PACKET_PROCESS_SHORT_BUFFER:
              ind = 0;
              rx_buffer_last_id = buf[ind++];
              buf[ind++];
              can_process_packet(buf + ind, len - ind);
            break;

            break;
            case CAN_PACKET_STATUS:
               for (ijk = 0;ijk < CAN_STATUS_MSGS_TO_STORE;ijk++) { //for the stattus messages in the array
                stat_tmp = &stat_msgs[ijk];                         //point to the current one
                if (stat_tmp->id == id || stat_tmp->id == 0) { // if its a message form the same vesc or an udefined message, oveewrite it
                  ind = 0;
                  stat_tmp->id = id;
                  stat_tmp->rpm = (float)buffer_get_int32(buf, &ind);
                  stat_tmp->current = (float)buffer_get_int16(buf, &ind) / 10.0;
                  stat_tmp->duty = (float)buffer_get_int16(buf, &ind) / 1000.0;
                  break;
                }
               }

            break;
            default:
            break;
          }
         
         
   
    }
}


void can_process_packet(unsigned char *data, unsigned int len){
  Serial.println("Getting Here");
  int32_t ind = 0;
  int i = 0;
  unsigned char id = data[0];
  data++;
  len--;
  switch(id){
    case COMM_GET_VALUES:
      ind = 0;
      values.temp_mos1 = buffer_get_float16(data, 10.0, &ind);
      values.temp_mos2 = buffer_get_float16(data, 10.0, &ind);
      values.temp_mos3 = buffer_get_float16(data, 10.0, &ind);
      values.temp_mos4 = buffer_get_float16(data, 10.0, &ind);
      values.temp_mos5 = buffer_get_float16(data, 10.0, &ind);
      values.temp_mos6 = buffer_get_float16(data, 10.0, &ind);
      values.temp_pcb = buffer_get_float16(data, 10.0, &ind);
      values.current_motor = buffer_get_float32(data, 100.0, &ind);
      values.current_in = buffer_get_float32(data, 100.0, &ind);
      values.duty_now = buffer_get_float16(data, 1000.0, &ind);
      values.rpm = buffer_get_float32(data, 1.0, &ind);
      values.v_in = buffer_get_float16(data, 10.0, &ind);
      values.amp_hours = buffer_get_float32(data, 10000.0, &ind);
      values.amp_hours_charged = buffer_get_float32(data, 10000.0, &ind);
      values.watt_hours = buffer_get_float32(data, 10000.0, &ind);
      values.watt_hours_charged = buffer_get_float32(data, 10000.0, &ind);
      values.tachometer = buffer_get_int32(data, &ind);
      values.tachometer_abs = buffer_get_int32(data, &ind);
      values.fault_code = (mc_fault_code)data[ind++];
      break;
    default:
    break;
         
  }
 
}
int i=0;

void loop(){
  //comm_can_set_rpm(1,1500);
  comm_can_get_values(1);
  delay(500);



 
  /*
  comm_can_set_rpm(1,0000);
  comm_can_set_rpm(2,0000);
  comm_can_set_rpm(3,0000);
  comm_can_set_rpm(4,0000);
 
  Serial.println("Motor 1");
  comm_can_set_rpm(1,1500);
  delay(1000);
  Serial.println("Motor 2");
  comm_can_set_rpm(1,0);
  comm_can_set_rpm(2,1500);
  delay(1000);
  Serial.println("Motor 3");
  comm_can_set_rpm(2,0);
  comm_can_set_rpm(3,1500);
  delay(1000);
  Serial.println("Motor 4");
  comm_can_set_rpm(3,0);
  comm_can_set_rpm(4,1500);
  delay(1000);
  comm_can_set_rpm(4,0);

  Serial.println(F("Set RPM"));
  comm_can_set_rpm(1,1500);
  comm_can_set_rpm(2,1500);
  comm_can_set_rpm(3,1500);
  comm_can_set_rpm(4,1500);
 
  delay(500);
  Serial.println(F("Full Break"));
  com_can_full_break(1);
  com_can_full_break(2);
  com_can_full_break(3);
  com_can_full_break(4);
  delay(500);
  Serial.println(F("Current Control"));
  comm_can_set_cur(1,2.0);
  comm_can_set_cur(2,2.0);
  comm_can_set_cur(3,2.0);
  comm_can_set_cur(4,2.0);
  delay(500);
  Serial.println(F("Current Controled Break "));
  comm_can_set_cur(1,0.5);
  comm_can_set_cur(2,0.5);
  comm_can_set_cur(3,0.5);
  comm_can_set_cur(4,0.5);
  delay(500);
  Serial.println(F("Duty Control"));
  comm_can_set_duty(1,0.2);
  comm_can_set_duty(2,0.2);
  comm_can_set_duty(3,0.2);
  comm_can_set_duty(4,0.2);
  delay(500);
  Serial.println(F("Release"));
  comm_can_release(1);
  comm_can_release(2);
  comm_can_release(3);
  comm_can_release(4);
  delay(500);
 
  */

 
 
 

}






There are some mistakes in here, especially with the receiving data sections. I don't plan on developing this further as I've switched to a teensy for the CAN based control.

Cheers,
Nick

ExiD
Posts: 6
Joined: 28 Nov 2017, 12:41
Location: Russia

Re: VESC & CAN Bus communication to another MCU (NOT VESC)

Postby ExiD » 30 Nov 2017, 13:11

skipper762 wrote:HI ExiD,

Here is my code, for controlling the VESC using the MCP2515 and associated Arduino libraries


Thanks, I found my mistake.
Replace

Code: Select all

CAN0.sendMsgBuf(id, 0, 4, packet);

to

Code: Select all

CAN0.sendMsgBuf(id, 1, 4, packet);


All works.

xachmo
Posts: 2
Joined: 16 Sep 2017, 19:18
Location: California

Re: VESC & CAN Bus communication to another MCU (NOT VESC)

Postby xachmo » 03 Feb 2018, 03:36

Hi Nick,

I've got a similar setup; using a Teensy and MCP2562 and working on using it to control my VESC over CAN.

Was wondering how far you got with this ?

yosoufe
Posts: 47
Joined: 18 Jul 2016, 11:26
Location: Germany

Re: VESC & CAN Bus communication to another MCU (NOT VESC)

Postby yosoufe » 03 Feb 2018, 07:36

xachmo wrote:Hi Nick,

I've got a similar setup; using a Teensy and MCP2562 and working on using it to control my VESC over CAN.

Was wondering how far you got with this ?


It has been a long time that is working nicely


Return to “General”

Who is online

Users browsing this forum: Bing [Bot] and 1 guest