An imaging parameter that keeps switching itself back on looks like a camera fault, and it almost never is. On ROS cells the signature is precise: enable_auto_exposure reads True after some restarts, the images come up overexposed, and the fault can go days without repeating. The cause is an ordering race between your startup script and the ROS master, and it leaves evidence you can find in two minutes. This guide walks the diagnosis: read the failed write out of the boot log, prove the camera is innocent, and re-order the boot so the write cannot lose the race again. The same reasoning protects every parameter you set from a script before the node launches.
Why does enable_auto_exposure flip back to True after a restart?
It never flipped: the rosparam set ran while the ROS master was not yet listening, the command failed with "Unable to communicate with master!" and wrote nothing, and the node then started on the wrapper default, enable_auto_exposure=True.
Nothing in the camera changes the parameter. enable_auto_exposure lives on the master's parameter server, and the wrapper reads it once, when the node starts. Found false, the camera exposes manually for the whole session; found absent or True, the wrapper applies its default and auto exposure runs.
Two paths put the parameter in that state at boot, and both are live on every restart. The parameter server holds its values in the master process's memory, so a value written yesterday is gone when the master restarts today. And a rosparam set that runs before any master is listening writes nothing at all, apart from one stderr line that an unattended boot throws away. The depth-camera sibling of this failure, a depth stream whose own auto exposure ignores startup settings, is covered in the depth auto exposure setting order guide.
What does "ERROR: Unable to communicate with master!" mean?
rosparam is a client of the master's parameter server: it asks the master at ROS_MASTER_URI, by default http://localhost:11311, to store the value, and when nothing is listening on that address it prints the error and exits without writing.
Work the causes in this order, because the first is by far the most common at boot.
- The master is not up yet. roscore and your script start independently; in the seconds — typically 2 to 5 on a healthy machine — before the master accepts connections, every write fails. That is the race this article closes.
- No master is running at all. If nothing on the machine runs ROS, the error is expected, not a fault: start roscore first.
- ROS_MASTER_URI points somewhere else. A master on another machine, or one inside a container that is not exported, does not answer on the address your client dialed.
- The handshake cannot complete. On a multi-machine cell, ROS_HOSTNAME and ROS_IP must be set to the hostname and IP address of the machine itself, not of any other machine; a client advertising the wrong address cannot connect back. The 3D camera handshake guide walks that class of failure.
rostopic, rosnode and rosservice print the same line for the same reason: they are all clients of the same master, so the error is never specific to rosparam.
How do you confirm the failed write and rule out the camera?
Three checks decide it: read the parameter back after the node is up, count the master-error lines in the boot log, and reproduce the race by writing with no master running — if the parameter reads True while the log shows the failed write, the camera is innocent.
Run the readback first; it takes ten seconds:
rosparam get /camera_source/rgb_camera/enable_auto_exposure
rosrun dynamic_reconfigure dynparam get /camera_source/rgb_camera
True on the first line confirms the symptom. Then grep the boot log for "Unable to communicate with master". Each failed rosparam set prints exactly one such line, so a loop writing seven parameters leaves seven identical lines when all seven raced; the count tells you how many writes were lost. Finally, reproduce it on demand: with everything stopped, run the rosparam set alone. The same error appears, nothing is written, and you are holding the failure signature.
The camera cannot be the culprit: the parameter lives on the host's parameter server, not in the camera, and no camera command edits it mid-run. What you saw was the wrapper applying its default. A separate warning such as "Failed to read modalias" comes from the camera driver's Linux video backend and belongs to a different investigation; close the parameter race first.
How do you make the startup script wait for the ROS master?
Poll the master with a light read until it answers, then write: run rosparam list in a retry loop, and only after it succeeds issue your rosparam set commands, because the master, not the camera, is the thing you are waiting for.
The script below waits at most 30 seconds, then writes and proves the result:
ok=""
for attempt in $(seq 1 30); do
if rosparam list >/dev/null 2>&1; then ok="yes"; break; fi
sleep 1
done
if [ -z "$ok" ]; then
echo "ROS master not answering after 30 s" >&2
exit 1
fi
rosparam set /camera_source/rgb_camera/enable_auto_exposure false
# Test: the readback must print False, never True.
rosparam get /camera_source/rgb_camera/enable_auto_exposure
rosparam list is the probe because it reads the same server your write targets, so its success is exactly the readiness you need. The 30-second budget has a basis: a master starts in 2 to 5 seconds on a healthy machine, so thirty seconds gives roughly a tenfold margin while still failing a genuinely dead master fast enough to page someone. Order inside the script stays fixed: master up, parameters written, node launched. If the master runs as a service, express the ordering there as well, so the poll is a backstop rather than the only guard.
Should enable_auto_exposure be set in the launch file instead?
Yes, and for a fixed value it is the better fix: a param element inside the node block of a launch file is loaded by roslaunch — which starts the master first, then the parameters, then the nodes — so the write cannot race ahead of the master.
Put the switch where the wrapper reads it:
<launch>
<node pkg="depth_camera_pkg" type="camera_node.py" name="camera_source">
<param name="rgb_camera/enable_auto_exposure" value="false" />
</node>
</launch>
The node name and package above are illustrative; the parameter element is the real thing. A param inside the node element is private, so it resolves under the node name and lands on /camera_source/rgb_camera/enable_auto_exposure, the same address your command-line write used. The wrapper reads what it finds there at startup and applies false before the first frame. Keep the wait loop from the previous section for values you compute at runtime; a launch file can only carry values known at launch time.
If a parameter set this way still seems ignored, the usual cause is a renamed parameter rather than timing; the renamed launch parameter guide covers that diagnosis. On a cell with several cameras, plan the launch order explicitly — the multi-camera launch planning guide lays out acquisition and synchronization alongside the parameters.
| Fix | Use when | Race left open? |
|---|---|---|
| Wait loop, then rosparam set | Values computed at runtime, or writes must stay in your script | No, if every write is gated by the poll |
| param element in the launch file | Value fixed at launch time | No; the launcher orders master, parameters, nodes |
| Saved camera-side user set | A second line of defence for exposure defaults | Host-side parameters still need one of the two above |
The third row persists exposure defaults in the camera's own memory so they survive power cycles; see save camera parameters as a user set that loads on startup.
Why does the overexposure appear only once every few reboots?
Because it is a timing race between processes that start independently: on most boots the master wins and the write lands; on a slow boot — a cold disk, DHCP still running, a loaded CPU — the script wins, the write fails, and nothing else tells you.
The window is the gap between your script's first write and the master accepting connections, and boot-time work you do not control sets its width. A bench reboot with a warm cache can hide the race for weeks; a plant-floor cold start loses it on the first morning. The fault therefore appears at roughly the rate the cell reboots, at most once per day on a machine that reboots daily, and never on command unless you stop the master first.
It also hides its own evidence. The error text goes to the stderr of whatever terminal or service ran the script, and an unattended cell usually discards it, so the only traces are the log line and a parameter reading True. Silently-not-applied startup settings are a whole family of faults; the auto exposure upper limit never applied guide covers a sibling. The cure is the same in every case: make the boot assert and verify its own settings.
What do you check after every reboot so this cannot regress?
One readback, every boot: after the node is up, ask the server for the value and fail the boot check if it is not false — rosparam get /camera_source/rgb_camera/enable_auto_exposure printing False is the pass condition, anything else stops the line before a bad image does.
Build the rest of the prevention around that assert:
- Master first, writes second, node last. Keep that order in one script, or express it as ordering between the services.
- Move every fixed parameter into the launch file. The wait loop remains only for values computed at runtime.
- Gate every rosparam write on the poll and check the exit status before moving on.
- Assert on every boot. Read the parameter back and fail loudly on anything but False; one command per boot catches every future reordering.
- Alarm on the error line. A count of "Unable to communicate with master" above zero in a boot log means a write was lost; make that an alert, not a footnote.
- Decide auto exposure deliberately. If some scenes do better with auto on, set an explicit brightness target rather than the default. If you also drive exposure from outside ROS, apply the same before-streaming order — the manual exposure before streaming guide is the counterpart.
When the camera itself also misses its boot window and is not discovered at startup, that is a separate enumeration failure; the GigE camera boot order guide sorts it.
Which cameras does this startup order apply to?
Any camera driven through a ROS wrapper, because the parameter server and its defaults live on the host rather than in the camera; a stereo pair, a ToF unit and a structured-light projector all expose their switches the same way, so the same two fixes close the race.
The pattern is not ROS-specific either. Any integration that writes settings from outside the imaging stack has the same shape, including GenICam-based set-ups where the exposure write must land before acquisition starts; setting exposure through a GenICam API shows that side.
If you are specifying the depth camera side of the cell as well, these are the two depth families most integrations start from:
- Type
- Depth / ToF camera
- Type
- Stereo / structured light
To put the rest of the cell together rather than debug it piecemeal, start from the 3D sensors and area scan cameras categories, or go straight to the camera finder. More start-up-order guides sit on the learn hub, and if a fault needs eyes on your logs, contact us.
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.
Questions
Does the same failure hit rostopic and rosservice calls?
Yes, and they fail the same way: rostopic, rosnode, rosservice and viewer tools such as rviz are all clients of the same master, so with nothing listening they print their own Unable to communicate with master variant and do nothing. The readiness poll from the main guide belongs ahead of any client call, not only ahead of rosparam set.
Can you set the parameter from a second machine on the network?
Yes. Point ROS_MASTER_URI at the machine running the master on port 11311, its default. Both ROS_HOSTNAME and ROS_IP must then be set to the hostname and IP address of the machine you are calling from, not of any other machine, or the return connection cannot complete. The same rule keeps a single-machine cell talking to itself.
Can a written parameter survive a reboot?
Not a rosparam set. The parameter server is memory inside the master process, so nothing written through rosparam survives a master restart or a reboot; persistence has to come from somewhere else. That is why the launch-file param loads on every boot, and why a saved camera-side user set is worth adding for exposure defaults.
How does a script detect that a rosparam set was lost?
Capture stderr and grep it for Unable to communicate with master, then read the parameter back and require False. The pair is dependable, and the readback also catches the opposite failure, a command that returns cleanly but wrote to the wrong parameter name. Log both checks; the boot alarm keys off the same grep.
Auto exposure is off now but the image is still bright — what next?
Then the manual exposure value is the next suspect. With auto exposure off, the wrapper's manual exposure parameter, commonly named exposure_time, governs, and a value left over from auto mode can be far too long for the scene. Set it explicitly in the same launch file, and read it back after the node is up just as you did for the auto switch.

