June 22, 2026
How to Deploy a Spiking Neural Network on a ROS2 Robot
No spiking-neuron math, no hand-rolled ROS2 message wiring. Camera in, spikes out, one launch file.
Search "ROS2 spiking neural network" and you mostly find research papers: a TurtleBot running an RL policy on Loihi, an SNN navigating a Gazebo maze, a biomimetic robotic head built on ROS1 and Python 2. What you don't find is a package you can install and run today. NeuroCUDA's ROS2 integration - neurocuda_ros2 and neurocuda_msgs - is built to close that specific gap: a normal ROS2 package, wrapping an already-verified ANN-to-SNN compiler, distributed via pip and a launch file.
This walkthrough covers the architecture, the three nodes, the message types, and the fastest path to running it - Docker - plus an honest account of what's tested and what isn't yet.
The problem this solves
General-purpose ANN-to-SNN tools - SpikingJelly, snnTorch, NengoDL - are PyTorch libraries with no robotics integration. The robotics-side spiking neural network work that does exist is either ROS1 (predates the current ROS2 standard) or a research demo tied to one robot and one paper. If you wanted to put a spiking network on a robot's camera feed before this, you had two options: learn spiking-neuron simulation from first principles, or fork someone's research code and rewire it to your own sensors. Neither is a repeatable workflow.
neurocuda_ros2 is a thin ROS2 wrapper around NeuroCUDA's existing compiler. The hard part - converting a trained PyTorch model into a spiking network without losing accuracy - is already solved and documented on the NeuroCUDA compiler page. The ROS2 package just gives that compiled model a standard interface: topics in, topics out.
Three nodes, three jobs
The package ships three ROS2 nodes, each with a single responsibility:
| Node | Input | Output | Job |
|---|---|---|---|
| snn_inference_node | Camera images or DVS events | Class predictions, spike stats | Perception |
| snn_control_node | Robot state, odometry | Velocity commands, Q-values | Action / policy |
| spike_viz | Spike events | Real-time spike raster | Debugging |
Perception and control are deliberately separate nodes. A camera-facing SNN classifier and a state-facing SNN control policy are different models with different inputs - keeping them as separate ROS2 nodes means you can swap or restart either independently, which matters once you're debugging a real robot instead of a simulation.
Custom messages, not raw strings
Robotics SNN demos often just publish a JSON string and call it integration. NeuroCUDA ROS2 defines three typed messages in neurocuda_msgs instead:
- SnnDetection - class_id, class_name, confidence, top_k_labels, top_k_scores, sparsity, total_spikes, total_neurons
- SnnSpikeEvent - layer_name, neuron_type, spike_count, total_neurons, sparsity
- SnnStatus - model_name, task, architecture, accuracy, total_params, neuron_count, device, avg_sparsity, inference_time_ms
Typed messages mean other nodes in your ROS2 graph can subscribe to /snn/detections and immediately know the schema, instead of parsing a string field by field.
Quick start: three commands
pip install neurocuda ros2 launch neurocuda_ros2 infer.launch.py model:=vgg5_cifar10 device:=cuda
That's the entire setup. The launch file starts snn_inference_node, subscribes to your configured camera topic, loads vgg5_cifar10 from the NeuroCUDA HuggingFace hub (94.6% accuracy, the best CIFAR-10 SNN currently shipped), and starts publishing detections, sparsity, and status. No model file to download manually, no spiking-neuron parameters to tune by hand.
Six pre-trained models to start from
| Model | Task | Accuracy |
|---|---|---|
| MLP | MNIST digit recognition | 97.4% |
| CNN | NMNIST event classification | 99.88% |
| StrongCNN | CIFAR-10 classification | 74.3% |
| ResNet-18 | CIFAR-10 (convert + fine-tune) | 70.1% |
| SEW-ResNet | CIFAR-10 (direct SNN training) | 67.7% |
| VGG-5 SNN | CIFAR-10 | 94.6% |
All six load with neurocuda.hub.load("model-name"), which is also what the ROS2 launch file calls under the hood when you pass a model:= argument.
The fastest path: Docker
Building ROS2 Jazzy and CUDA from scratch on robot-grade hardware is its own afternoon. The Docker image skips that:
docker pull kvarma/neurocuda-ros2:latest docker run --gpus all kvarma/neurocuda-ros2:latest
The image bundles Ubuntu 24.04, CUDA 12.9, ROS2 Jazzy Jalisco, PyTorch with CUDA, and NeuroCUDA built from source with every HuggingFace-hosted model already available - about 26 GB total. It sources the workspace automatically and is ready for ros2 launch neurocuda_ros2 infer.launch.py as soon as the container starts.
Choosing a backend
The same compiled model runs on four backends through one function call - the launch file just exposes this as an argument:
neurocuda.deploy(model, "snn_cifar10", target="gpu") # CUDA GPU neurocuda.deploy(model, "snn_cifar10", target="cpu") # CPU fallback neurocuda.deploy(model, "snn_cifar10", target="loihi2") # Intel Loihi 2 simulator neurocuda.deploy(model, "snn_cifar10", target="fpga") # FPGA
Cross-backend deviation between GPU, CPU, and the Loihi 2 simulator is verified at 1.2% or less, with zero spike deviations across 256,000 comparisons against Intel's published Loihi neuron equations - the same validation already documented for the core NeuroCUDA compiler, carried over unchanged into the ROS2 package.
What's verified, what isn't yet
In keeping with how every result on this site is reported - no inflated claims, no silent gaps:
- Done: code compiles, both ROS2 packages build with colcon, CI/CD runs on GitHub Actions, Docker builds successfully, core inference works end-to-end from HuggingFace hub to output.
- Not yet: tested against a live ROS2 runtime on real Linux hardware, lifecycle-node compliance (currently standard nodes), full message-type wiring in the Python nodes (currently emits String in places where typed messages are defined), and deployment on a physical robot.
This is software that builds, runs, and produces correct output in isolation - the next milestone is validating it against a live ROS2 graph and a physical camera, not just a recorded topic.
Where this fits
NeuroCUDA ROS2 isn't a new spiking-neuron algorithm or a new compiler - it's packaging. The compiler, the QCFS-to-IF conversion pipeline, and the multi-backend deployment already exist and are documented on the NeuroCUDA page. What's new here is making that compiler reachable from inside a robot's existing software stack with the same install command and launch-file convention every other ROS2 package uses. See the full NeuroCUDA ROS2 architecture page for the message definitions and Docker image in detail. New to ROS2 itself? Start with What Is ROS2?. For how this compares to every other SNN-and-robotics project out there, see ROS2 and Spiking Neural Networks: What Exists, What Doesn't.