The Sensor Ring library includes both C++ examples and Python examples that show how to use it in custom projects.
⚠️ Interface: All examples register both a SocketCAN and an USBtingo interface by default. The SensorRingFactory auto-discovery will use whichever interface is available on your system. Depending on your setup, you may need to adjust the interface names (e.g. the SocketCAN device name or the USBtingo device index) in the respective example source file. Note that SocketCAN is only available on Linux.
1. C++ Examples 
The library is written in C++ and it is recommended to use the C++ interface of the library for performance reasons.
The following examples show how to use the Sensor Ring library in your own C++ project:
Measurement Rate Examples
The first two examples are functionally identical — they all use the SensorRingFactory for auto-discovery and display the current ToF and thermal measurement rate on the command line. They differ only in the programming pattern used to receive measurements:
- Using Lambdas (function-based): Subscribes to device groups and state changes using lambda callbacks directly on the MeasurementManager
- Using Proxy Class (object-oriented): Wraps the subscription logic in a custom proxy class that binds its member functions as callbacks via std::bind
Visualization and Action Examples
- Depth Map Example: Prints a colored 8×8 depth map of the first connected ToF sensor on the command line
- Thermal Map Example: Prints a 32×32 false-color thermal image from the first connected HTPA32 sensor on the command line
- Extra Action Example: Demonstrates how to use enqueueExtraAction() to control WS2812b LEDs with a smooth color cycling animation
⚠️ To use the depth_map or thermal_map C++ examples on Windows you might first need to enable UTF-8 support for your current terminal session with this command:
$OutputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding.
2. Python Examples 
ℹ️ The library can be built with -DSENSORRING_BUILD_PYTHON_BINDINGS=ON option to generate python bindings.
⚠️ To use the sensorring python package you have to append the location of the package to your PYTHONPATH environment variable.
⚠️ It is strongly recommended to copy measurements to NumPy arrays before manipulating them in Python. This is shown in the depth_map_matplotlib example using point_cloud.copyTo().
Linux
export PYTHONPATH=$PYTHONPATH:/usr/local/lib/python3/dist-packages
Windows
$env:PYTHONPATH = "${env:PYTHONPATH};C:\Program Files\EduArt Robotik GmbH\Sensor Ring\bindings\python3"
$env:EDU_SENSORRING_DIR = "C:\Program Files\EduArt Robotik GmbH\Sensor Ring\"
Alternatively you can use the Windows
Edit the System Environment Variables tool to add the python package location to the environment variable
PYTHONPATH.
The following examples show how to use the Sensor Ring library in your own Python project.
Measurement Rate Examples
The first two examples are functionally identical — they all use the SensorRingFactory for auto-discovery and display the current ToF and thermal measurement rate on the command line. They differ only in the programming pattern used to receive measurements:
- Using Lambdas (function-based): Subscribes to device groups and state changes using Python callbacks directly on the MeasurementManager
- Using Proxy Class (object-oriented): Wraps the subscription logic in a custom proxy class that binds its member methods as callbacks
Depth Map Examples
Thermal Map Examples
Action Examples
- Extra Action Example: Demonstrates how to use enqueueExtraAction() to control WS2812b LEDs with a smooth color cycling animation

The depth_map_terminal example | 
The depth_map_matplotlib example. |
Below is a minimal example that shows how to set up the SensorRing and receive measurements in Python using the function-based subscription API:
import time
import eduart.sensorring as sensorring
def main():
params = sensorring.ManagerParams()
interface = sensorring.ComInterfaceID()
interface.type = sensorring.InterfaceType_UsbTingo
interface.name = "0"
try:
log_sub = sensorring.Logger.getInstance().subscribe(
lambda verbosity, msg:
print(f"[{sensorring.LogVerbosityToString(verbosity)}] {msg}")
if verbosity > sensorring.LogVerbosity_Debug else None
)
factory = sensorring.SensorRingFactory()
factory.addInterface(interface)
sensor_ring = factory.build(sensorring.ValidationMode_Relaxed)
if sensor_ring is None:
print("Failed to create SensorRing. Exiting.")
return
manager = sensorring.MeasurementManager(params, sensor_ring)
state_sub = manager.subscribeToStateChanges(
lambda state: print(f"[State] State changed to: {sensorring.ManagerStateToString(state)}")
)
tof_sub = manager.subscribeToDeviceGroup(
sensorring.DeviceType_VL53L8CX,
lambda group: None
)
thermal_sub = manager.subscribeToDeviceGroup(
sensorring.DeviceType_HTPA32,
lambda group: None
)
manager.startMeasuring()
while manager.isMeasuring():
time.sleep(1)
state_sub.cancel()
tof_sub.cancel()
thermal_sub.cancel()
log_sub.cancel()
manager.stopMeasuring()
except Exception as e:
print(f"Caught: {e}")
if __name__ == "__main__":
main()
3. Logger Subscription
All examples subscribe to the Logger before creating the SensorRingFactory or any other library object. This is intentional: the factory and the manager emit log messages during construction, enumeration and initialization. A logger subscription that is set up after these objects are created will miss those early messages.
Because the subscription must exist before any class instance it could be embedded in, a simple lambda (C++) or function (Python) is the best choice. A class-based approach (binding a member function) would require the logger-owning object to be fully constructed first, making it impossible to capture the very first messages.
auto log_sub = logger::Logger::getInstance()->subscribe(
[](const logger::LogVerbosity verbosity, const std::string& msg) {
if (verbosity > logger::LogVerbosity::Debug)
std::cout << "[" << verbosity << "] " << msg << std::endl;
});
log_sub = sensorring.Logger.getInstance().subscribe(
lambda verbosity, msg:
print(f"[{sensorring.LogVerbosityToString(verbosity)}] {msg}")
if verbosity > sensorring.LogVerbosity_Debug else None
)