Page 1 of 1

VESC - Custom Applications

Posted: Aug 20 2015 4:53pm
by vedder
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.

Re: VESC - Custom Applications

Posted: Aug 21 2015 1:21am
by pkondratyuk
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);
}

Re: VESC - Custom Applications

Posted: Aug 21 2015 1:32am
by erwincoumans
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.

Re: VESC - Custom Applications

Posted: Aug 21 2015 1:44am
by pkondratyuk
@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.

Re: VESC - Custom Applications

Posted: Aug 21 2015 10:48pm
by erwincoumans
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!

Re: VESC - Custom Applications

Posted: Aug 23 2015 10:38am
by erwincoumans
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
*********************************************************************************************************/

Re: VESC - Custom Applications

Posted: Sep 03 2015 8:52am
by benj
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 :)

Re: VESC - Custom Applications

Posted: Sep 03 2015 2:06pm
by pkondratyuk
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?

Re: VESC - Custom Applications

Posted: Jan 05 2016 3:51am
by Trbt555
I've also started trying to get data back over CAN bus to Arduino.
Has anyone made any more progress on this yet ?

Re: VESC - Custom Applications

Posted: Jan 06 2016 10:10am
by benj
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

Re: VESC - Custom Applications

Posted: Jan 14 2016 1:39am
by mastalyn
Hi.
How to interface an arduino with the vesc to send commands with tx?
Do i need to change something ?

Re: VESC - Custom Applications

Posted: Jan 14 2016 5:25am
by benj
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.

Re: VESC - Custom Applications

Posted: Jan 14 2016 6:48am
by mastalyn
Ok. Thank u
I will try

Re: VESC - Custom Applications

Posted: Jan 22 2016 11:43am
by Trbt555
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.

Re: VESC - Custom Applications

Posted: Jan 22 2016 1:11pm
by piyiotisk
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?

Re: VESC - Custom Applications

Posted: Sep 18 2018 3:58am
by gabs
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

Re: VESC - Custom Applications

Posted: May 30 2019 1:36pm
by erikaylen
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?