pyrplidarsdk 0.1.2
Python wrapper for RPLIDAR SDK using nanobind
License: MIT
Requires Python: >=3.10

# PyRPLIDARSDK

A high-performance Python wrapper for the [Slamtec RPLIDAR SDK](https://github.com/Slamtec/rplidar_sdk) using [nanobind](https://github.com/wjakob/nanobind).

PyRPLIDARSDK provides a fast, memory-efficient Python interface to RPLIDAR series 2D laser range scanners, supporting both serial and UDP connections with comprehensive data processing utilities.

## Installation

### Prerequisites

- Python 3.10 or higher
- NumPy
- C++ compiler with C++17 support (for building from source)

### From PyPI

```bash
pip install pyrplidarsdk
```

### From Source

```bash
# Clone the repository with submodules
git clone --recursive https://github.com/dexmate-ai/pyrplidarsdk.git
cd pyrplidarsdk

# Install in development mode
pip install -e .

# Or build and install
pip install .
```

## Quick Start

### Serial Connection

```python
import pyrplidarsdk
import time

# Create driver instance for serial connection
driver = pyrplidarsdk.RplidarDriver(port="/dev/ttyUSB0")

# Connect to the device
if not driver.connect():
    print("Failed to connect!")
    exit(1)

# Get device information
info = driver.get_device_info()
if info:
    print(f"Connected to RPLIDAR model {info.model}")
    print(f"Firmware: {info.firmware_version}")
    print(f"Hardware: {info.hardware_version}")
    print(f"Serial: {info.serial_number}")

# Check device health
health = driver.get_health()
if health:
    print(f"Device health: {health.status}")

# Start scanning
if driver.start_scan():
    print("Scanning started...")
    
    try:
        for i in range(10):  # Get 10 scans
            scan_data = driver.get_scan_data()
            if scan_data:
                angles, ranges, qualities = scan_data
                print(f"Scan {i+1}: {len(angles)} points")
            time.sleep(0.1)
    finally:
        driver.stop_scan()
        driver.disconnect()
```

### UDP Connection

```python
import pyrplidarsdk

# Create driver instance for UDP connection
driver = pyrplidarsdk.RplidarDriver(ip_address="192.168.1.100")

# Rest of the code is the same...
```

## API Reference

### RplidarDriver

Main class for controlling RPLIDAR devices.

#### Constructor

```python
RplidarDriver(port=None, ip_address=None, baudrate=1000000, udp_port=8089)
```

- `port` (str, optional): Serial port path (e.g., "/dev/ttyUSB0", "COM3")
- `ip_address` (str, optional): IP address for UDP connection
- `baudrate` (int): Serial baudrate (default: 1000000)
- `udp_port` (int): UDP port (default: 8089)

#### Methods

- `connect() -> bool`: Connect to the device
- `disconnect()`: Disconnect from the device
- `get_device_info() -> DeviceInfo | None`: Get device information
- `get_health() -> DeviceHealth | None`: Get device health status
- `start_scan() -> bool`: Start laser scanning
- `stop_scan()`: Stop laser scanning  
- `get_scan_data() -> tuple[list[float], list[float], list[int]] | None`: Get scan data

### DeviceInfo

Device information structure.

- `model` (int): Device model number
- `firmware_version` (int): Firmware version
- `hardware_version` (int): Hardware version  
- `serial_number` (str): Device serial number (hex string)

### DeviceHealth

Device health information.

- `status` (int): Health status code
- `error_code` (int): Error code if any

## Utility Functions

The package includes comprehensive utility functions in `pyrplidarsdk.utils` for high-performance data processing:

### Data Conversion & Processing

```python
from pyrplidarsdk.utils import (
    polar_to_cartesian,
    cartesian_to_polar,
    angles_to_degrees,
    angles_to_radians,
    to_numpy_arrays,
    smooth_ranges,
    downsample_scan
)

# Convert between coordinate systems
x_coords, y_coords = polar_to_cartesian(angles, ranges)
angles_polar, ranges_polar = cartesian_to_polar(x_coords, y_coords)

# Convert angle units
angles_deg = angles_to_degrees(angles)
angles_rad = angles_to_radians(angles_deg)

# Convert to NumPy arrays for efficient processing
angles_np, ranges_np, qualities_np = to_numpy_arrays(angles, ranges, qualities)

# Smooth noisy range data
smoothed_ranges = smooth_ranges(ranges, window_size=5)

# Downsample for reduced data size
downsampled = downsample_scan(angles, ranges, qualities, factor=2)
```

### Filtering & Quality Control

```python
from pyrplidarsdk.utils import (
    filter_by_range,
    filter_by_quality,
    filter_by_angle
)

# Filter by distance range
filtered = filter_by_range(angles, ranges, qualities, min_range=0.1, max_range=12.0)

# Filter by quality threshold
high_quality = filter_by_quality(angles, ranges, qualities, min_quality=50)

# Filter by angular sector
sector_data = filter_by_angle(angles, ranges, qualities, min_angle=0, max_angle=180)
```

### Analysis & Detection

```python
from pyrplidarsdk.utils import (
    compute_scan_statistics,
    detect_obstacles,
    find_closest_point,
    find_farthest_point
)

# Compute comprehensive statistics
stats = compute_scan_statistics(angles, ranges, qualities)
print(f"Mean range: {stats['mean_range']:.2f}m")
print(f"Valid points: {stats['valid_points']}")

# Detect obstacles within specified parameters
obstacles = detect_obstacles(
    angles, ranges, qualities,
    min_distance=0.2,
    max_distance=2.0,
    min_angle=-45,
    max_angle=45,
    min_quality=30
)

# Find closest and farthest points
closest = find_closest_point(angles, ranges, qualities)
farthest = find_farthest_point(angles, ranges, qualities)
```

## Examples

The `examples/` directory contains comprehensive demonstrations:

- **`simple_scan.py`**: Advanced scanning with data analysis, quality filtering, and obstacle detection
- **`realtime_plot.py`**: Real-time visualization of LIDAR data with matplotlib

Run examples with:

```bash
# Basic scanning
python examples/simple_scan.py --port /dev/ttyUSB0

# With analysis and obstacle detection
python examples/simple_scan.py --port /dev/ttyUSB0 --analysis --detect-obstacles

# UDP connection with custom parameters
python examples/simple_scan.py --ip 192.168.1.100 --min-quality 50 --max-range 10.0
```

## Project Structure

```
pyrplidarsdk/
├── pyrplidarsdk/          # Python package
│   ├── __init__.py        # Package initialization and exports
│   └── utils.py           # Vectorized NumPy utilities for data processing
├── src/                   # C++ source files
│   └── rplidar_wrapper.cpp # nanobind wrapper for RPLIDAR SDK
├── rplidar_sdk/           # RPLIDAR SDK submodule
├── examples/              # Example scripts
│   ├── simple_scan.py     # Advanced scanning example
│   └── realtime_plot.py   # Real-time visualization
└── CMakeLists.txt         # Build configuration
```

## Performance Features

- **nanobind Integration**: Minimal overhead Python-C++ bindings
- **Vectorized Operations**: NumPy-based utilities for efficient batch processing
- **Zero-Copy Data Transfer**: Direct memory sharing between C++ and Python where possible
- **Optimized Data Structures**: Efficient handling of large scan datasets
- **Multi-platform Support**: Linux (x86_64, aarch64) with planned Windows/macOS support

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Support

- **GitHub Issues**: [Report bugs or request features](https://github.com/dexmate-ai/pyrplidarsdk/issues)
- **Documentation**: [GitHub Repository](https://github.com/dexmate-ai/pyrplidarsdk)
- **Email**: contact@dexmate.ai

## Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

## Acknowledgments

- [Slamtec](https://www.slamtec.com/) for the comprehensive RPLIDAR SDK
- [nanobind](https://github.com/wjakob/nanobind) for the excellent Python-C++ binding framework
- The open-source robotics community for continuous feedback and support