VESC - Custom Applications

Lightweight / Folding / Portable EVs - seats optional
Post Reply
vedder   100 W

100 W
Posts: 249
Joined: Nov 05 2011 9:37pm

VESC - Custom Applications

Post by vedder » Aug 20 2015 4:53pm

I wrote a short tutorial a few days ago about how to write and run custom applications for the VESC:
http://vedder.se/2015/08/vesc-writing-c ... lications/

As you can see, it does not take many lines to do something useful. Would anyone like to give this a try? If there is anything you have questions about in the code I will try my best to help. For example, you can use the PWM input from the servo_dec driver and write your custom application with e.g. smoothing and maybe add some brake lights using the ws2812 driver.

Regarding UART communication, I will write a library for that that can be used from any mcu that can be programmed in C and write a post about that. It would be nice if someone could give that a try on e.g. arduino.
Some of my projects: http://vedder.se
Support my open source ESC development with a small donation

pkondratyuk   1 mW

1 mW
Posts: 15
Joined: Apr 20 2015 8:14am

Re: VESC - Custom Applications

Post by pkondratyuk » Aug 21 2015 1:21am

Hi Benjamin,

I've written a simple Arduino library (attached) to send commands to VESC over UART. Hopefully it can be useful to other people who try VESC, in addition to the c library that you are gonna write. I am using it on Arduino Due but it should work on all other Arduions too (knock on wood). All the necessary code was extracted with some simplifications from the BLDC Tool source.

The library can send six commands:

Code: Select all

void SetCurrent(double val)   //Current control
  void SetRpm(double val)   //RPM control
  void SetDuty(double val)   //Set duty cycle
  void SetBrake(double val)   //Set brake current
  void Release()   //Release the motor
  void FullBrake()   //Short motor phases for max braking
To compile with the library, the header file should be placed into the folder .../Arduino/libraries/VescController/

Then the usage is like this:

Code: Select all

#include "VescController.h"

//Declare a controller object and tell it to use Serial1 port to communicate with VESC.
//Other serial ports on Arduino are called Serial, Serial2 and Serial3
//On some arduinos, like Arduino Nano, only Serial is available

VescController vesc(Serial1);

void setup
{
  Serial1.begin(115200);
}

void loop
{
   vesc.SetCurrent(3.00);
   delay(2000);

   vesc.SetRpm(7000);
   delay(2000);

   vesc.SetDuty(0.2);
   delay(2000);

   vesc.SetBrake(3.0);
   delay(2000);

   vesc.Release();
   delay(2000);

   void FullBrake();
   delay(2000);
}
Attachments
VescController.h
(4.51 KiB) Downloaded 477 times
Last edited by pkondratyuk on Aug 21 2015 1:58pm, edited 3 times in total.

erwincoumans   100 W

100 W
Posts: 141
Joined: Apr 02 2015 11:25pm

Re: VESC - Custom Applications

Post by erwincoumans » Aug 21 2015 1:32am

Benjamin wrote: Regarding UART communication, I will write a library for that that can be used from any mcu that can be programmed in C and write a post about that. It would be nice if someone could give that a try on e.g. arduino.
C sounds good, please avoid using Qt for such example, it is too large of a dependency.
pkondratyuk wrote:Hi Benjamin,

I've written a simple Arduino library (attached) to send commands to VESC over UART.
What are all the UART pin connections exactly on the VESC side and Arduino side? Some picture that shows the connections on both sides would be great.

pkondratyuk   1 mW

1 mW
Posts: 15
Joined: Apr 20 2015 8:14am

Re: VESC - Custom Applications

Post by pkondratyuk » Aug 21 2015 1:44am

@erwincoumans:
What are all the UART pin connections exactly on the VESC side and Arduino side?
On the Arduino side, it's simple - they are marked RX, TX and GND. If there are more serial ports, they are RX1, TX1, RX2, TX2 etc. On the VESC side the UART port is on the PWR_COMM connector. See this schematic from Vedder's site:

http://vedder.se/wp-content/uploads/201 ... atic-1.png and
http://vedder.se/wp-content/uploads/201 ... _Front.png

The UART pins on the PWR_COMM connector are 1, 2 and 4 (RX, TX and GND). Numbering on that connector starts from the side where the motor wires are soldered. You need to connect Arduino GND to VESC GND, Arduino RX to VESC TX, and Arduino TX to VESC RX.

