AdaptiveSensorFiltering is a ROS 2 package designed to solve a common problem in robotics: noisy sensor data in dynamic environments.
Standard filters (like Kalman filters) often rely on static parameters. This project implements an Online Machine Learning approach using Stochastic Gradient Descent (SGD) to dynamically learn the noise patterns of a sensor in real-time.
Assume a distance measuring sensor which outputs noisy data of distance measured from a wall to the robot as the robot moves away accelerating and decelerating constantly, the goal here is to remove the noise from the measurement to obtain the actual distance measured.
To ensure the robot never "freezes" while training the model, the system utilizes a custom Multithreaded Architecture with ReentrantCallbackGroups and atomic locking, allowing it to process heavy mathematical operations on a background thread while continuing to receive high-frequency sensor data.
- Online Learning: continuously trains an
SGDRegressormodel on incoming data streams, adapting to changes in the environment immediately. - Multithreaded Execution: Uses
MultiThreadedExecutorto separate data collection (high priority) from model training (lower priority/heavy computation). - Thread Safety: Implements strict
threading.Lockprotocols to manage shared data buffers between callbacks and processing threads. - Real-Time Simulation: Includes a generator node that simulates a robot moving with random velocity and noisy sensor readings.
- Framework: ROS 2 Humble
- Language: Python 3.10+
- Machine Learning: Scikit-Learn (
SGDRegressor) - Data Processing: NumPy
- Concurrency: Python
threading, ROS 2 Executors
Acts as the hardware simulation layer.
- Publishes: *
/sensor(Float64): Distance measurements with added random noise./odometry(Int32): The actual control/velocity inputs.
Processes the incomming sensor data to remove noise.
- Subscribes: Listens to both
/sensorand/odometry. - Buffer Logic: Accumulates data in a temporary list.
- Thread Trigger: When the buffer hits 10 items, it atomically locks the data, copies it for processing, and clears the main buffer.
- Background Task: A separate thread trains the ML model on the copied batch and updates the global model weights (
w) and bias (b).
Ensure you have the following installed:
- ROS 2 Humble
- Python 3 dependencies:
pip install scikit-learn numpy-
Create a ROS 2 workspace (if you haven't already):
mkdir -p ~/ros2_ws/src cd ~/ros2_ws/src
-
Clone this repository or create the package:
ros2 pkg create --build-type ament_python random_sensor_handling # Place the python scripts inside the package folder -
Build the package:
cd ~/ros2_ws colcon build --packages-select random_sensor_handling source install/setup.bash
You will need two terminal windows to run this simulation.
Terminal 1: Start the Processor This node listens for data and performs the ML training.
source install/setup.bash
ros2 run random_sensor_handling data_processingTerminal 2: Start the Sensor data generator This node starts publishing noisy data.
source install/setup.bash
ros2 run random_sensor_handling data_genIn the Processor terminal, you should see logs like:
[INFO]: Received data, Distance measured: 12.5
[INFO]: Actual len : 10 Measured len : 10
[WARN]: LOCKED & LOADED. Processing 10 items...
[INFO]: ==== PROCESSED ====
[INFO]: Predicted distance covered : 14.2
- Latency: If the robot moves significantly faster than the model can train (processing time > data arrival rate), the predictions may lag behind the current state.
- Hyperparameters: The learning rate is currently static. An adaptive learning rate would improve convergence in highly variable environments.
- Data Sync: The system assumes a loose temporal correlation between the sensor and odometry messages arriving within the same batch window.