MVR2EB LIDAR module not reading hex instructions over UART Serial

I have an MVR2EB lidar module I got from amazon, and it can output in both hex and ASCII. I would really really really like to get it working in ASCII mode. Problem is, the module does not seem to be accepting the command and changing modes. According to the datasheet, I should send a string of "56 71 00 27" to switch to ASCII mode. I'm using Serial.write for this. Does my code at least look correct?

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200); // replace 17,16 with your RX/TX pins
  delay(1000);
  byte SendData[] = {0x56,0x71,0x00,0x27};
  Serial.print("Sending Message ");
  Serial.write(SendData,sizeof(SendData));
}

void loop() {
  if (Serial1.available() > 0) { // If anything comes in
    Serial.print(Serial1.read(), DEC); // read it and send it out
    Serial.print(", ");
    int Sync = Serial1.read();
    Serial.print(Sync, HEX); // read it and send it out
    Serial.print(", ");
    int code = Serial1.read();
    Serial.print(code, HEX); // read it and send it out
    Serial.print(", ");
    Serial.print(Serial1.read(), HEX); // read it and send it out
    Serial.print(", ");
    Serial.print(Serial1.read(), HEX); // read it and send it out
    Serial.print(", ");
    Serial.print(Serial1.read(), HEX); // read it and send it out
    Serial.print(", ");
    Serial.print(Serial1.read(), HEX); // read it and send it out
    Serial.print(", ");
    Serial.print(Serial1.read(), HEX); // read it and send it out
    Serial.print(", ");
    Serial.print(Serial1.read(), HEX); // read it and send it out
    Serial.print(", ");
    Serial.print(Serial1.read(), HEX); // read it and send it out
    Serial.print(", ");
    Serial.println(Serial1.read(), HEX); // read it and send it out
  }
}

The other issue is reading the hex it sends back in the serial monitor. I'm not sure I'm doing it right.
After running the code above, this is what the serial monitor gives me:

Sending Message Vq'137, 81, BD, 4, C7, 18, 26, FA, 0, 0, B2
137, 81, BD, 4, CC, 18, 26, FA, 0, 0, B9
137, 81, BD, 4, BC, 18, 26, FA, 0, 0, C9
137, 81, BD, 4, BC, 18, 26, FA, 0, 0, C9
137, 81, BD, 4, B4, 18, 26, FA, 0, 0, C1
137, 81, BD, 4, AC, 18, 26, FA, FFFFFFFF, FFFFFFFF, 89
129, C1, 4, 4E, 18, 26, FA, 0, 0, 47, FFFFFFFF
137, 81, C2, 4, 4F, 18, 26, FA, 0, 0, 45
137, 81, C2, 4, 66, 18, 26, FA, 0, 0, 6C
137, 81, C1, 4, 6E, 18, 26, FA, 0, 0, 67
137, 81, C1, 4, 6A, 18, 26, FA, 0, 0, 63
137, 81, C1, 4, 63, 18, 26, FA, 0, 0, 6A
137, 81, C1, 4, 5A, 18, 26, FA, 0, 0, 53
137, 81, C1, 4, 54, 18, 26, FA, 0, 0, 5D
137, 81, C1, 4, 5D, 18, 26, FA, 0, 0, 54
137, 81, C1, 4, 5C, 18, 26, FA, 0, 0, 55
137, 81, C1, 4, 5B, 18, 26, FA, 0, 0, 52
137, 81, C1, 4, 59, 18, 26, FA, 0, 0, 50
137, 81, C2, 4, 48, 18, 26, FA, 0, 0, 42
137, 81, C2, 4, 52, 18, 26, FA, 0, 0, 58
137, 81, C2, 4, 56, 18, 26, FA, 0, 0, 5C

I don't know what the "Vq" thing is. And if I change the first "Serial1.read" to HEX instead of DEC, I get highly garbled output. This is the only way we could get it to look remotely like it's supposed to.

So our problems are the module not reading my output, and me not reading the hex output properly to begin with.

Another code I found made by someone in the Amazon reviews goes like this:

#include <HardwareSerial.h>
HardwareSerial Lidar(1);

void setup() {
Serial.begin(115200);
Lidar.begin(115200, SERIAL_8N1, 17, 16); // replace 17,16 with your RX/TX pins
byte cmd[] = {0x56, 0x71, 0x00, 0x27}; // cmd for getting it to send ascii data
Lidar.write(cmd, sizeof(cmd)); // if using their provided software, comment this line out
}

