I Need Help Coding ESP32 for Brake Lights. Will Pay $$/hr.

My build is stalled because I’m in over my head with trying to code an ESP32 (tinypico) to interact with my VESC and DieBieMS over CAN bus to drive some lighting.

The good news is I’ve got the hardware together and working enough to read the CAN communication happening on the system, but I just don’t know where to go from here.

I need help and and willing to pay a good market rate for it. I figured I’d ask here first before I went onto some of the freelance websites.


6 Likes

Looks like you’ve got some packets to parse!

I don’t have time to pickup freelance work these days, but if you’re still willing to take a crack at it yourself, I recommend checking out our Robogotchi Firmware repos as we deal with parsing the VESC protocol and making can-forward requests.

9 Likes

Ambitious project. What does the test setup look like other than an esp a vesc and some lights?

2 Likes

You mean for the lighting system? TJA1050 CAN transceiver, two step down buck converters, one 60v to 12v, and one 12v to 5v. The brake light is going to be N type PWM controlled, it’s a single color 12v strip. The running lights are 5v RGBW SK6812, two strips, both driven by its own data line, 20 LEDs per strip. Everything taps into the DBMS’s 2nd CAN port.

2 Likes

I could give this a shot over the winter break, I will try to get my hands on the TJA1050…

2 Likes

Why do you step down the 12v to 5v instead of stepping down the 60v again? Im not saying its wrong Im just curious as I imagine the power loss due inefficiency would add together. Is it because the 12v to 5v buck converter is much smaller then the one that can step down 60v to 12v?

Looks like the leds require 12v?

I get that part, he needs 12V for the leds and the 5v is I for the tinypico I guess. I’m a bit confused here though, as the esp32 is 3.3v chip so probably he is using the onboard regulator to step it down third time.
I was just wondering why the double(triple) step down, although I dont know if it really matter efficiency wise or the loss is neglectable.
Sorry for the derail, im stopping it and starting to look into how efficient these converters are :slight_smile:

1 Like

Space constraints. In the actual board I don’t have room for two full size 60v buck converters. Instead I have to vow for the one of these mini 12v to 5v converters. https://www.amazon.com/dp/B01MQGMOKI?psc=1&ref=ppx_yo2_dt_b_product_details

1 Like

It will be a slow project for me since I won’t be riding until spring. I would love the support! I can keep a steady support of beers to your door round the clock haha.

Also I have a bunch of TJA1050’s I’ll mail you one for free, DM me your address if you’d like.

The single color brake light strip is the 12v row true. The runner lights are 5v

1 Like

The TinyPico from UM can run off of 3.3v or 5v. It must have an onboard regulator cause you can power it up by USB too

1 Like

Here’s a mug shot of the breadboard for anyone who is interested.

2 Likes

For added measure, I think at least I’ve found the right door to knock on to figure this out.

If you’re connecting directly through UART there is a PPM state comm request called → ‘COMM_GET_DECODED_PPM’ and I’m 90% this is what Metr and others use to track throttle position.

It’s located here. bldc/datatypes.h at be439a2a55ae5b1ba8cce8ad6b0da2d80466e9df · vedderb/bldc · GitHub

And I believe the implementation for getting that info through CAN looks something like this from the rESCue repo. Though rESCue currently uses a mix of ERPM inputs as I understand it to determine whether the brake light should be one. As I understand it though this won’t result in brake lighting unless there is negative current. Meaning no light on during motion free sitting at a stop light etc.

3 Likes

Hey guys, I’m slowly trying to work through this as best I can. I got a lot of support from various people that reached out to me or vice versa, to take this project on myself and ask questions as I go so that I can learn from it. I’m a bit stuck at the moment.

I believe I am getting a VESC response now with PPM information, though I am having trouble understanding the output format. My short Arduino code is below.

My primary question is, have I gone about this correctly to read the PPM info, is the output as expected, and can anyone advise of the parsing format or where I can dig to find it?

#include <Arduino.h>
#include <ESP32CAN.h>
#include <CAN_config.h>


CAN_device_t CAN_cfg;               // CAN Config
unsigned long previousMillis = 0;   // will store last time a CAN Message was send
const int interval = 500;          // interval at which send CAN Messages (milliseconds)
const int rx_queue_size = 10;       // Receive Queue size
uint8_t vesc_id = 0;
uint16_t CAN_PACKET_PROCESS_SHORT_BUFFER = 8;   //From CanBus.H header typedef enum list kicks out --> CAN_PACKET_ID;  



void setup() {
  Serial.begin(9600);
  Serial.println("Basic Demo - ESP32-Arduino-CAN");
  CAN_cfg.speed = CAN_SPEED_500KBPS;
  CAN_cfg.tx_pin_id = GPIO_NUM_22;
  CAN_cfg.rx_pin_id = GPIO_NUM_21;
  CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
  // Init CAN Module
  ESP32Can.CANInit();
}

