So today my Neat XV LIDAR module arrived, and I had to test it directly with the Raspberry Pi. For everyone that does not know this wonderful piece of hardware yet: It is a low-cost 360-degree spinning laserscanner that is usually scavenged from the Neato XV vacuum-robots. In Germany it is quite hard to get your hands on one, so I ordered one via ebay from the US.
According to https://xv11hacking.wikispaces.com/LIDAR+Sensor, the wires of the LIDAR-unit have the following pinout:
Although the logic-unit is supplied with 5V, the interface (rx/tx) is 3.3v. Perfect for talking to a raspberry pi!
As stated in the wiki, the sensor (without the motor!) draws ~45mA in idle and ~135mA when in use (rotating).
For these first tests, I wired it up by connection the power-lines of the logic to an external 5v power supply (that can definitely provide the needed mA), the TX of the scanner directly to the RX of the raspberry pi, connected the GNDs. Without connecting the motor yet and just powering the logic-unit on while connected to the serial (115200 baud, 8N1), it would greet me with the following welcome-message:
Piccolo Laser Distance Scanner Copyright (c) 2009-2011 Neato Robotics, Inc. All Rights Reserved Loader V2.5.15295 CPU F2802x/c001 Serial KSH14415AA-0358429 LastCal [5371726C] Runtime V2.6.15295 #Spin...3 ESCs or BREAK to abort
After that I hooked up the motor to an external power-supply with approx. 3V. After spinning it up to 300rpm and got my first measurement-packets, which sadly did not look very promising:
fa:a6:f0:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:4e:20: fa:a7:e9:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:52:19: fa:a8:e9:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:56:19: fa:a9:e9:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:5a:19: fa:aa:e9:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:5e:19: fa:ab:e9:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:62:19: fa:ac:e9:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:66:19: fa:ad:e2:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:6a:12: fa:ae:e2:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:6e:12: fa:af:e2:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:72:12: fa:b0:e2:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:76:12: fa:b1:e2:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:7a:12: fa:b2:e2:4a:55:80:00:00:55:80:00:00:55:80:00:00:55:80:00:00:7e:12:
The packet-format (https://xv11hacking.wikispaces.com/LIDAR+Sensor) is the following:
22 Bytes: <start> <index> <speed_L> <speed_H> [Data 0] [Data 1] [Data 2] [Data 3] <checksum_L> <checksum_H>
- start is always 0xFA
- index is the index byte in the 90 packets, going from 0xA0 (packet 0, readings 0 to 3) to 0xF9 (packet 89, readings 356 to 359).
- speed is a two-byte information, little-endian. It represents the speed, in 64th of RPM (aka value in RPM represented in fixed point, with 6 bits used for the decimal part).
- [Data 0] to [Data 3] are the 4 readings. Each one is 4 bytes long, and organized as follows :
`byte 0 : <distance 7:0>`
`byte 1 : <„invalid data“ flag> <„strength warning“ flag> <distance 13:8>`
`byte 2 : <signal strength 7:0>`
`byte 3 : <signal strength 15:8>`
I wrote up a little python script to decode the packets in real-time for me:
#!/usr/bin/python import serial import time import math # Some settings and variables outfile = open("outfile.txt", "w+") print("Start") f = serial.Serial(port='/dev/ttyAMA0', baudrate=115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=0) def decode_string(string): print string data =  for byte in string.strip("\n").split(":")[:21]: data.append(int(byte,16)) start = data idx = data - 0xa0 speed = float(data | (data &amp;amp;lt;&amp;amp;lt; 8)) / 64.0 in_checksum = data[-2] + (data[-1] &amp;amp;lt;&amp;amp;lt; 8) # first data package (4 bytes after header) angle = idx*4 + 0 angle_rad = angle * math.pi / 180. dist_mm = data | ((data &amp;amp;amp; 0x1f) &amp;amp;lt;&amp;amp;lt; 8) quality = data | (data &amp;amp;lt;&amp;amp;lt; 8) if data &amp;amp;amp; 0x80: print "X - ", else: print "O - ", if data &amp;amp;amp; 0x40: print "NOT GOOD" print "Speed: ", speed, ", angle: ", angle, ", dist: ",dist_mm, ", quality: ", quality #print "Checksum: ", checksum(data), ", from packet: ", in_checksum outfile.write(string+"\n") print "-----------" byte = f.read(1) started = False string = "Start" while True: if byte != '': enc = (byte.encode('hex') + ":") if enc == "fa:": if started: try: decode_string(string) except Exception, e: print e started = True string = "fa:" elif started: string += enc else: print "Waiting for start" byte = f.read(1) outfile.close() print("End")
Until now I did not have any luck. One thing I noticed was that during the spin-up of the motor to full speed, it would give me valid readings for approximately half a second (without the bad-flag). However, even if I adjusted the rpm to exactly these values, it would still output only bad packets. Additionaly, the rotational speed at which those few good packets came through always changed, so my current guess is that either the laser- oder imager-unit is faulty, or that their connection through the slip-ring is somehow bad.
I contacted the seller and he agreed to send another unit, so lets wait.