Lidar CAN example for MRMS ESP32: Arduino, IMU, eFuse, BT, WiFi, CAN Bus (mrm-esp32)


If not already done so already, install Arduino software and make basic connections, as described in page for MRMS ESP32: Arduino, IMU, eFuse, BT, WiFi, CAN Bus (mrm-esp32). This setup is convenient, but it is not mandatory. Read on and we will describe how to connect some other microcontroller and power supply.

This setup is necessary for the rest of MRMS system. If You want to try just this example, don't copy all the libraries but only directories "mrm-common" and "mrm-can-bus". They provide CAN Bus support, but again just for ESP32 microcontroller, MRMS or any other. If You want to use some other MCU, You will have to start its CAN Bus driver. If You do so, this example will work for that board, too.


We will order the lidar to start measuring distance and sending the result every few milliseconds.


Starting from a basic connection, let's add a MRMS LIDAR 2m VL53L0X, CAN Bus (mrm-lid-can-b). Connecting a MRMS CAN Bus device is easy. Only a cable, like MRMS CAN Bus cable 10 cm (mrm-jst-can10), is necessary. The cable will connect 2 CAN Bus lines (low and high) and will also supply 0 V and 5 V through 3. and 4. wire.

However, this bus is not only intended for MRMS devices, but for any other CAN Bus compatible. You can read here how to connect Your boards to MRMS CAN Bus.


The program is short, but it hides some of the details in Mrm_can_bus class:

#include <mrm-can-bus.h>


Mrm_can_bus can;

uint8_t data[8];        // Message content: 8 bytes

void setup() {

  data[0] = COMMAND_SENSORS_MEASURE_CONTINUOUS;  // First byte of the content
  for (uint8_t i = 0; i < 8; i++)
    can.messageSend(0x180 + 2 * i, 1, data);
  for (uint8_t i = 0; i < 8; i++)
    can.messageSend(0x280 + 2 * i, 1, data);

void loop() {
  // Receive a message
  CANBusMessage* msg = can.messageReceive();
  if (msg != NULL && msg->data[0] == COMMAND_SENSORS_MEASURE_SENDING){
    uint16_t mm = (msg->data[2] << 8) | msg->data[1];
    Serial.println(" mm");
The program uses Mrm_can_bus class to access ESP32s CAN Bus hardware. setup() starts serial communication with PC so that Serial.print() can display the results. Array data is payload CAN Bus messages use. First we will use it for an outgoing message and so we set its first byte to COMMAND_SENSORS_MEASURE_CONTINUOUS. That's the command we'd like to execute. It will instruct the sensor to start sending measurement data continually. As You can have many lidars of this kind in Your CAN Bus, each is supposed to listen to just one message id. The whole range is covered by the 2 loops that follow: 0x180, 0x182,..., 0x18E, and the next one 0x280,..., 0x28E. You can change address the sensor listens to but You may not know how the one You have is set up. So, we start them all.

loop() receives messages. You should be familiar with CAN Bus message structure to understand data sent and received. When a message is received, the program will check first byte of the payload to see if it is a measurement result. If it is, it will convert bytes 2 and 3 into millimeters and will print the result.

You can use an oscilloscope or a logic analyzer to check the signals.

The program uses mrm-can-bus library which can be found in C:\Users\<Your login name>\Documents\Arduino\libraries\mrm-can-bus\src. Open mrm-can-bus.cpp in an editor. Notepad++ is a good choice. If You want to change bus speed from the default 250 kbps, find line with "CAN_TIMING_CONFIG_250KBITS" and change the constant. If You like to have messages' content displayed, change "#define VERBOSE 0" into "#define VERBOSE 1". This library is based on Espressif's native driver so Espressif original documentation will give You all the information.

If You use MRMS CAN Bus devices, by far the easiest option for CAN Bus usage will be to stick to the MRMS framework which takes care about messaging so CAN Bus layer is not exposed at all. When You demand MRMS LIDAR 2m VL53L0X, CAN Bus (mrm-lid-can-b) to return a measured distance, You just call a function. The framework takes care that the reasonably fresh result is supplied. The details of this work are not so easy to replicate.

Here is the complete CAN Bus interface:
CommandMCU -> sensorSensor -> MCUComment
Calibration0x05If a temperature varies greatly, a calibration will improve measuring. Calibration data are saved in sensor's flash.
Firmware0x190x1A LowByte HighByteFirmware version = (HighByte << 8) & LowByte.
FPS0x300x31 LowByte HighByteFrames Per Second (sensor's local loop frequency) = (HighByte << 8) & LowByte.
Id change0x40 newIdChanges message's id the sensor listens to. It is close to its address. Valid "newId" values are 0 - 14. Each value chooses addresses in one of 2 ranges: 0x180, 0x182,..., 0x18E and 0x280,..., 0x28E. 0 chooses 0x180, 1 0x182, etc.
Alive0xFF id0xFFIf the sensor with address "id" is present, it will return the message.
Measure once0x110x13 LowByte HighByteMeasures just once and returns the result. Result in mm = (HighByte << 8) & LowByte
Measure continuous0x100x13 LowByte HighByteInitiates measuring and returning of the measured temperature each few ms, if the distance changes. Result in mm = (HighByte << 8) & LowByte.
Stop measuring0x12
Ranging type0x42 type"type" is 0 for long range, 1 for high speed, and 2 for high accuracy. Data are retained in flesh memory during power loss.

CAN Bus limitations

For 1 node You will have no problems. If You plan to have many of them, check this page.