LIDAR scanners are awesome devices and I’ve been fascinated by the broad application possibilities for a long time. When I finally got my hands on two devices this year I was quickly disappointed with how little software was available, even for the simplest things. Narrowing down the search to C#/.NET SDKs lead to: zero, zilch, zip, nada 🙁
A few hours, lots of coffee and a few datasheets later; voilà LidaRx was born!
You noticed that Rx suffix in the name? Then, hello, fellow Reactive Extensions aficionado! For everybody else, here’s an ultra short intro to the Rx core concept:
Using Reactive Extensions is programming with (asynchronous) data streams. These data streams can be created from out of anything (variables, events, user inputs, properties, you name it…). You can listen to streams and react accordingly.
Basically, a stream is a sequence of ongoing events ordered in time. It can emit three different things: a value (of some type), an error, or a “completed” signal. On top of that, you are given an amazing toolbox of functions to combine, aggregate, create and filter any of those streams.
In the .NET world the Reactive Extensions are built around so-called Observable Collections and LINQ (plus Schedulers for that matter, but that’s way off topic here) giving the developer a super handy toolbox for anything that’s remotely related to stream based data processing!
These are a few of my bookmarks about Rx.NET:
- Muhammad Rehan Saeed’s Rx blog posts
- Rx.NET on MSDN
- 101 Rx.NET samples
- Intro to Rx (messy but in depth – don’t start with this)
So; now we all know about Rx, let’s talk about that LIDAR part. Technically LIDAR scanners use a light pulse time-of-flight (ToF) module to measure the distance between the sensor and the point in space the sensor’s pointing at. That, combined with the angular information of the scanner’s head, gives you polar coordinates. Well… you get a stream of polar coordinates, and that’s the point at which using Rx makes perfect sense!
By the way here’s a capture of my workplace, just as an example:
LidaRx is essentially divides into two parts; the core library and device drivers.
The core library provides a set of nice and easy helpers that allow you to write high-level applications. The scanner objects (e.g. one LIDAR scanner) all have their own position and orientation in 3D space. The processed polar coordinates are automatically transformed to LidaRx’s “world” (Cartesian) coordinate system. This eases sensor fusion dramatically and helps developers – like me – who really struggle to keep track of a multiple sensor centric polar coordinate systems.
Anyhow – in addition to those nifty coordinate system tricks, the core library contains filters (e.g.: only points in a certain azimuth range of the scanner) and buffering operators (e.g.: group all the points of a scanner revolution into one batch) for the data streams.
Here’s a fairly self-explanatory example:
One very nice aspect of LidaRx is that it enables application developers to abstract the hardware, in the way that the business-logic of the application is totally device independent. As long as you program against
ILidarScanner you can keep most of your application scanner vendor independent (sure, there’ll be some vendor specific bootstrapping and configuration of the sensor, but that shouldn’t account for much of your code).
In the current release, there’s support for two device types, but I hope to be able to add more to that list in the future:
- Scanse.io’s SWEEP (as a financially accessible “toy” scanner)
- Pepperl+Fuchs OMDxxx R2000 series scanners
How can I start?
Just head over to the project’s Github or lidarx.io for examples and code (Nuget packages are there too). I hope to add a few more fancy things (3d geometry matching, motion detection, static world background filtering, etc…) to the library soon.
Oh, I nearly forgot to mention one important detail; all that goodness is released as Open Source under the LGPL v3.0 license. If that is an issue for your application, please get in touch with me for a custom licensing agreement.