A camera icon splitting into a smooth graceful signal and a jagged abrupt one, illustrating a clean SIGINT shutdown versus a forced SIGKILL
ros2dockermediatek geniocameraembedded linux

Camera Lifecycle in Docker: SIGINT vs SIGTERM

Andres Campos ·

A camera that will not restart cleanly is a small bug with a large blast radius, because everything downstream depends on it. Ours got stuck in a way that looked like flaky hardware and was actually a stop signal. This is one of those fixes that is one line and saves a day, so it is worth knowing before you meet it.

Key Insights

  • Our ROS 2 camera container took ten seconds to stop and left the camera in a bad state
  • The launcher ran as PID 1 and ignored SIGTERM, so every stop rode out Docker’s grace period and ended in a hard kill
  • The hard kill left the camera mid-operation, it self-reset, and the next open collided with that reset and never recovered
  • Switching the container’s stop signal to SIGINT let the process close the camera cleanly in about a second, and restarts became reliable
  • A frame watchdog was added as a backstop to recover from any remaining stuck state

The symptom

Stopping and restarting the camera container was unreliable. A stop took a full ten seconds, and afterward the camera would often fail to open, throwing the same error over and over and never recovering until a deeper reset. It alternated between working and failing in a way that felt like a bad cable or a marginal device, which is the kind of symptom that sends teams down the hardware path for days.

The cause: PID 1 and the stop signal

Inside the container, the ROS 2 launcher ran as process ID 1. When Docker stops a container it sends the SIGTERM signal and waits a grace period before hard-killing with SIGKILL. The launcher, as PID 1, did not act on SIGTERM, so every stop waited out the entire grace period and then died by force. That is why the stop took ten seconds, and it is why the camera was left in a bad state: a forced kill does not give the process a chance to close the device cleanly.

Then the two halves collided. The camera, abandoned mid-operation, would reset itself a couple of seconds later. Meanwhile the next start of the container was already trying to open the camera, and that open landed right on top of the device’s self-reset. The result was a camera that never came back until something reset it harder.

The fix

The camera closed cleanly when the process received SIGINT, the interrupt signal, rather than SIGTERM. Telling the container to use SIGINT as its stop signal changed the shutdown from a ten-second forced kill into a clean close in about a second, with no device reset and reliable restarts. We also added a frame watchdog as a backstop: if the camera goes quiet unexpectedly, it recovers the device rather than sitting stuck.

That is the whole fix, and it is the kind of thing that is obvious once seen and invisible until then. The general lesson is broader than cameras: any container that owns a hardware device needs its shutdown to actually reach the process, so the device gets released cleanly. When PID 1 ignores the signal Docker sends, you get hard kills and stuck devices, and the cure is to send a signal the process respects.

We keep the specific launch and compose details for the projects we do, because they vary with your stack. The reusable insight, the one worth publishing, is to check the stop signal the moment a device-owning container restarts badly.

If your containerized robotics or vision stack has services that will not cycle cleanly, on the MediaTek Genio or on NVIDIA Jetson, tell us what you are building and we will make the lifecycle reliable. For the whole robot, see the ROSOrin build overview.

MediaTek Genio Expert Support

Building on MediaTek Genio?

BSP bring-up, GStreamer pipelines, NeuroPilot integration, we've shipped it. Get unblocked fast. One call to scope it, fixed bid to deliver it.

Frequently Asked Questions

Why does a ROS 2 container take ten seconds to stop?

Because the process running as PID 1 in the container ignores the default stop signal. Docker sends SIGTERM, waits, and then hard-kills with SIGKILL after its grace period. A launcher that does not handle SIGTERM as PID 1 rides out the whole grace period and dies by force, which is slow and unclean.

What is the difference between SIGINT and SIGTERM for a container?

They are different stop signals, and a given program may handle one and ignore the other. Some launchers, including common ROS 2 launch setups, respond cleanly to SIGINT, the interrupt signal, but do not act on SIGTERM when running as PID 1. Telling the container to stop with SIGINT lets the process shut down gracefully instead of being killed.

Why did our camera get stuck after stopping the container?

A hard kill left the camera mid-operation, and the device then reset itself a moment later. The next attempt to open the camera collided with that self-reset and never recovered, failing repeatedly. Fixing the stop so the process closed the device cleanly removed the collision and made restarts reliable.

Andrés Campos, Co-Founder & CTO at ProventusNova

Written by

Andrés Campos

Co-Founder & CTO · ProventusNova

8 years deep in embedded systems, from underwater ROVs to edge AI. Andrés leads every technical delivery personally.

Connect on LinkedIn