Shop Learn P1 Docs P2 Docs
VESC UART Control with Spin — Parallax Forums

VESC UART Control with Spin

As mentioned in another thread, I'm working on an electric skateboard.
I'm hoping to use a Propeller to interface with several VESC (Vedder Electronic Speed Controller) boards. One reason for using VESC boards is VESC is an open source project. The source code for the VESC is available. The C code is out of my comfort zone. Rather than attempting to modify the VESC code, I'm hoping to interface with the VESC board using a Propeller.

There's a guide to Communicating with the VESC using UART but I find the instructions a bit sparse.



I'm attempting to figure out the commands and how they are used from the source code. I'm hopeful I'll be able to figure this all out but I thought I'd check here in case any of you have done something similar.

Do any of you have any suggestions on how to interface a Propeller (Spin or PASM preferred) with a VESC?

Searching the forums for "VESC" didn't produce any hits.

Comments

  • BeanBean Posts: 8,126
    edited 2020-08-10 12:52
    The VESC communicates over UART using packets with the following format:
    
    One Start byte (value 2 for short packets and 3 for long packets)
    One or two bytes specifying the packet length
    The payload of the packet
    Two bytes with a CRC checksum on the payload
    One stop byte (value 3)
    

    Why on earth would you use a stop byte value that is the same as a possible start byte value ?

    Bean
  • Bean wrote: »
    Why on earth would you use a stop byte value that is the same as a possible start byte value ?

    Bean

    I don't know. I think the original comm protocol used CAN. I'm guessing the "3" value for start and stop doesn't present the same issue when using CAN.
    The VESC communicates over UART using packets with the following format:
    
    One Start byte (value 2 for short packets and 3 for long packets)
    One or two bytes specifying the packet length
    The payload of the packet
    Two bytes with a CRC checksum on the payload
    One stop byte (value 3)
    

    The line "The payload of the packet" is disappointingly vague. I'm reading through the code attempting to understand how this payload is structured.

    I'll likely load one of the Arduino based examples and monitor the com line with a logic analyzer to see if the payload structure becomes understandable.

    I was kind of hoping there would be a list of commands and what they do someplace (other than within the code). Something like this one for Dynamixel actuators would be great.

    I like to think I'll be able to figure this out from the code and from monitoring communication from an Arduino. I'll post what I learn to the forum in case anyone else wants to control a VESC using a Propeller.
  • I think the payload is made up of a command followed by appropriate data.

    I believe the commands are listed in this file (part of a Raspberry Pi VESC project).

    There's also a Python file to get values from the VESC and set values in the VESC.

    Hopefully this is enough info for me to write a Spin program to interface with the VESC. I'll post an update whether or not it works.
  • mmm yeah, not the best instructions in the world. It basically comes down to 'use the source Luke'. Can not offer a source, but hope this gives some direction:

    Packet structure is described in the blog
        One Start byte (value 2 for short packets and 3 for long packets)
        One or two bytes specifying the packet length
        The payload of the packet
        Two bytes with a CRC checksum on the payload
        One stop byte (value 3)
    

    the start byte value basically indicates the index where the payload starts (ie length > 255, two bytes needed, use 3 other wise 2)

    For the payload you need to look in the bldc_interface.c file. It seems to consist of a command followed by a set of parameters depending on the command. The commands used are defined in datatypes.h.

    Example using the command given in the blog:
    "bldc_interface_set_current(10.0);
    

    bldc_interface.c
    void bldc_interface_set_current(float current) {
    	if (motor_control_set_func) {
    		motor_control_set_func(MOTOR_CONTROL_CURRENT, current);
    		return;
    	}
    	int32_t send_index = 0;
    	send_buffer[send_index++] = COMM_SET_CURRENT;
    	buffer_append_float32(send_buffer, current, 1000.0, &send_index);
    	send_packet_no_fwd(send_buffer, send_index);
    }
    

    datatypes.h
    typedef enum {
    	MOTOR_CONTROL_DUTY = 0, 
    	MOTOR_CONTROL_CURRENT,
    	MOTOR_CONTROL_CURRENT_BRAKE,
    	MOTOR_CONTROL_RPM,                                   
    	MOTOR_CONTROL_POS
    } motor_control_mode;
    ....
    typedef enum {
    	COMM_FW_VERSION = 0,
    	COMM_JUMP_TO_BOOTLOADER,
    	COMM_ERASE_NEW_APP,
    	COMM_WRITE_NEW_APP_DATA,
    	COMM_GET_VALUES,
    	COMM_SET_DUTY,
    	COMM_SET_CURRENT,
    	COMM_SET_CURRENT_BRAKE,
    	COMM_SET_RPM,
    	COMM_SET_POS,
    	COMM_SET_HANDBRAKE,
    	COMM_SET_DETECT,
    	COMM_SET_SERVO_POS,
    	COMM_SET_MCCONF,
    	COMM_GET_MCCONF,
    	COMM_GET_MCCONF_DEFAULT,
    	COMM_SET_APPCONF,
    	COMM_GET_APPCONF,
    	COMM_GET_APPCONF_DEFAULT,
    	COMM_SAMPLE_PRINT,
    	COMM_TERMINAL_CMD,
    	COMM_PRINT,
    	COMM_ROTOR_POSITION,
    	COMM_EXPERIMENT_SAMPLE,
    	COMM_DETECT_MOTOR_PARAM,
    	COMM_DETECT_MOTOR_R_L,
    	COMM_DETECT_MOTOR_FLUX_LINKAGE,
    	COMM_DETECT_ENCODER,
    	COMM_DETECT_HALL_FOC,
    	COMM_REBOOT,
    	COMM_ALIVE,
    	COMM_GET_DECODED_PPM,
    	COMM_GET_DECODED_ADC,
    	COMM_GET_DECODED_CHUK,
    	COMM_FORWARD_CAN,
    	COMM_SET_CHUCK_DATA,
    	COMM_CUSTOM_APP_DATA,
    	COMM_NRF_START_PAIRING
    } COMM_PACKET_ID;
    


    packet payload
    0: 6  (COMM_SET_CURRENT)
    1-4: float32 representation of 10.0
    5-8: float32 representation of 1000.0
    

    Problem: my google-fu was not good enough to find how gcc stores a float32 (might be the same as binary32 ??)

    CRC = CRC16 value of the payload
  • rosco_pc wrote: »
    mmm yeah, not the best instructions in the world. It basically comes down to 'use the source Luke'.

    I like to think I'm slowly making sense of it. Of course it's easier to think I understand it when I haven't tested my knowledge yet.
    rosco_pc wrote: »
    Problem: my google-fu was not good enough to find how gcc stores a float32

    I'm pretty sure the float in the VESC is packaged the same way F32.spin packages a 32-bit float.
    rosco_pc wrote: »
    CRC = CRC16 value of the payload

    I've used CRC16 in other projects. I found some code by Mike Green which works great.
    PUB Crc16(bufferPtr, size)
    
    '' This method was written by Mike Green.
    '' Found on Parallax forums.
    
       result := $FFFF
       repeat size
          result ^= byte[bufferPtr++]
          repeat 8
             result := result >> 1 ^ ($A001 & (result & 1 <> 0))
    
    

    Thanks for your help in deciphering how the payload it built.





  • My initial attempts to communicate with the VESC didn't work.

    I just found this reply from Vedder on a forum. It looks really helpful. I had the CRC bytes reversed.

    I'll give this another try with this new info.
  • My latest attempt also didn't work.

    Here's the code I tried.
    PUB GetValues
    
      Pst.str(string(11, 13, "GetValues"))
      
      vescPayload := Vesc#COMM_GET_VALUES_4  'vescBuffer[2]
      vescSize := 1 'vescBuffer[1]
      result := Crc16(@vescPayload, 1) 
      vescBuffer[3] := result >> 8
      vescBuffer[4] := result
      vescBuffer[5] := 3
      TxOut(@vescBuffer, 6, globalEchoFlag)  
    
    DAT ' VESC Packet Buffer
    
    vescBuffer              byte 2
    vescSize                byte 0-0
    vescPayload             byte 0-0[257]
    

    The above code sent the following data.
    <$02> <$01> <$04> <$83> <$BE> <$03>
    
    

    Hopefully it's obvious those are bytes displayed in hexadecimal.

    I'll likely purchase the appropriate hardware to test the example code provided by Vedder. Hopefully I'll be able to figure out what I'm doing wrong by studying logic analyzer captures of valid packets.
  • Duane DegnDuane Degn Posts: 10,568
    edited 2020-08-16 04:25
    It looks like I'm doing something wrong with the CRC.

    I found an Arduino program to communicate with the VESC and here's a capture from my logic analyzer.

    VescCapture.PNG

    The output from the Arduino code is:
    <$02> <$01> <$04> <$40> <$84> <$03>
    
    

    The proper CRC is $40 $84.

    I'll need to figure out the correct way to calculate the CRC.
    2108 x 159 - 16K
  • Duane DegnDuane Degn Posts: 10,568
    edited 2020-08-16 16:24
    I translated the C code to calculate the CRC16 into Spin. Here's the C code.
    unsigned short crc16(unsigned char *buf, unsigned int len) {
        unsigned int i;
        unsigned short cksum = 0;
        for (i = 0; i < len; i++) {
            cksum = crc16_tab[(((cksum >> 8) ^ *buf++) & 0xFF)] ^ (cksum << 8);
        }
        return cksum;
    }
    

    The array "crc16_tab" has 256 16-bit elements. I'll include this table with the Spin code.
    Edit: As JonnyMac points out below, my CRC code is wrong. Look for updated code later in this thread. (Coming soon.)
    PUB GetValues
    
      Pst.str(string(11, 13, "GetValues"))
      
      vescPayload := Vesc#COMM_GET_VALUES_4  'vescBuffer[2]
      vescSize := 1 'vescBuffer[1]
    
      result := Crc16Vesc(@vescPayload, 1) 
      vescBuffer[3] := result >> 8
      vescBuffer[4] := result
      vescBuffer[5] := 3
      TxOut(@vescBuffer, 6, globalEchoFlag)  
    
    PUB Crc16Vesc(bufferPtr, size) | tableIndex
    
      repeat size
        tableIndex := (((result >> 8) | byte[bufferPtr++]) & $FF) | (result << 8)
        result := crcTable[tableIndex]
    
    DAT ' CRC Table  256 elements
    
    crcTable      word $0000, $1021, $2042, $3063, $4084
                  word $50a5, $60c6, $70e7, $8108, $9129, $a14a, $b16b, $c18c, $d1ad
                  word $e1ce, $f1ef, $1231, $0210, $3273, $2252, $52b5, $4294, $72f7
                  word $62d6, $9339, $8318, $b37b, $a35a, $d3bd, $c39c, $f3ff, $e3de
                  word $2462, $3443, $0420, $1401, $64e6, $74c7, $44a4, $5485, $a56a
                  word $b54b, $8528, $9509, $e5ee, $f5cf, $c5ac, $d58d, $3653, $2672
                  word $1611, $0630, $76d7, $66f6, $5695, $46b4, $b75b, $a77a, $9719
                  word $8738, $f7df, $e7fe, $d79d, $c7bc, $48c4, $58e5, $6886, $78a7
                  word $0840, $1861, $2802, $3823, $c9cc, $d9ed, $e98e, $f9af, $8948
                  word $9969, $a90a, $b92b, $5af5, $4ad4, $7ab7, $6a96, $1a71, $0a50
                  word $3a33, $2a12, $dbfd, $cbdc, $fbbf, $eb9e, $9b79, $8b58, $bb3b
                  word $ab1a, $6ca6, $7c87, $4ce4, $5cc5, $2c22, $3c03, $0c60, $1c41
                  word $edae, $fd8f, $cdec, $ddcd, $ad2a, $bd0b, $8d68, $9d49, $7e97
                  word $6eb6, $5ed5, $4ef4, $3e13, $2e32, $1e51, $0e70, $ff9f, $efbe
                  word $dfdd, $cffc, $bf1b, $af3a, $9f59, $8f78, $9188, $81a9, $b1ca
                  word $a1eb, $d10c, $c12d, $f14e, $e16f, $1080, $00a1, $30c2, $20e3
                  word $5004, $4025, $7046, $6067, $83b9, $9398, $a3fb, $b3da, $c33d
                  word $d31c, $e37f, $f35e, $02b1, $1290, $22f3, $32d2, $4235, $5214
                  word $6277, $7256, $b5ea, $a5cb, $95a8, $8589, $f56e, $e54f, $d52c
                  word $c50d, $34e2, $24c3, $14a0, $0481, $7466, $6447, $5424, $4405
                  word $a7db, $b7fa, $8799, $97b8, $e75f, $f77e, $c71d, $d73c, $26d3
                  word $36f2, $0691, $16b0, $6657, $7676, $4615, $5634, $d94c, $c96d
                  word $f90e, $e92f, $99c8, $89e9, $b98a, $a9ab, $5844, $4865, $7806
                  word $6827, $18c0, $08e1, $3882, $28a3, $cb7d, $db5c, $eb3f, $fb1e
                  word $8bf9, $9bd8, $abbb, $bb9a, $4a75, $5a54, $6a37, $7a16, $0af1
                  word $1ad0, $2ab3, $3a92, $fd2e, $ed0f, $dd6c, $cd4d, $bdaa, $ad8b
                  word $9de8, $8dc9, $7c26, $6c07, $5c64, $4c45, $3ca2, $2c83, $1ce0
                  word $0cc1, $ef1f, $ff3e, $cf5d, $df7c, $af9b, $bfba, $8fd9, $9ff8
                  word $6e17, $7e36, $4e55, $5e74, $2e93, $3eb2, $0ed1, $1ef0
                                 
    

    My Propeller version of the CRC produces the same output as the Arduino.

    So far, I've only computed the CRC for a single byte payload. Hopefully this method works for larger payloads as well.

    Now I need to figure out how to parse out the reply message. The reply includes 16-bit floats which I haven't used with the Propeller before. Hopefully it won't be hard to convert 16-bit floats into 32-bit floats so I can use F32.spin to perform appropriate operations on the floating point values.
  • rosco_pcrosco_pc Posts: 432
    edited 2020-08-16 08:52
    C-code from this page: https://exceptionshub.com/32-bit-to-16-bit-floating-point-conversion.html
    float f = ((h&0x8000)<<16) | (((h&0x7c00)+0x1C000)<<13) | ((h&0x03FF)<<13);
    

    edit: making good progress :)
  • JonnyMacJonnyMac Posts: 8,232
    edited 2020-08-16 14:53
    @"Duane Degn" I notice you have an OR operator where they have XOR. It seems like this would have an impact on multi-byte input.
    720 x 158 - 6K
  • rosco_pc wrote: »
    C-code from this page: https://exceptionshub.com/32-bit-to-16-bit-floating-point-conversion.html
    float f = ((h&0x8000)<<16) | (((h&0x7c00)+0x1C000)<<13) | ((h&0x03FF)<<13);
    

    edit: making good progress :)

    Wow! Thank you. That's just what I tried to find but couldn't . I had hoped it would be as easy as shifting some bits.
    JonnyMac wrote: »
    @"Duane Degn" I notice you have an OR operator where they have XOR. It seems like this would have an impact on multi-byte input.


    I didn't realize my C was that rusty. Thank you!

    I love this forum!
  • Duane DegnDuane Degn Posts: 10,568
    edited 2020-08-17 17:33
    The CRC code I posted had even more problems than the ones pointed out by Jon.

    I finally found my other mistakes and my calculated CRC now agrees with the one sent from the VESC. I also modified my CRC code to deal with a circular buffer. Here's my current CRC code.
    PUB Crc16Vesc(bufferAddress, bufferSize, byteIndex, dataSize) | tableIndex, localByte, shiftedHigh
    ' bufferAddress is the beginning of a ring buffer.
    ' bufferSize is the size of the ring buffer.
    ' byteIndex is the buffer index of the first byte to be used in the CRC calculation.
    ' dataSize is the number of bytes to be used in the CRC calculation.
    ' The method AdvanceWithRollover will zero byteIndex when the end of the buffer is reached.
    
      repeat dataSize
        localByte := byte[bufferAddress][byteIndex] ' It safest to perform bit operations on longs, not bytes.
        AdvanceWithRollOver(@byteIndex, bufferSize) ' Make sure byteIndex doesn't go past end of buffer.
        tableIndex := ((result >> 8) ^ localByte) & $FF
        shiftedHigh := result << 8
        result := crcTable[tableIndex] ^ shiftedHigh
        result &= $FFFF ' This is required since we're using 32-bit longs.
    

    The "Get Values" command is successfully sent and I receive a 73 byte payload in return. I haven't started parsing the payload yet but here's one of the payloads returned.
    goodCrcCount = 3, badCrcCount = 0
    vescRxPacketExpected = 73
    vescRxPacketSizeSoFar = 73
    vescHead = 234, vescTail = 233
    crcAsReceived = 21958 = $55C6, crcComputed = 21958 = $55C6
     <$04> <$01> <$43> <$00> <$E3> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00>
     <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$01> <$CF> <$00> <$00> <$00>
     <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00>
     <$01> <$00> <$00> <$00> <$03> <$00> <$10> <$D8> <$22> <$60> <$60> <$00> <$00> <$00> <$00> <$00>
     <$00> <$00> <$00> <$00> <$00> <$FF> <$FF> <$FF> <$FD>
    
    checkInputCount = 6241
    Rx Character = g
    GetValues
    TxOut, size = 6
     <$02> <$01> <$04> <$40> <$84> <$03>
    

    I also included the CRCs to show the calculated value agrees with the received value. The six bytes at the bottom of the text block are the bytes sent to the VESC.

    Thanks again to everyone who has helped so far.
  • As I try to figure out how the data is received, I'm starting to think the floating point values are just there to aid in displaying the data with decimal points in the right place. It appears all the data is actually packaged as integers. The various values have corresponding scaling factors.


  • I don't think I have the data figured out yet.

    The first byte of the payload is 4 which indicates it's a reply for my request for "values" but I doubt I have the various values link to the correct variables.
    processedData = 12, processedValues = 12
    @valueNameText = 408
    @valueNameText = vIn <$04> <$01> <$35> <$00> <$DA> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00>
     <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$01> <$D2> <$00> <$00> <$00>
     <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00>
     <$10> <$00> <$00> <$00> <$B2> <$00> <$06> <$02> <$15> <$F8> <$60> <$00> <$00> <$00> <$00> <$00>
     <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$00> <$03>
    vIn = 30.9
    tempMos1 = 21.8
    tempMos2 = 0.0
    tempMos3 = 0.0
    tempMos4 = 0.0
    tempMos5 = 0.0
    tempMos6 = 0.0
    tempPcb = 0.00
    currentMotor = 0.00
    currentIn = 0.000
    rpm = 466
    dutyNow = 0.0
    ampHours = 0.
    ampHoursCharged = 0.
    wattHours = 0
    wattHoursCharged = 0
    tachometer = 1048576
    tachometerAbs = 11665414
    faultCode = 2
    extraData = 21, 248, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    

    I'm not sure why "vIn" is set to 30.9. The voltage of the batteries I'm using adds up to about 45V.
    The temperature of the first MOSFET seems reasonable. I'm guessing my board only has one temperature sensor which is why the other MOSFETs are reported as zero degrees.

    I attempted to set the RPM to 60.
    SetRpm
    TxOut, size = 10
     <$02> <$05> <$08> <$00> <$00> <$00> <$3C> <$F5> <$F2> <$03>
    

    Either I'm doing something wrong with this command or 60 is too low for the RPM to produce motion. I didn't want the motors to go crazy on me since I don't have the secured very well right now. It's also possible I have to set some other parameter in order to set the RPM directly.

    The Arduino program I used as a guide for the "Get Values" command, doesn't have a function to set the RPM so I couldn't use my logic analyzer to check to see if my code generated the correct packet.

    I've ordered a STM32F0DISCOVERY board from Digikey. There's a very full featured example which uses this board. Hopefully I can monitor the UART with my logic analyzer and figure out how to set parameters and not just read them (not that I have the reading part all figured out).

    I'm making some progress, but it's painfully slow progress right now.
  • I just noticed a fault code of 2. This is an undervoltage fault.
    Of course this is assuming I'm reading the correct byte in the payload.

    I used the VESC-Tool to set up the board initially. I set the battery as a 12 cell LiPo. 30.9V would be too low of a voltage for a 12 cell battery but my battery is closer to 45V. I just measured the battery with my Fluke and it was close to 46V. I'm back to being confused.
  • Duane DegnDuane Degn Posts: 10,568
    edited 2020-08-19 01:12
    Duane Degn wrote: »
    I doubt I have the various values link to the correct variables.

    At least I was right about something. I'm pretty sure I was using the wrong list to assign the various values to variables. I used this structure:
    // VESC Types
    struct mc_values {
        float v_in;
        float temp_mos1;
        float temp_mos2;
        float temp_mos3;
        float temp_mos4;
        float temp_mos5;
        float temp_mos6;
        float temp_pcb;
        float current_motor;
        float current_in;
        float rpm;
        float duty_now;
        float amp_hours;
        float amp_hours_charged;
        float watt_hours;
        float watt_hours_charged;
        int32_t tachometer;
        int tachometer_abs;
        mc_fault_code fault_code;
    };
    

    The code below assigns values to variables one at a time. I'm now using this code to determine which bytes correspond to which variable. Notice the location of the "v_in" variable. I was treating a temperature value as the battery voltage value. Just one reason why I was/am so confused.
        switch (packetId)
        {
            case COMM_GET_VALUES:
                ind = 0;
                values.temp_mos1 = buffer_get_float16(message, 10.0, &ind);
                values.temp_mos2 = buffer_get_float16(message, 10.0, &ind);
                values.temp_mos3 = buffer_get_float16(message, 10.0, &ind);
                values.temp_mos4 = buffer_get_float16(message, 10.0, &ind);
                values.temp_mos5 = buffer_get_float16(message, 10.0, &ind);
                values.temp_mos6 = buffer_get_float16(message, 10.0, &ind);
                values.temp_pcb = buffer_get_float16(message, 10.0, &ind);
    
                values.current_motor = buffer_get_float32(message, 100.0, &ind);
                values.current_in = buffer_get_float32(message, 100.0, &ind);
                values.duty_now = buffer_get_float16(message, 1000.0, &ind);
                values.rpm = buffer_get_int32(message, &ind);
                values.v_in = buffer_get_float16(message, 10.0, &ind);
                values.amp_hours = buffer_get_float32(message, 10000.0, &ind);
                values.amp_hours_charged = buffer_get_float32(message, 10000.0, &ind);
                ind += 8; //Skip 9 bit
                values.tachometer = buffer_get_int32(message, &ind);
                values.tachometer_abs = buffer_get_int32(message, &ind);
                values.fault_code = (mc_fault_code)message[ind++];
    
                return true;
                break;
    
    

    When I originally read the above code, I thought the data was packaged as a combination of floats and integers. I'm now confident all the data is packaged as integers and the floats are only used to display the values.

    Looking back at the data, I see the battery voltage was read as 46.6V. This is pretty close to what I read using my multimeter. A bit of a silver lining to this confusing dark cloud.

    My next attempt will be to set the current value. I'm pretty sure the VESC is set to current control so hopefully this will allow me some control of the motor from the Propeller. As I mentioned previously, my attempt to control the RPM didn't work.
  • rosco_pcrosco_pc Posts: 432
    edited 2020-08-19 07:15
    They are integers scaled to look like floats, from buffer.c
    float buffer_get_float16(const uint8_t *buffer, float scale, int32_t *index) {
        return (float)buffer_get_int16(buffer, index) / scale;
    }
    

    EDIT: mmm that means the same should apply to setting the data in the command buffer, and yes indeed
    void buffer_append_float32(uint8_t* buffer, float number, float scale, int32_t *index) {
        buffer_append_int32(buffer, (int32_t)(number * scale), index);
    }
    

    Sorry for not digging deep enough when looking through the code :(
  • Duane DegnDuane Degn Posts: 10,568
    edited 2020-08-23 19:58
    rosco_pc wrote: »
    Sorry for not digging deep enough when looking through the code :(

    I asked about converting 16-bit floats to 32-bit floats and you answered my question. I certainly wasn't expecting anyone to dig through the code. Thanks again for the information your provided.

    I have made some more progress on this project. I can controller the two motors independently now.

    One of my initial problems was thinking I could just send occasional UART commands. The VESC expects a regular (several times a second?) stream of data over the UART or it will timeout and shut off the motor. This is certainly a reasonable thing to do.

    I now have the program send MOTOR_CURRENT commands at about 50 Hz. This seems to work well. I also wired up separate UART lines to each of the two ports on the VESC. There should be a way to send to just one port but I don't know how to do this.

    The motor doesn't start turning until the current is set to about 500. I thought this was 500mA but with both motors set to 500, the combined draw is about 160mA from the 47V battery. I don't know what sort of units the "500" is but I'm doubtful it's milliamps.
    rosco_pc wrote: »
    edit: making good progress :)

    Now that I can independently control two motors, I kind of agree with you.

    I'd like to figure out how to control these motors using RPM rather than current. If needed, I could monitor the encoders and adjust the current to produce the desired RPM. While I think this route is possible, I feel like I'd be duplicating work already possible with the VESC itself.

    Edit: I just realized I never tried sending RPM control signals repeatedly. It's possible this would work but I think I have to change some mode setting.
Sign In or Register to comment.