Your depth camera driver starts, its topics show up in rostopic list, and the people detection node sits there receiving nothing. The two programs almost never use the same topic names, and ROS does not search for a match: a publisher and a subscriber connect only when a topic name and its message type line up exactly. The fix is remapping — renaming one side's topics in the launch file until they meet the other side. This guide gives you the full procedure for a depth camera feeding a people detection node: find what the driver publishes, read what the detector subscribes to, confirm the message types, wire the remaps, and prove frames are flowing with a rate check before you touch a single detection parameter.
Find what each node actually uses
Three things need to be running: the camera driver, the built detector package and a terminal.
Start the driver on its own and list what it advertises:
rostopic list
A depth camera rig typically publishes four kinds of topic: a color image, a rectified depth image, a point cloud, and a camera_info message for each image stream that carries the intrinsics. For each topic, run:
rostopic info /camera/color/image_raw
rostopic info prints the two things you need: the message type, and who publishes or subscribes. The name above is illustrative — your driver chooses its own names, which is exactly why this check comes first.
The detector's inputs are in its documentation, but the running node is more honest. Launch it, then run:
rosnode info /people_detector
The Subscriptions block lists every topic the detector wants, each with the message type it expects. Put the two lists side by side and pair them: color to color, depth to depth, cloud to cloud, info to info. The companion task — feeding depth frames to an inference model — is covered in Depth camera object detection: connect frames to inference.
Match message types before you remap anything
ROS connects a publisher and a subscriber only when their message types are identical: sensor_msgs/Image to sensor_msgs/Image, sensor_msgs/PointCloud2 to sensor_msgs/PointCloud2. A remap changes names, never types. When the types differ, the remapped nodes still never meet, and ROS prints no error — the detector just runs forever on no input.
The classic trap is compression. Drivers built on image_transport publish raw and compressed variants side by side: /camera/color/image_raw as sensor_msgs/Image and /camera/color/image_raw/compressed as sensor_msgs/CompressedImage. Remap a detector that wants Image onto the compressed name and nothing flows. Point the remap at the raw topic; the ROS depth color compression mismatch guide walks that diagnosis step by step.
When the detector wants a type the driver does not produce, choose one of two clean fixes:
- Change the driver. Enable the missing stream — the point cloud, or the registered depth image — in the driver's own launch parameters.
- Insert a converter. If the driver gives a depth image and the detector wants a cloud, run the depth-image-to-cloud nodelet from the depth_image_proc package and remap its topics to yours: its depth input onto the driver's image topic, its points output onto the detector's cloud input. The nodelet runs the deprojection covered in Depth map to point cloud: the deprojection calculation explained.
Deprojecting a cloud back into a depth image is not the practical route: the projection is many-to-one, so the result loses structure and the effort outweighs enabling the driver's image stream. If the detector wants the image, enable the image stream instead.
Wire the remaps in the launch file
Both nodes get remap tags inside their own <node> block, and both sides point at one agreed absolute name. Names without a leading slash resolve inside the node's namespace, which is how a "correct" remap quietly lands on /camera/color_image while the detector watches /color_image. Absolute names remove the guesswork.
<!-- Illustrative: replace every pkg, type and topic with your own -->
<launch>
<!-- the names both nodes agree on -->
<arg name='color' default='/camera/color/image_raw'/>
<arg name='depth' default='/camera/depth/image_rect_raw'/>
<node pkg='my_depth_camera_driver' type='camera_node' name='camera' output='screen'>
<remap from='image_color' to='$(arg color)'/>
<remap from='image_depth' to='$(arg depth)'/>
</node>
<node pkg='my_people_detector' type='detector_node' name='detector' output='screen'>
<remap from='image_in' to='$(arg color)'/>
<remap from='depth_in' to='$(arg depth)'/>
</node>
</launch>
The steps, for any driver-detector pair:
- Put both nodes in one launch file, so a single command starts the rig.
- Add a
<remap>tag inside each<node>block. A tag left at launch-file level applies to every node in the file, which is rarely what you want. - Remap the driver's published names and the detector's subscribed names onto the same absolute topics.
- Pair every stream: image with image, depth with depth, cloud with cloud, camera_info with camera_info. The detector needs the intrinsics to register depth into the color frame; ROS 2 camera calibration: validate and publish camera_info shows what a valid camera_info message must contain.
- Save, relaunch, and run the checks in the next section.
Typical pairings, and the action each needs:
| Driver publishes | Its type | Detector wants | Its type | Action |
|---|---|---|---|---|
| /camera/color/image_raw | sensor_msgs/Image | /detector/image_in | sensor_msgs/Image | remap both onto one name |
| /camera/color/image_raw/compressed | sensor_msgs/CompressedImage | /detector/image_in | sensor_msgs/Image | remap onto the raw topic |
| /camera/depth/image_rect_raw | sensor_msgs/Image | /detector/cloud_in | sensor_msgs/PointCloud2 | insert depth_image_proc/point_cloud_xyz |
Topic names in the table are illustrative; the message types are the ones ROS actually prints.
Prove frames are flowing
- Relaunch and run
rostopic infoon each shared topic. The detector must now appear under Subscribers. If only the driver is listed, a name is still unmatched. - Run
rostopic hzon a shared image topic. The rate should sit near the camera's native rate — around 30 Hz for a live depth camera. A steady 0.0 means the driver is not streaming at all; the stream-enable and trigger checks in 3D camera frame rate low on software trigger: mode and data streams cover that case. - Watch the detector's output topic until the first detection message arrives. That one message proves the whole chain — driver, remap, detector.
The bandwidth behind a silent dropout
A perfect remap can still starve the detector if the pipe is too small for the streams you just wired together. Size the link before adding a second camera.
Take a 640 × 480 depth camera streaming RGB8 color and an xyz point cloud at 30 Hz:
- Color: 640 × 480 pixels × 3 bytes per pixel = 921,600 bytes per frame; × 30 Hz = 27.6 MB/s.
- Cloud: 640 × 480 points × 12 bytes per point — three float32 fields, x, y and z — = 3,686,400 bytes per frame; × 30 Hz = 110.6 MB/s.
- Combined: 138.2 MB/s of payload, which is 1.11 Gbps on the wire (decimal MB).
A GigE link carries 125 MB/s at line rate and roughly 110 MB/s once protocol overhead is paid, so this one camera saturates one port. Drivers that pad each point to 16 or 32 bytes, or pack an RGB field into the cloud, push the cloud figure higher; resolution and frame rate scale the result linearly.
The decisions this drives: one camera at full rate wants USB 3 or a dedicated GigE port; two or more cameras streaming clouds want one network port each, or a throttled re-publisher that cuts the cloud to 10-15 Hz. At 15 Hz, the combined load above halves to 69.1 MB/s.
When the detector still receives nothing
Work down the list; each cause has a short test.
-
Compressed variant.
rostopic infoshows sensor_msgs/CompressedImage where the detector expects sensor_msgs/Image. Remap onto the raw topic. -
Namespace doubling. The remap resolved inside a namespace, so the driver publishes
/camera/color_imagewhile the detector watches/color_image. Use leading-slash absolute names on both sides. -
Remap on the wrong node. A
<remap>tag outside its<node>block applies to every node in the file. Move it inside the node that owns the topic. - Stream not enabled. The cloud or registered depth topic does not exist at all. Check the driver's stream settings in its launch parameters — the renamed-parameter case is exactly what ROS camera launch parameter not supported: fix renamed settings resolves.
- Sync requirement. The detector subscribes to depth, color and camera_info and waits for timestamps that line up; one missing member blocks all output. Remap every member of the set, not just the images.
- QoS mismatch (ROS 2). Names and types match, but the driver publishes best-effort data while the detector's subscription asks for reliable delivery. Align the reliability setting on one side.
The hardware running the stack
The wiring is software, but frames still have to move. Two hardware numbers decide whether they do: link capacity — the section above — and the number of ports on the machine. A single depth camera on USB 3 runs from any workstation; a multi-camera cell wants one network port per camera plus processor headroom for the detection workload. That is the vision controllers category: compact fanless boxes with a handful of LAN ports at the entry end and multi-port units with eight built-in light channels at the top.
For the camera side, the 3D sensors category groups depth cameras by type — ToF, structured light, laser profiler — and the camera finder filters them by range and interface. An example of the depth-camera class this procedure applies to:
- Type
- Depth / ToF camera
And if you would rather keep the workstation out of the cell, a compact vision controller runs the driver and the detector next to the camera:
- LAN ports
- 3-4 LAN ports
- USB 3 ports
- 2 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
If you are specifying a rig rather than wiring one, put the camera choices and port count into the system configurator. When the detector's required topics and rates are already known, send them along through the contact page — they decide the camera and the controller. The 3D topic page collects the rest of the depth-camera guides, from capture settings to point-cloud handling.
Questions
Can I remap a topic without editing the launch file?
Yes. Add the remapping when you start the node: rosrun my_package my_node image_in:=/camera/color/image_raw, with your own package, node and topic names. The same two rules apply — the names must line up and the message types must be identical. Command-line remaps suit a quick test; once a pair works, move it into the launch file so the wiring survives the next relaunch.
Do I need to remap the camera_info topics too?
If the detector registers depth into the color image or builds a point cloud from the depth image, it subscribes to sensor_msgs/CameraInfo for the intrinsics, and those subscriptions need remapping like any other topic. Keep each camera_info paired with its own image: a depth frame combined with another camera's intrinsics produces a cloud that is warped even though every topic connects.
What changes in ROS 2?
The name-based wiring survives, but the syntax moves: remaps travel as --remap from:=to arguments on the command line or as a remappings entry in the launch description. The new silent failure is QoS — a publisher sending best-effort data never satisfies a subscription requesting reliable delivery, even with matching names and types. Compare the QoS profiles of both nodes before blaming the remap.
What frame rate does a people detection node need?
For people walking at a normal pace of about 1.4 m/s, 10-15 Hz is a workable floor for tracking and 30 Hz is comfortable. The arithmetic: at 30 Hz a walker moves about 4.7 cm between frames, and at 10 Hz about 14 cm, which leaves plenty of overlap for classical detectors. Measure what actually arrives with rostopic hz before tuning the algorithm.