Actually, if you are only sending commands from Arduino to VESC, you don't need Arduino RX to VESC TX connection. So it's only two wires in that case.

erwincoumans   100 W

100 W
Posts: 141
Joined: Apr 02 2015 11:25pm

Re: VESC - Custom Applications

Post by erwincoumans » Aug 21 2015 10:48pm

vedder wrote:Would anyone like to give this a try?
Yes, I am experimenting with it, thanks for the info!

By the way, how does the UDP feature in BLDC tool work? Do we need to solder a network connector on VESC?
It would be nice if someone could give that a try on e.g. arduino.
Yes, it works on Arduino Uno, using Serial instead of Serial1. It would be nice to add the option to receive status data, is that easy to add?

Thanks!

erwincoumans   100 W

100 W
Posts: 141
Joined: Apr 02 2015 11:25pm

Re: VESC - Custom Applications

Post by erwincoumans » Aug 23 2015 10:38am

Once you have a few VESC's it is fun to control them externally over CAN-bus. Such motion control over CAN could be useful for multi-wheel vehicles using VESC. Another application would be to perform Cartesian motion control for a robot, but that is outside of the scope of this forum.

I bought a cheap CAN-BUS shield for Arduino, and multiple VESCs can be controlled, pretty cool.
http://www.amazon.com/gp/product/B00NQV ... ge_o01_s00

This is the shield, and below is the script. It requires the CAN_BUS_Shield Arduino library to be installed (following the instructions here: http://www.seeedstudio.com/wiki/CAN-BUS_Shield).
It would be easy to support other commands too.

Code: Select all

comm_can_set_rpm(CAN_target_ID,electrical rpm);
FullSizeRender-9a.jpg
The script sets the target eRPM to 4000 for 0.1 second to VESC with CAN ID 1 and a VESC with CAN ID 5. After that it will set the eRPM for both VESCs to 0, then -4000 eRPM for 0.1 second and then it sets the RPM to 0 again (for a small test).

Code: Select all

// demo: CAN-BUS Shield, receive data with interrupt mode
// when in interrupt mode, the data coming can't be too fast, must >20ms, or else you can use check mode
// loovee, 2014-6-13

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

// 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 = 9;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin


unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void buffer_append_int16(uint8_t* buffer, int16_t number, int32_t *index) {
        buffer[(*index)++] = number >> 8;
        buffer[(*index)++] = number;
}

void buffer_append_uint16(uint8_t* buffer, uint16_t number, int32_t *index) {
        buffer[(*index)++] = number >> 8;
        buffer[(*index)++] = number;
}

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 buffer_append_uint32(uint8_t* buffer, uint32_t number, int32_t *index) {
        buffer[(*index)++] = number >> 24;
        buffer[(*index)++] = number >> 16;
        buffer[(*index)++] = number >> 8;
        buffer[(*index)++] = number;
}

// CAN commands
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;



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);
//        comm_can_transmit(controller_id | ((uint32_t)CAN_PACKET_SET_RPM << 8), buffer, send_index);
}


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,4000);
      comm_can_set_rpm(5,4000);
      delay(100);

      comm_can_set_rpm(1,0000);
      comm_can_set_rpm(5,0000);
    delay(1000);

     comm_can_set_rpm(1,-4000);
      comm_can_set_rpm(5,-4000);

    delay(100);
      comm_can_set_rpm(1,0000);
      comm_can_set_rpm(5,0000);

}

void MCP2515_ISR()
{
    flagRecv = 1;
}

void loop()
{
  
    if(flagRecv) 
    {                                   // check if get data

        flagRecv = 0;                   // clear flag

        // iterate over all pending messages
        // If either the bus is saturated or the MCU is busy,
        // both RX buffers may be in use and reading a single
        // message does not clear the IRQ conditon.
        while (CAN_MSGAVAIL == CAN.checkReceive()) 
        {
          
           
            // read data,  len: data length, buf: data buf
            CAN.readMsgBuf(&len, buf);

           Serial.print("Get Data From id: ");
           Serial.println(CAN.getCanId());
           if (CAN.isExtendedFrame())
           {
             Serial.println("IsExtendedFrame");
           } else
           {
            Serial.println("Is NOT ExtendedFrame");
       }
        
          // print the data
            for(int i = 0; i<len; i++)
            {
                Serial.print(buf[i]);Serial.print("\t");
            }
            Serial.println();
        }
    }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

User avatar
benj   100 W

100 W
Posts: 242
Joined: Jun 06 2013 3:32am

Re: VESC - Custom Applications

Post by benj » Sep 03 2015 8:52am

pkondratyuk wrote:Hi Benjamin,

I've written a simple Arduino library (attached) to send commands to VESC over UART. Hopefully it can be useful to other people who try VESC...
Hi pkondratyuk.

Firstly - thanks for the Arduino library you wrote. I got it working nicely, and modified it to work with SoftwareSerial as well. This allows me to control VESC over Bluetooth 8)

