XV-11 lidar

idle

Scan

Event log

Link check

Live

Packet index coverage (90 per revolution)

arrived arrived twice missing

Rotation speed

Red line is 349 rpm, where 115200 baud can no longer carry a whole revolution.

Signal strength against range

Healthy returns fall away with distance. A flat smear near zero is a dirty or blocked window.

Last packet

waiting

Connecting the lidar

This browser cannot open serial ports. The Web Serial API needs desktop Chrome, Edge or Opera, in a secure context. If you opened this file directly and it is refused, serve it instead: python3 -m http.server 8000 in the tools/ directory, then open http://localhost:8000/xv11_lidar.html. Demo and file replay work in any browser.

The XV-11 puck has two separate connectors, and they do different jobs. The four-pin one carries logic power and data. The two-pin one is only the motor, and nothing on the data connector will make it turn.

Four-pin: power and data

WireSignalGoes toNotes
Red+5 Vadapter 5V / VBUS Logic draws about 45 mA idle, 135 mA turning
BrownLDS_RXleave unconnected The sensor accepts no commands. There is nothing to send it
OrangeLDS_TXadapter RX 3.3 V logic. A 5 V adapter reads it fine; this is the only wire that carries data
BlackGNDadapter GND Required, and shared with the motor supply

Wire colours vary between revisions of the module. Confirm against your own unit before applying power rather than trusting the table.

Two-pin: the motor

About 3 V, drawing roughly 60 to 100 mA once turning. There is no closed-loop control and no start command, so speed follows the voltage you apply. Aim for 290 to 310 rpm, which this page reads out live, and use that reading to set the voltage.

Do not run the motor from the adapter's 3V3 pin. On an FTDI FT232RL that pin is rated 50 mA; a CP2102's regulator gives about 100 mA in total including what the chip itself uses. The motor wants 60 to 100 mA, so it sits at or over the limit. It may well spin, but the rail sags, the adapter's regulator runs hot, and the speed wanders. Give the motor its own supply, sharing only ground.

Serial settings

115200 8N1, no flow control, receive only. On macOS use the cu. device rather than tty., which blocks on open waiting for carrier detect and looks exactly like a dead sensor.

One program at a time. A serial port opens exclusively, so close the Python tool before connecting here, and this page before running it.

What a healthy link looks like

ReadingGoodMeaning
Checksum100%The only figure that cannot be faked by noise
Speed290-310 rpmSet by motor voltage; nothing regulates it
Packets per revolution90Fewer means loss, more means the sensor is repeating indices
Byte rate~9900 B/s86% of the line at 300 rpm
Usable readingsvariesAn angle with nothing inside ~6 m returns nothing. Open space is not a fault
There is a hard speed ceiling of 349 rpm, and it is arithmetic, not a setting. A revolution is 90 packets of 22 bytes, so 1980 bytes; 115200 8N1 carries 11520 bytes per second. Past 349 rpm the sensor cannot transmit a whole revolution and starts dropping packets. Driving the motor harder makes the scan worse, not faster.

When it does not work

SymptomMost likely cause
No port offered in the chooserAdapter driver missing, or the browser is not Chrome/Edge/Opera
Port opens, zero bytesMotor not turning, TX not connected, or TX and RX swapped. The sensor sends nothing while stationary
Bytes arrive, no frames foundWrong baud rate. Try the others in the menu
Frames found, checksums failingNoise, a marginal ground, or a baud rate close to but not the right one
Valid data, few usable readingsNormal aimed at open space. Check the strength-against-range chart before suspecting the sensor
Speed jumping to 4/3 or 4/5 of the true valueThe sensor miscounting its own rotation, not the motor changing speed. Suspect the motor supply first
Packet format, if you are reading the raw hex

22 bytes, 90 per revolution, four readings each, so 360 readings of one degree.

FA <index> <speed_L> <speed_H> [4 readings x 4 bytes] <crc_L> <crc_H>

FieldEncoding
index0xA0 to 0xF9. Angle of the first reading is (index - 0xA0) x 4
speed16-bit little endian, RPM x 64
reading byte 0distance bits 7:0
reading byte 1bit 7 no-return, bit 6 strength warning, bits 5:0 distance 13:8
reading bytes 2-3signal strength, 16-bit little endian
crcTen 16-bit LE words shifted and added, folded into 15 bits
The distance mask is 0x3F, not 0x1F. Widely copied tutorial code masks 0x1F, which keeps only 13 bits, so anything past 8191 mm wraps: 9000 mm reads back as 808 mm, which looks like an obstacle right in front of you rather than like an error. It survives because it only bites past the XV-11's useful range.