PointCloud Publisher
This example demonstrates how to create a static point cloud using 3D Slicer’s built-in features and publish it over a ROS 2 topic to be visualized in RViz.
Creating and Publishing the Point Cloud in 3D Slicer
You can run the publisher script in one of two ways:
Option A – run the script directly from a terminal using the slicer launcher’s
--python-script argument (the script executes automatically after Slicer starts):
ros2 run slicer_ros2_module slicer --python-script $(ros2 pkg prefix slicer_ros2_module)/share/slicer_ros2_module/docs/code/point_cloud_publisher.py
Option B – paste the code into Slicer’s Python Interactor (Ctrl + 3 or through the Developer Tools menu):
import slicer
import vtk
import qt
# 1. Build sphere geometry and a transform filter to animate it
sphere = vtk.vtkSphereSource()
sphere.SetRadius(15.0)
sphere.SetThetaResolution(20)
sphere.SetPhiResolution(20)
sphere.Update()
transform = vtk.vtkTransform()
transformFilter = vtk.vtkTransformPolyDataFilter()
transformFilter.SetInputConnection(sphere.GetOutputPort())
transformFilter.SetTransform(transform)
transformFilter.Update()
# 2. Create a Model node seeded with the initial geometry
modelNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode', 'AnimatedPointCloud')
modelNode.SetAndObservePolyData(vtk.vtkPolyData())
modelNode.GetPolyData().DeepCopy(transformFilter.GetOutput())
modelNode.CreateDefaultDisplayNodes()
# 3. Set up the ROS 2 publisher
rosLogic = slicer.util.getModuleLogic('ROS2')
rosNode = rosLogic.GetDefaultROS2Node()
pub = rosNode.CreateAndAddPublisherNode('PolyData', '/slicer_point_cloud')
pub.SetFrameId('world')
# 4. Auto-republish whenever the model node is marked modified.
# This also fires if the user edits the model interactively in Slicer.
def onModelModified(caller, event):
pub.Publish(caller.GetPolyData())
modelNode.AddObserver(vtk.vtkCommand.ModifiedEvent, onModelModified)
# Publish the initial frame immediately
pub.Publish(modelNode.GetPolyData())
# 5. Drive the animation at 10 Hz: rotate the sphere 5 degrees per step
angle = [0.0]
def animate():
angle[0] = (angle[0] + 5.0) % 360.0
transform.Identity()
transform.RotateZ(angle[0])
transformFilter.Update()
modelNode.GetPolyData().DeepCopy(transformFilter.GetOutput())
modelNode.Modified() # triggers onModelModified -> pub.Publish()
timer = qt.QTimer()
timer.setInterval(100) # 10 Hz
timer.connect('timeout()', animate)
timer.start()
# Keep a reference so the timer is not garbage-collected
slicer.modules.AnimatedPointCloudTimer = timer
print("Animated point cloud publisher started at 10 Hz on /slicer_point_cloud.")
print("The model will also republish automatically if you edit it in Slicer.")
Once executed, Slicer will create a local model displaying the sphere, and publish
the points to the ROS 2 topic /slicer_point_cloud with the frame_id set to
world.
Visualizing in RViz
To visualize this published point cloud in RViz:
Open a terminal, source the ROS 2 setup script, and launch RViz:
source /opt/ros/jazzy/setup.bash rviz2
- Configure RViz Display:
In the Global Options panel, set the Fixed Frame to
world.Click the Add button at the bottom left of the window.
Switch to the By topic tab, expand
/slicer_point_cloud, select PointCloud2, and click OK.(Optional) In the newly added PointCloud2 display properties, increase the Size (m) parameter to
0.2or larger to render the sphere points clearly in the 3D grid.