I'm trying to get values back from VESC as well, using COMM_GET_VALUES. I've dug through the video logger code from Vedder, and your code, and I can't see any reason why it shouldn't work....I literally just send the COMM_GET_VALUES value (4, as per packetinterface.cpp) along with the CRC bits, but I never get any serial data back.

I don't suppose you've tried or had any luck reading back VESC data over UART have you? I'm happy to share my code once it's tidy :)

pkondratyuk   1 mW

1 mW
Posts: 15
Joined: Apr 20 2015 8:14am

Re: VESC - Custom Applications

Post by pkondratyuk » Sep 03 2015 2:06pm

Hey benj,

I have not tried requesting data from VESC yet, though I plan to do that. I'll let you know when I get it working. If you figure it out before I get to it, could you make a post about it here, too?

Trbt555   10 W

10 W
Posts: 77
Joined: Oct 26 2015 12:47am

Re: VESC - Custom Applications

Post by Trbt555 » Jan 05 2016 3:51am

I've also started trying to get data back over CAN bus to Arduino.
Has anyone made any more progress on this yet ?
Shred.

User avatar
benj   100 W

100 W
Posts: 242
Joined: Jun 06 2013 3:32am

Re: VESC - Custom Applications

Post by benj » Jan 06 2016 10:10am

Hi trbt555,

Some people have it working over UART, but I'm not sure about CAN. See this thread https://endless-sphere.com/forums/viewt ... 35&t=73812

mastalyn   1 µW

1 µW
Posts: 2
Joined: Jan 14 2016 1:32am

Re: VESC - Custom Applications

Post by mastalyn » Jan 14 2016 1:39am

Hi.
How to interface an arduino with the vesc to send commands with tx?
Do i need to change something ?

User avatar
benj   100 W

100 W
Posts: 242
Joined: Jun 06 2013 3:32am

Re: VESC - Custom Applications

Post by benj » Jan 14 2016 5:25am

Hi mastalyn. In BLDC tool, go to App Configuration on the top tabs, and in General you must select 'UART' or 'PPM and UART' or 'ADC and UART'.

Now on the left tabs, choose UART and make sure you've set baud rate you want to use.

Now connect Arduino TX to VESC RX and + and GND, and that's all you need. The rest is coding.

mastalyn   1 µW

1 µW
Posts: 2
Joined: Jan 14 2016 1:32am

Re: VESC - Custom Applications

Post by mastalyn » Jan 14 2016 6:48am

Ok. Thank u
I will try

Trbt555   10 W

10 W
Posts: 77
Joined: Oct 26 2015 12:47am

Re: VESC - Custom Applications

Post by Trbt555 » Jan 22 2016 11:43am

erwincoumans wrote:Once you have a few VESC's it is fun to control them externally over CAN-bus. Such motion control over CAN could be useful for multi-wheel vehicles using VESC. Another application would be to perform Cartesian motion control for a robot, but that is outside of the scope of this forum.

The script sets the target eRPM to 4000 for 0.1 second to VESC with CAN ID 1 and a VESC with CAN ID 5. After that it will set the eRPM for both VESCs to 0, then -4000 eRPM for 0.1 second and then it sets the RPM to 0 again (for a small test).

Code: Select all

// demo: CAN-BUS Shield, receive data with interrupt mode
// when in interrupt mode, the data coming can't be too fast, must >20ms, or else you can use check mode
// loovee, 2014-6-13

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

// 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 = 9;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin


unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void buffer_append_int16(uint8_t* buffer, int16_t number, int32_t *index) {
        buffer[(*index)++] = number >> 8;
        buffer[(*index)++] = number;
}