void loop() {
if (Lidar.available() > 0) { // If anything comes in
Serial.write(Lidar.read()); // read it and send it out
}

Only issue, is that is has more errors.

Arduino: 1.8.16 (Linux), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

sketch_dec02d:2:23: error: no matching function for call to 'HardwareSerial::HardwareSerial(int)'
 HardwareSerial Lidar(1);
                       ^
In file included from /app/Arduino/hardware/arduino/avr/cores/arduino/Arduino.h:233:0,
                 from sketch/sketch_dec02d.ino.cpp:1:
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:117:12: note: candidate: HardwareSerial::HardwareSerial(volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*)
     inline HardwareSerial(
            ^~~~~~~~~~~~~~
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:117:12: note:   candidate expects 6 arguments, 1 provided
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:93:7: note: candidate: constexpr HardwareSerial::HardwareSerial(const HardwareSerial&)
 class HardwareSerial : public Stream
       ^~~~~~~~~~~~~~
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:93:7: note:   no known conversion for argument 1 from 'int' to 'const HardwareSerial&'
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:93:7: note: candidate: constexpr HardwareSerial::HardwareSerial(HardwareSerial&&)
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:93:7: note:   no known conversion for argument 1 from 'int' to 'HardwareSerial&&'
/home/joseph/Arduino/sketch_dec02d/sketch_dec02d.ino: In function 'void setup()':
sketch_dec02d:6:39: error: no matching function for call to 'HardwareSerial::begin(long int, int, int, int)'
 Lidar.begin(115200, SERIAL_8N1, 17, 16); // replace 17,16 with your RX/TX pins
                                       ^
In file included from /app/Arduino/hardware/arduino/avr/cores/arduino/Arduino.h:233:0,
                 from sketch/sketch_dec02d.ino.cpp:1:
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:121:10: note: candidate: void HardwareSerial::begin(long unsigned int)
     void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
          ^~~~~
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:121:10: note:   candidate expects 1 argument, 4 provided
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:122:10: note: candidate: void HardwareSerial::begin(long unsigned int, uint8_t)
     void begin(unsigned long, uint8_t);
          ^~~~~
/app/Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:122:10: note:   candidate expects 2 arguments, 4 provided
exit status 1
no matching function for call to 'HardwareSerial::HardwareSerial(int)'

And I have no idea how to fix this.

@UKHeliBob @Railroader

You are suffering from typical confusion about the meaning of hex, ASCII, etc., which are human readable representations of binary numbers. All communications are in binary, as are all numbers stored in a computer.

To send a user command, you send binary bytes to the device, using Serial.write(). For example, to send the start byte of the four byte command, use

Serial.write(0x56);  //human readable hex representation of the start byte.

To send the user command
"Continuous automatic exposure time measurement"
56 50 00 06

use

Serial.write(0x56);
Serial.write(0x50);
Serial.write(0);
Serial.write(6);  //this is the XOR checksum. Check the data sheet for details

This shortcut, from the code you found somewhere, also works:

byte cmd[] = {0x56, 0x71, 0x00, 0x27}; // cmd for getting it to send ascii data
Lidar.write(cmd, sizeof(cmd)); // if using their provided software, comment this line out

So it looks like that's what I'm already doing, but the module is not switching when I send the command.

I changed the code a bit, and fixed some of the goofyness with reading the output of the module. It turns out I was using Serial.write to display the output of the device, which would be sending the output back to the device. Not good! Now its just printing it.

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200); // replace 17,16 with your RX/TX pins
  //byte SendData[] = {0x56, 0x71, 0x00, 0x27};
  //Serial.write(SendData,sizeof(SendData));
  Serial.write(0x56);
  Serial.write(0x71);
  Serial.write(0);
  Serial.write(27);
}

void loop() {
if (Serial1.available() > 0) { // If anything comes in
Serial.println(Serial1.read()); // read it and send it out
}
}

The monitor now looks like this:

150
0
0
23
137
129
248
7
115
33
38
150
0
0
21
137
129
248
7
112
33
38
150
0
0
22
137
129
248
7
102

Just a long string of characters. I think the "137" is the frame header, but I don't know enough about this to turn it into anything useful. The end goal is to display the distance read by the sensor onto a display. I still need to get the distance value into a float or int or something, and have the display show it.

Sorry, I overlooked the Serial.write statement, but that statement is in fact the problem.

You are sending the command to the serial monitor, not the device. Use Serial1.write instead.

Good catch! I hadn't noticed that.

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200); // replace 17,16 with your RX/TX pins
  //byte SendData[] = {0x56, 0x71, 0x00, 0x27};
  //Serial1.write(SendData,sizeof(SendData));
  Serial1.write(0x56);
  Serial1.write(0x71);
  Serial1.write(0);
  Serial1.write(27);
}

void loop() {
if (Serial1.available() > 0) { // If anything comes in
Serial.println(Serial1.read()); // read it and send it out
}
}

I'm still getting the same issue though, I should be getting lines with tags like "DIST" and then numbers to represent the distance however I'm still seeing the same thing as before.

Maybe some hardware info will help. I have the TX pin on the module connected to the RX pin on the arduino mega. I have the RX pin on the module connected to the TX pin on the mega. The other two wires in use are the ground and 5v. There is a 3rd wire, labeled "TTL" which I have not connected to anything since it was my understanding that TTL is another form of data transfer. The last two wires are marked as unused in the datasheet and are not connected to anything.

