C# / .NET Reactive Extensions (Rx) for LIDAR scanners
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
.gitignore
CNAME
LICENSE
README.md
_config.yml
appveyor.yml

README.md

LidaRx

Build status NuGet NuGet

A lightweight but powerful Lidar scanner driver and data processing library for .NET providing support for multiple Lidar scanners and an intuitive way to process samples received by the scanner.

Features

  • Unified data processing with all the power of Rx.NET at your fingertip
  • 3D coordinates
    • Configurable sensor position and orientation
    • Sensor position and orientation updatable at runtime
  • Vendor agnostic sensor fusion (join data streams from multiple scanners)
  • Comprehensive API an helpers: LidaRx readme
    • Unified base API for scanners: connect/disconnect, start/stop scanning and simple status information
    • Polar coordinates filters
      • PointsInAzimuthRange
      • PointsInDistanceRange
      • RadiusRangeMinDistance
      • RadiusRangeMaxDistance
    • Cartesian coordinates filters
      • PointsInBox
    • Grouping/Transforming operators
      • BufferByScan
  • Fully async
  • Cross platform support:
    • .NET Standard 1.5 / .NET Core 1.0
    • .NET Standard 2.0 / .NET Core 2.0
    • .NET 4.6+

Supported devices

These device are officially supported by LidaRx:

  • Scanse.io SWEEP Readme
  • Pepperl+Fuchs OMDxxx-R2000 device family (HD and UHD) Readme

Show me some code!

Here's a simple example using a Scanse.io Sweep sensor.

Basically the program connects to the Sweep on Com1, set the motor speed to 10Hz and the sample rate to 1kHz

using (var sweep = new SweepScanner("COM1"))
{
    await sweep.ConnectAsync();
    await sweep.SetMotorSpeedAsync(SweepMotorSpeed.Speed10Hz);
    await sweep.SetSampleRateAsync(SweepSampleRate.SampleRate1000);

	await sweep.StartScanAsync();

...then the program registers for LidarStatusEvent with the LidarStatusLevel.Error and logs the messages to the console.

	// log errors to the console
	sweep.OnlyStatusEvents(LidarStatusLevel.Error).Subscribe(ev =>
	{
		Console.WriteLine($"Error: {ev.Message}");
	});

Next, the program takes the LIDAR point stream and filters away all the points that are outside of the distance range 40cm to 100cm (imagine two concentric circles around the scanner; only points between them propagate in the resulting Observable<LidarPoint> stream)

    // using the data stream for multiple subscriptions
    var pointsBetween400and1000mm = sweep
		.OnlyLidarPoints()					// filter away all those status messages
        .Where(pt => pt.Distance > 400)		// unit is mm
		.Where(pt => pt.Distance <= 1000);	// unit is mm

Finally we use the restrained stream as source for a Rx Buffer() which collects all the points into consecutive "1 second long" buffers. In the second part the program uses the pointsBetween400and1000mm stream and restricts it further to points in the azimuth range of -45 to +45 degree.

    // buffer in 1second long samples
    pointsBetween400and1000mm
        .Buffer(TimeSpan.FromSeconds(1000))
        .Subscribe(buffer =>
        {
            Console.WriteLine($"{buffer.Count} points in [400;1000]mm range per second");
        });

    // this narrows down the point stream to points in the -45 to +45 degree range
    pointsBetween400and1000mm
        .PointsInAzimuthRange(-45, 45)
        .Subscribe(pt =>
        {
            // write the points to disk?!
        });

This part uses the full stream of LidarPoint from the scanner but instead of buffering on a time basis as in the code above it buffers by scan (basically per scanner head revolution).

    // buffer the lidar points in scans
    sweep.OnlyLidarPoints()
        .BufferByScan()
        .Subscribe(scan =>
        {
            Console.WriteLine($"Got {scan.Count} points for scan {scan.Scan}");
            Console.WriteLine($"Most distant point: {scan.Points.Max(pt => pt.Distance)}mm");
            Console.WriteLine($"Closest point: {scan.Points.Min(pt => pt.Distance)}mm");
        });

	
	Console.ReadLine();      // wait here 'till user hits the enter key
	sweep.StopScan();
}

Roadmap

  • Usable implementation of 3D collision test (think of PointsIn3DModel(string pathToStlFile) )
  • Points to object matching
  • Point and motion tracking

License

lidaRx is dual licensed. Unless you've made a separate licence agreement with Staudt Engineering (for example because you can't stand the LGPL / use contact form on http://www.staudt-engineering.com) you can use lidaRx under the GNU Lesser General Public License v3.0. The full licence text is available in this repository: LICENSE

Support & Contribution

Commercial support and device driver development service is available, support for open source usage is limited on a "free time available" basis, but please feel free to open issues or pull requests if you can think of something that would make this library more awesome :)