-
Notifications
You must be signed in to change notification settings - Fork 32
High Speed Lidar
A Guide to Using a SICK Lidar at 500kbps With a PCI Card
The SICK LMS-200 and variant series of laser range finders are capable of running at a number of baud rates. These bauds are 9600, 19.2 kilobaud, 38.4 kilobaud, and 500 kilobaud. Since the lidar runs at a 75Hz scanning frequency, any baud rate below the 500 kilobaud rate results in slow updates; the lidar is throwing data away so as to not flood the serial interface. This paper describes my experiences in attempting to use a LMS-291 at 500 kilobaud under Linux, as a component to a Player server.
First off, the 500 kilobaud rate requires RS-422. Most serial ports that come with standard computers are RS-232. The difference is that RS-232 is a single-ended spec, and is susceptible to noise at high speeds and/or long cable lengths. RS-422 is a differential signal spec, which has better noise performance. As far as the host computer is concerned, the UARTs that are used are the same; the difference between RS-422 and RS-232 is in the bus driver chips that are connected to TXD and RXD of the UART chip. Alas, the base baud rate of modern RS-232 ports is 115.2 kilobaud, which isn't fast enough.
To get the 500 kilobaud rate using the Quatech board, a custom crystal will have to be used. The equation for determining the base baud rate, to which a UART divisor is applied, is given by the following equation:
<math>\text{BaseBaud} = \frac{\text{CrystalFreq}}{16}</math>So, to get a 500 kilobaud rate, a base baud of 1 Mbaud can be generated with a 16Mhz crystal, and then a divisor of 2 applied. Other combinations are possible, but this one uses a commonly available crystal.
Your BIOS must support running PCI ROM code; in the Quatech card, the ROM code only serves to enable interrupts from the 16C750 UARTs. If you can run at low-speed by setting irq 0 to setserial , but not when set to the true interrupt, forget about high-speed for the moment. There is something amiss with your system such that either interrupts are not being enabled, or they're not being received. I had a card partially fall out of a PCI card slot that displayed the latter symptom. Other potential pitfalls include PCI bridge chips in the way that aren't truly transparent. This document won't help you solve either of these problems. The Linux Serial HOWTO has some help; your mileage may vary.
Linux needs to know that the base baud rate is 1Mbaud; this is typically set in the kernel code that registers a new UART with the built-in serial driver. The kernel will then correctly set divisors for getting the POSIX baud rates by using the following equation:
<math>\text{Divisor} = \frac{\text{CrystalFreq}}{16*{RequestedBaud}}</math> If the kernel source is unavailable, setserial may be used to set the base baud rate after the fact. Check out the man page; the basic usage is: setserial /dev/ttyS4 baud_base 1000000 Of course, this assumes that you know what your serial device is. Check the output of dmesg for the correct port to which your lidar is attached.Since 500 kilobaud is not a POSIX baud rate, Linux doesn't have a preprogrammed constant for cfsetispeed() and cfsetospeed() . However, all is not lost. There is a provision for setting a custom divisor using the 38400 baud rate and the spd_cust flag. There are a couple of ways of programming for 500 kbaud; the basic requirement is that the software that runs the port will have to be changed.
The procedures described here have been successfully used on a Quatech DSC-200 PCI card. The card had its crystal replaced with a 16Mhz crystal to enable the higher baud rates. The board runs in a 2.6.6 kernel series system, using version 1.20 of Quatech's kernel driver. The only change from the stock driver is a modification to a #define that sets the base baud rate. This #define was altered to reflect the base baud rate of 1 Mbaud. The Quatech driver package provides a SysV init script and works with existing kernel source. For this particular board, the termination resistors of the RS-422 bus are selectable; 100<math>\Omega</math> seems to work just fine. CTS is tied to RTS via jumper, as are DSR to DTR.
There are two fundamentally different approaches to the software that is actually using the port. Which one you use depends on how general-purpose you want your RS-422 ports to be. Option 1 is telling Linux the true base baud value, and then using a custom divisor for the non-POSIX baud rates. Option 2 is lying to Linux, and keeping track of what the true baud rate is without the help of the kernel serial system. Option 1 lets Linux calculate the divisors for the baud rates that POSIX defines, while Option 2 uses the a priori knowledge of divisors for a particular base baud rate and desired baud rate.
The true base baud rate is set as part of the struct serial_struct that is passed into the serial core via register_serial() . User software can then use the POSIX defines for well-known baud rates. To set a custom baud rate, OR the constant ASYNC_SPD_CUST with the flags of a struct serial_struct . Then, set the custom_divisor field to the desired value for the divisor. Save it to the serial driver via a TIOCSSERIAL ioctl() on the file descriptor for the port. To enable the divisor, use a POSIX rate of 38.4 kbaud to cfsetispeed() and cfsetospeed() .
Advantages : The code is very clear about what baud rate the device is truly using. Also, diagnostic and other programs for which source isn't available can be used, albeit not at the higher rate. The kernel code change can be avoided by using setserial with the base_baud flag to set the rate in a system init script instead of kernel code.
Disadvantages : The newer kernels mark the ASYNC_SPD_CUST flag as deprecated, but don't provide an alternative. Thus, this method might fail to work at some point in the future.
The base baud rate is set to a common baud, such as 115.2 kbaud. Then, the standard POSIX baud rates, when requested via cfsetispeed() and cfsetospeed() will calculate a divisor that produces a true wire speed that is the needed baud.
Advantages : Old programs can work at the higher baud rate, since the kernel is lying to them about the true capabilities of the underlying port. If your card is already supported, you can just solder in a new crystal and not have to change the kernel code support for your card.
Disadvantages : Code confusion runs rampant. The baud rate selected by the program is not the true wire speed. Also, to get a POSIX rate on the wire, a custom divisor would have to be used anyway.
If you had the protocol part figured out for 9600 baud, you also have it done for 500 kbaud. There is a message that SICK defines for shifting baud rates, it's in the manual. Keep in mind that the lidar responds with an ACK on the old baud rate, and then shifts speed. The user software must do the same. Also, when disconnecting from the lidar, don't forget to shift down the speed for the next program to connect to the lidar at a standard rate.
You should now be able to request streaming data and have the scans come at a very fast rate - the lidar is not paring any of its data down before sending down the wire.
Hopefully, you can run your lidar at 500k now!
Getting the lidar started is somewhat problematic. There is an initialization sequence that is used in the Player project that motivated this paper. However, the lidar occasionally times out when requesting a configuration or setting device parameters. The cause of this timeout has yet to be determined, or for effective work-arounds. The "best" workaround found thus far is to use a small program to pre-initialize the lidar, so that when a program that absolutely must use the lidar is started, it will already be hot and producing data.
Unfortunately, I no longer have access to any of the hardware referenced. I wanted to contribute this for a while, and just now am getting around to it.
Steve McGuire, [email protected]
SICK GmBH Telegram Listing