What I would do is make sure I understand the default mode correctly.

For example, send the binary command to read the firmware version number and see what comes back. The command for that in hex representation is 56 0e 00 58.

To make the response easier to interpret, print the result in both integer and HEX mode, like this. Note that the module response repeats the command, then sends the requested data.

if (Serial1.available() > 0) { // If anything comes in
int ch = Serial1.read();
Serial.print(ch); 
Serial.print(" ");
Serial.println(ch, HEX);
}
void setup() {
  Serial.begin(115200);
  Serial1.begin(115200); // replace 17,16 with your RX/TX pins
  //byte SendData[] = {0x56, 0x71, 0x00, 0x27};
  //Serial1.write(SendData,sizeof(SendData));
  Serial1.write(0x56);
  Serial1.write(0x0e);
  Serial1.write(0);
  Serial1.write(58);
}

void loop() {
//if (Serial1.available() > 0) { // If anything comes in
//Serial.println(Serial1.read()); // read it and send it out
if (Serial1.available() > 0) { // If anything comes in
int ch = Serial1.read();
Serial.print(ch); 
Serial.print(" ");
Serial.println(ch, HEX);
}
}

Response:

137 89
129 81
176 B0
18 12
22 16

 81
175 AF
18 12
9 9
14 E
47 2F
232 E8
3 3
0 0
118 76
18 12
18 12
14 E
47 2F
232 E8
3 3
0 0
109 6D

and on to infinity, the module keeps sending the live distance data forever

It looks to me like it is working correctly, set in a continuous measurement mode, except it is ignoring your commands.

The bytes 89 and 81 are the start of a distance measurement result, which should consist of 11 bytes total.

What do you get if you send no command at all?

Maybe put a delay(100) after the Serial1.begin(115200), in case the user command is being sent prematurely, before the device is ready to accept it.

Experiment with forcing it into single measurement mode, as the default sample rate is 50 Hz.

Since the Arduino has to do a lot of printing and may have trouble keeping up, maybe it would be better to use:

if (Serial1.available() > 0) { // If anything comes in
Serial.println(Serial1.read(), HEX); // read it and send it out
}

I tried sending the single measurement mode command, but it ignores it.

I bought this same MVR2EB Lidar module. After a lot of effort, I've got the thing working well with an Arduino Nano. I like that this module reads up to 14m where most others like the Tfmini only go to 12m.

Like you, I wasn't able to get the ascii output command to work. All the other commands seem to work fine. Careful changing the baud rate. I got into a weird state where I could no longer get reads. I found that if you disconnect power for a minute or two, the baud rate will revert back to the default of 115200.

Here's a simple sketch to get reads:
Fyi, I've got the UART_TX (white) wire going to pin 2 on my arduino and UART_RX (blue) going to pin 3. Theres a 5v wire and ground connected as well. The other 3 wires are not used.


>#include <SoftwareSerial.h>
SoftwareSerial Serial1(2, 3); 

int distance=0;
int strength =0;
int temperature =0;
int integration =0;
int statusNo =0;

void setup() {
  Serial.begin(115200);   //to PC COM
  Serial1.begin(115200);  //data form sensor
  Serial.println("MVR2EB TOF Distance Sensor");    
}

int rx[11];

void loop() {
  static char i = 0;
  int checksum = 0; 

  if(Serial1.available()) {  
    rx[i] = Serial1.read();
    if(rx[0] != 0x89) //header byte
     {
        i = 0;
      }
    else if(i == 1 && rx[1] != 0x81) //header2 byte
     { 
        i=0;
      }
    else if(i == 10) {
      for(char j = 0; j < 10; j++) {
        checksum ^= rx[j];
      }
      if(rx[10] == (checksum % 256)) {
        distance = rx[2] + rx[3] * 256;
        strength = rx[4] + rx[5] * 256;
        temperature = rx[6];
        integration =rx[7] + rx[8] * 256;
        statusNo =rx[9];
        Serial.print("Millis = ");
        Serial.print(millis());
        Serial.print('\t');
        Serial.print("Distance (mm) = ");
        Serial.print(distance); 
        Serial.print('\t');
        Serial.print("strength = ");
        Serial.print(strength); 
        Serial.print('\t');
        Serial.print("temp = ");
        Serial.print(temperature); 
        Serial.print('\t');
        Serial.print("exp_time = ");
        Serial.print(integration); 
        Serial.print('\t');
        Serial.print("Status = ");
        Serial.print(statusNo);
        Serial.print('\n');
      }
      else {
        Serial.print("CHECK FAILED");   //ignore these.  Also might want to ignore any reads with statusNo > 1 or strength < 50
      }
      
      i = 0;
    } 
    else {
      i++;
      if (i>10) i=0;
    }
  }
}

Good luck!
Evan

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.