void loop() {

  CAN_frame_t rx_frame;

  unsigned long currentMillis = millis();

  // Receive next CAN frame from queue
  if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 3 * portTICK_PERIOD_MS) == pdTRUE) {

    if (rx_frame.FIR.B.FF == CAN_frame_std) {
      printf("New standard frame");
    }
    else {
      printf("New extended frame");
    }

    if (rx_frame.FIR.B.RTR == CAN_RTR) {
      printf(" RTR from 0x%08X, DLC %d\r\n", rx_frame.MsgID,  rx_frame.FIR.B.DLC);
    }
    else {
      printf(" from 0x%08X, DLC %d, Data ", rx_frame.MsgID,  rx_frame.FIR.B.DLC);
      for (int i = 0; i < rx_frame.FIR.B.DLC; i++) {
        printf("0x%02X ", rx_frame.data.u8[i]);
      }
      printf("\n");
    }
  }
  // Send CAN Message
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    CAN_frame_t tx_frame;
    tx_frame.FIR.B.FF = CAN_frame_ext;   
    tx_frame.MsgID = (uint32_t(0x8000) << 16) + (uint16_t(CAN_PACKET_PROCESS_SHORT_BUFFER) << 8) + vesc_id;   
    tx_frame.FIR.B.DLC = 0x07;
    tx_frame.data.u8[0] = 0x11;
    tx_frame.data.u8[1] = 0x00;
    tx_frame.data.u8[2] = 0x1F; // Comm_Packet_ID --> Comm_GET_DECODED_PPM     ,   0x1F = 31 in decimal
    tx_frame.data.u8[3] = 0x00;
    tx_frame.data.u8[4] = 0x00;
    tx_frame.data.u8[5] = 0x00;
    tx_frame.data.u8[6] = 0x00;
   
    ESP32Can.CANWriteFrame(&tx_frame);
  }
}
2 Likes

@rpasichnyk I’m stuck!

1 Like

I got the can module and will start playing with it next week. I will post my findings here :+1:t2:

2 Likes

It looks like not all CAN frames are captured. Things are happening pretty fast and on high BAUD rates it gets impossible to capture and print all frames with printf.

For example on the screenshot you attached, first line is “New extended frame from 0x00000511…”. The data you are interested in starts after 0x1F (COMM_GET_DECODED_PPM). On the screenshot you have 6 bytes of data after 0x1F.

Let’s look at VESC code:

	case COMM_GET_DECODED_PPM: {
		int32_t ind = 0;
		uint8_t send_buffer[50];
		send_buffer[ind++] = COMM_GET_DECODED_PPM;
		buffer_append_int32(send_buffer, (int32_t)(app_ppm_get_decoded_level() * 1000000.0), &ind);
		buffer_append_int32(send_buffer, (int32_t)(servodec_get_last_pulse_len(0) * 1000000.0), &ind);

What it does is writes 0x1F into the buffer and then it writes 8 bytes of data. First 4 bytes are ppm_decoded_level and then 4 bytes which are last_pulse_len. I don’t remember why, but trust me you want last 4 bytes (last_pulse_len)

When you get those 4 bytes, you need to put them into int32 and then divide by 1000000 to get ms value, like this one:

Screenshot 2021-12-27 at 10.08.08

But first you need to print missing frames. Lowering CAN baud rate might help. Try CAN_SPEED_100KBPS instead of CAN_SPEED_500KBPS. Don’t forget to change CAN BAUD rate on VESC as well.

What you should get is 3 frames right after each other.

CAN_PACKET_FILL_RX_BUFFER
CAN_PACKET_FILL_RX_BUFFER
CAN_PACKET_PROCESS_RX_BUFFER

7 Likes

That’s it!! It’s working! Hats off to you Roman! :partying_face: :pray: :pray: .

I adjusted the baud rate down to 125kbps in my arduino sketch, the VESC, and the DieBieMS. Unfortunately the DieBieMS stopped communicating when I did this. I think I’ll write Danny @JTAG about why that might be. But I cut the DBMS out of the CAN network and talked directly ESP32 to VESC I’ve now got two FILL_RX_BUFFERs frames and a PROCESS_RX_BUFFER frame upon each request.

I’m not sure that I’ll need the (last_pulse_len) value for my purposes? And I don’t think I understand what its doing in the first place.

The output from the four bytes after the COMM_GET_DECODED_PPM once converted to int32 and divided by 1000000 represent the throttle position -1 to +1 which is exactly what I had hoped for. VESC is doing the work to report % from the calibrated position in VESC Tool.

Roman thanks a bunch for the direction. I feel I cleared the first of a few hurdles finally. Off for a beer in celebration then back to it in trying to manipulate the data outside of the serial print. And also trying to figure out where these ghost frames 0x000005AE are coming from.

4 Likes

0xAE is address of Metr LTE. Even though you don’t have it, Metr Pro periodically searches for it :slight_smile:

2 Likes

Fancy that. Thanks again Roman!

1 Like