You can drive the arm in rviz, but the Image display never shows the wrist camera: you get the laptop's built-in webcam instead, or an empty panel. Nothing is missing from your ROS installation and no feature pack is needed. Linux gives every UVC camera a /dev/video node, the camera driver opens one node, and by default it opens the first node on the machine — on a laptop, the built-in webcam. The fix is to identify which node belongs to the wrist camera, pass that node to the driver as its device parameter, and subscribe an rviz Image display to the topic the driver publishes. The sections below cover the commands, the parameter, the checks that confirm frames are flowing, and the two rviz settings that leave the panel blank even when the topic is healthy.
What you need
A Linux machine (Ubuntu or similar) with ROS or ROS 2 and rviz on it. A UVC camera driver package — uvc_camera is the one most ROS 1 stacks reach for. The v4l-utils package, which provides v4l2-ctl; sudo apt install v4l-utils adds it. The wrist camera on its USB cable, with a connector you can reach for the unplug test in a moment.
If v4l2-ctl --list-devices prints nothing at all, fix the driver layer before anything else: the UVC driver module may not be loaded, and the Uvcvideo module not loaded: check for a built-in driver guide is the first check.
Find the wrist camera's video node
Linux hands out /dev/video numbers in the order USB devices finish enumerating, so the number alone tells you nothing. The unplug test tells you everything, and it takes about ten seconds.
- Run
v4l2-ctl --list-devices. The output groups nodes under each physical camera, with a name and a USB bus path per group. - Read the grouping. Recent kernels create two nodes per UVC camera: the lower node captures frames, the second carries metadata. Only the capture node accepts format and exposure settings.
- Unplug the wrist camera and run the command again. The pair that vanished belongs to it. Replug and confirm the same pair returns.
- Write down the wrist camera's capture node — the lower number of its pair. The driver needs that exact path in the next step.
Reported names can mislead when two cameras look alike, because laptop webcams and board cameras often share generic product strings; trust the unplug test over the label. The same matching problem, solved by bus path and port, is walked through in Two identical USB cameras: same name, open one by port.
Pass the node to the driver
Every UVC camera driver node has a device parameter, the setting that selects which /dev/video path it opens. Left unset, it opens /dev/video0 — and on a laptop that is the built-in webcam, which is exactly why rviz has been showing you the room instead of the part.
Confirm the parameter's exact name before setting it: rosparam list | grep -i device on ROS 1, ros2 param list on ROS 2. UVC driver packages commonly name it device or video_device. With a parameter named device, a command-line override reads rosrun uvc_camera uvc_camera_node _device:=/dev/video2, and on ROS 2 the same value goes to the node as --ros-args -p device:=/dev/video2, or permanently in the launch file. If rosparam list shows a different name, use that one — the path after := is the unplug-test capture node either way.
If the node refuses to start with a device or resource busy error, another process holds the node: a second driver instance, a vendor viewer, or a leftover test capture. Clear it before blaming the camera; the VIDIOC_S_FMT device or resource busy: two nodes opening one camera guide walks that diagnosis.
Check the frames before you open rviz
Confirm the stream first, so anything left over is an rviz problem rather than a camera problem.
-
rostopic list | grep image(ROS 1) orros2 topic listfinds the driver's raw topic, usually the one ending in image_raw. -
rostopic hz /camera/image_rawshould sit at the frame rate you configured. Half the configured rate usually means the USB link cannot carry the uncompressed format, not that the camera is broken. - Echo one message header and read
frame_id— the frame name rviz needs later.
Worked example: a bench arm cell with a laptop webcam and a wrist UVC camera
The set-up: a bench arm driven from a laptop, a wrist camera on USB, and only the laptop webcam's image arriving in rviz.
Inputs, and where each comes from:
- Two cameras: the laptop's built-in webcam and one wrist UVC camera (the set-up in the question).
- A UVC driver node with its device parameter unset, so it opens /dev/video0 — the default these nodes use, and the reason the built-in camera's frames are the ones that appear (the reported symptom).
- Recent-kernel node layout: two nodes per UVC camera, capture plus metadata (V4L2 behavior).
The rule in words: node numbers go to cameras in probe order, and within each camera's pair the lower node captures. Two cameras therefore occupy four consecutive nodes and expose two capture nodes, one per camera.
The arithmetic: the webcam probes first and takes nodes 0 and 1; the wrist camera takes 2 and 3. Capture nodes are 0 (webcam) and 2 (wrist camera). Two cameras × two nodes each = four nodes, /dev/video0 through /dev/video3, and v4l2-ctl --list-devices should show exactly that grouping.
The result: point the device parameter at /dev/video2 and the topic starts carrying wrist frames.
The decision, as a rule with its threshold: whenever the device parameter is unset and the wrist camera's capture node is anything other than /dev/video0, rviz shows the wrong camera on every capture, not intermittently. Set the parameter explicitly. If a disabled webcam or a hub change someday drops the wrist camera onto /dev/video0, the default happens to work — but the explicit parameter still wins, because the assignment can change at the next boot.
See the image in rviz
Add the Image display
With the topic publishing, open rviz and choose Add, then By topic, then Image, and pick the raw topic such as /camera/image_raw. The panel renders frames within a second or two. Added manually, the display takes the topic name in its Image Topic field, and its Status entry tells you whether it is subscribed and receiving.
A blank panel with a healthy topic
Three causes cover nearly every blank Image display whose topic shows a steady rate:
- Fixed frame with no transform. rviz draws every display inside the fixed frame set under Global Options and needs a valid transform between that frame and the frame the image message carries. With Fixed Frame left on map and no published transform for the camera, the panel stays empty even though frames arrive. Set Fixed Frame to the frame_id you read from the header — the transform to itself is trivially valid — or publish the missing transform.
- A QoS mismatch on ROS 2. Sensor drivers commonly publish BestEffort, and a Reliable subscription never matches it. Set the display's reliability to BestEffort; the RViz2 image topic published but not displaying: fix the QoS mismatch guide shows the settings.
- A compressed-only stream. The Image display subscribes the raw message type, so a stack that publishes compressed frames only needs a republish to raw, or the compressed transport where your rviz offers it. The Compressed image topic not published: get /compressed streams working guide covers the diagnostics.
When the wrist camera is not a /dev/video device
Machine-vision cameras that follow GigE Vision or USB3 Vision never appear as V4L2 video nodes. Their drivers own the transport, so the usual UVC package cannot open them; capture through the vendor SDK or a GenICam-based ROS driver that publishes sensor_msgs/Image, and every rviz step above applies unchanged. If a GigE camera throws parameter errors at configure time, start with the GigE camera failed to read parameter: fix the driver mismatch guide, and the area scan cameras page lays out the interface and shutter options.
Some smart wrist cameras skip the video stack entirely: images are served through the robot controller's own data channel, and that path has its own configuration notes for bringing the stream into ROS.
Picking the wrist camera itself
Weight, cable routing and shutter decide this purchase more than resolution does. The camera rides a moving joint, so compact board-level modules beat housed industrial cameras, a global shutter keeps frames usable while the arm moves, and GigE keeps video off USB altogether — the host reaches the camera by network address, so the /dev/video collision in this guide cannot happen.
Two board modules cover the usual wrist cases:
- Sensor format
- 1/1.8"
- Lens mount
- C-mount
- Sensor format
- 1/2.9"
- Lens mount
- M12
For capture on a moving wrist, the global-shutter USB3 module is the safer sensor; for the lightest payload, the 1.6 MP GigE module keeps cabling to one Ethernet run and mounts the smallest M12 lenses.
The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.
Keep the mapping and the permissions fixed
Two small chores save an afternoon later.
Enumeration: nothing pins /dev/video2 to the wrist camera. Hub order, boot timing or a firmware change can renumber it. A udev rule that matches the camera's USB serial number and creates a stable symlink lets the launch file point at one path forever.
Permissions: opening a camera is a write on the underlying USB device, so the user running the driver needs write access to the matching /dev/bus/usb entry. When the driver dies with an access error or the node list comes up short, add your user to the group that owns the device — video on most desktop installs — or install the driver package's udev rule. The Linux camera device permissions: video and media node checks guide lists the exact checks.
Common mistakes
- Trusting the number: /dev/video0 means first probe, not first camera you care about. Repeat the unplug test whenever hardware changes.
- Passing the metadata node: the second node of a UVC pair will not carry your format settings, because controls live on the capture node — the v4l2-ctl list-ctrls returns nothing: controls live on the right node guide shows the difference.
- Leaving Fixed Frame on map with no camera transform published, then blaming the driver.
- Expecting the raw Image display to render a compressed-only stream.
- Running two driver instances against one node and reading the resulting busy error as a hardware fault.
- Hunting for a missing feature pack: a driver that publishes sensor_msgs/Image plus an rviz Image display is the whole chain.
Once the device parameter points at the right node, the wrist camera's view sits next to your robot model in rviz, and every camera you add later repeats the same three moves: list, unplug, pass. When the hardware is the open question, the camera finder filters by interface, shutter and format, and the systems guides collect the device-node and driver fixes around it.
Questions
Why does my wrist camera get a different /dev/video number after every reboot?
Linux numbers video nodes in the order USB devices finish enumerating, and that order is not stable: hub placement, boot timing or a firmware update can reshuffle it. Two cameras therefore produce four nodes — two per camera — and the capture node is the lower of each pair. A udev rule keyed to the camera's USB serial can create a fixed name such as /dev/wrist_cam; point the driver's device parameter at the symlink once and the renumbering stops mattering.
Can rviz show the wrist camera and a fixed overhead camera at the same time?
Yes. Run one driver instance per camera, each with its own device parameter and topic name, then add one Image display per topic. Give the instances different frame names so transforms stay unambiguous. When both cameras are the same model, do not trust the reported product strings: match them by the USB bus path from v4l2-ctl output or by the unplug test before you assign parameters.
The vendor viewer shows the wrist camera but the ROS driver opens nothing — why?
The vendor viewer opens the device through its own library and can request formats and controls the ROS driver does not. Read back what the driver actually opened — the device path, the pixel format, the resolution — instead of assuming the camera failed. Cameras that follow GigE Vision or USB3 Vision never appear as /dev/video nodes at all, so a UVC driver cannot open them regardless of settings.
Do I need a global shutter on a wrist camera?
For frames captured while the arm moves, yes. A rolling shutter reads the sensor row by row, so motion during the exposure shears and smears the image, and a moving wrist supplies exactly that motion. A global shutter grabs every row at once and keeps geometry usable for detection and visual servoing. If you only capture after the arm comes to a full stop, a rolling shutter sensor is acceptable.