void buffer_append_uint16(uint8_t* buffer, uint16_t number, int32_t *index) {
        buffer[(*index)++] = number >> 8;
        buffer[(*index)++] = number;
}

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 buffer_append_uint32(uint8_t* buffer, uint32_t number, int32_t *index) {
        buffer[(*index)++] = number >> 24;
        buffer[(*index)++] = number >> 16;
        buffer[(*index)++] = number >> 8;
        buffer[(*index)++] = number;
}

// CAN commands
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;



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);
//        comm_can_transmit(controller_id | ((uint32_t)CAN_PACKET_SET_RPM << 8), buffer, send_index);
}


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,4000);
      comm_can_set_rpm(5,4000);
      delay(100);

      comm_can_set_rpm(1,0000);
      comm_can_set_rpm(5,0000);
    delay(1000);

     comm_can_set_rpm(1,-4000);
      comm_can_set_rpm(5,-4000);

    delay(100);
      comm_can_set_rpm(1,0000);
      comm_can_set_rpm(5,0000);

}

void MCP2515_ISR()
{
    flagRecv = 1;
}

void loop()
{
  
    if(flagRecv) 
    {                                   // check if get data

        flagRecv = 0;                   // clear flag

        // iterate over all pending messages
        // If either the bus is saturated or the MCU is busy,
        // both RX buffers may be in use and reading a single
        // message does not clear the IRQ conditon.
        while (CAN_MSGAVAIL == CAN.checkReceive()) 
        {
          
           
            // read data,  len: data length, buf: data buf
            CAN.readMsgBuf(&len, buf);

           Serial.print("Get Data From id: ");
           Serial.println(CAN.getCanId());
           if (CAN.isExtendedFrame())
           {
             Serial.println("IsExtendedFrame");
           } else
           {
            Serial.println("Is NOT ExtendedFrame");
       }
        
          // print the data
            for(int i = 0; i<len; i++)
            {
                Serial.print(buf[i]);Serial.print("\t");
            }
            Serial.println();
        }
    }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/
I'm trying to reproduce your setup and failing. Perhaps you can help ?
What settings do you need in the VESC apart from their ID ?

I also don't understand your code.
The documentation says that the id in the instruction

Code: Select all

 CAN.sendMsgBuf(INT8U id, INT8U ext, INT8U len, data_buf) 
is the node where the data came from, that's the source , not the target.
It appears your using it as the target ?
Am I mistaken ? Or is the documentation worded wrong ?

Thanks.
Shred.

piyiotisk   10 mW

10 mW
Posts: 29
Joined: Jan 15 2016 10:38am

Re: VESC - Custom Applications

Post by piyiotisk » Jan 22 2016 1:11pm

hello, can i use nunchuck and arduino on the UART port on the same time? Basically i want to control the VESC using the wireless controller and read data (with arduino) from VESC( voltage, amps, etc) and send them to my mobile phone over bluetooth?

gabs   1 µW

1 µW
Posts: 1
Joined: Sep 16 2018 11:49pm

Re: VESC - Custom Applications

Post by gabs » Sep 18 2018 3:58am

Hi there,

Luckily, I have found this thread… since weeks I am thinking about a new vehicle – I would like to build.
Basically it will be a beer-box on wheels  https://www.youtube.com/watch?v=7RUAW5s0ttU
Instead of the combustion-engine, I would like to realize a 4x4 bldc set up. (Pmax/motor about 4kW)
 As there is not much space, I would avoid a mechanical brake and use the motors instead
I will have four times:
• Wheel (longboard)
• Belt
• Motor (outrunner bldc about 200kV and BLDC)
• Controller (vesc6?)
Imput to Arduino:
• Throttle
• Steering angle sensor  potentiometer
• Accelerometer (to realize an active seat-inclination-system (roll axis) at a later point)
• Individual wheel speed

1. Thanks to the potentiometer output, the individual wheel speed is calculated (steering kinematics)
2. To realize an efficient acceleration, I would like to realize a traction control aswell
After I have ready many threads (this one included), it seems the best way, to control the vescs with CAN
If you have some doubts about my assumptions please let me know  my background is 100% mechanical engineering :D

Is there a official dbc file for the vesc(6?) which would help to set up my can bus?

Thanks in advance

SG
Gabriel

erikaylen   1 µW

1 µW
Posts: 1
Joined: May 30 2019 1:34pm

Re: VESC - Custom Applications

Post by erikaylen » May 30 2019 1:36pm

I am also trying to implement VESC control over CAN. Has anyone else had any luck finding (or making?) a .dbc file for encoding/decoding CAN messages?

Post Reply