Time Synchronization with PPS
Besides the position, most GNSS receivers can output a PPS (Pulse Per Second) signal: a hardware pulse emitted at the beginning of every UTC second. Used together with the time contained in the NMEA sentences, it lets the operating system align its clock to UTC within about a microsecond.
Why synchronize the clock?
The ZED SDK Fusion module matches camera data and GNSS data by timestamp. Camera images are timestamped with the system clock of the host, while GNSS measurements are usually timestamped with the GNSS time given by the receiver. If the system clock drifts away from UTC, the two timestamps no longer refer to the same instant, which degrades the fusion result or causes the data to be dropped. See Data Synchronization for more details on how the matching is performed.
The time contained in the NMEA sentences is affected by the latency and the jitter of the serial link, which limits its accuracy to a few milliseconds. The PPS edge, instead, is aligned to UTC with an accuracy in the order of tens of nanoseconds.
Disciplining the system clock with PPS is recommended when:
- your device has no reliable network time source (NTP), for example on a robot operating outdoors without connectivity,
- you fuse camera and GNSS data with the Global Localization module and need the best possible timestamp alignment,
- you record datasets that must be replayed or compared with data coming from other machines,
- you run a multi-camera setup where several devices must share a common time base.
The PPS signal is generated only when the GNSS receiver has acquired a valid fix. If no antenna is connected, or if the sky visibility is poor, no pulse is produced.
Hardware requirements
On Linux, the PPS signal is handled by the kernel PPS subsystem, which exposes it as a /dev/ppsN character device. The most common setup is:
- a GNSS receiver with a PPS output pin,
- a connection from this pin to a GPIO of the host, with compatible voltage levels,
- a device tree node that binds this GPIO to the Linux
pps-gpiodriver, and a kernel built withCONFIG_PPSandCONFIG_PPS_CLIENT_GPIO.
The GPIO to use and the device tree configuration depend on your board. Consult your carrier board vendor to know which pins support this use and how to enable the pps-gpio driver.
On the ZED Box Orin with the GNSS option, the PPS signal of the GNSS module is already wired and enabled: /dev/pps0 is available out of the box. See Using GNSS with ZED Box Orin.
USB receivers usually do not transmit the PPS signal over USB. Some USB-to-serial adapters can carry it on the DCD line of the serial port, which gpsd can use, but with a lower accuracy than a GPIO because of the USB latency.
Checking the PPS device
Once the PPS input is configured, the kernel exposes the signal as a PPS character device:
You should get /dev/pps0, or another index if several PPS sources are declared.
A quick check that does not require any additional package is to read the timestamp of the last pulse:
The value is the system time of the last rising edge, followed by the number of pulses received since boot. Reading it twice one second apart should show the counter increasing.
To monitor the pulses continuously, install the pps-tools package:
Then monitor the device:
The output should look like this:
The assert value is the system time at which the kernel detected the rising edge of the pulse, and sequence increments once per second. A value close to a whole second means that the system clock is already well aligned to UTC.
Synchronizing the system clock
This section assumes that gpsd is installed and configured as described in Setting up GNSS / RTK on Linux.
Feeding the PPS signal to gpsd
gpsd can read the PPS device together with the serial port of the GNSS receiver. Add /dev/pps0 to the list of devices passed to gpsd:
If you are also using RTK corrections through NTRIP, the PPS device is simply appended to the NTRIP command:
Replace ttyACM0 with the communication port of your GNSS receiver, and pps0 with your PPS device.
You can check that gpsd is actually receiving the pulses with:
Samples labeled NTP0 come from the NMEA time, while the ones labeled NTP1 come from the PPS signal.
To make the configuration persistent, update the gpsd line of your cron job so that it also includes the PPS device (see the warning below).
Configuring Chrony
gpsd publishes these two time sources in shared memory, where an NTP daemon such as Chrony can read them to discipline the system clock. Install it with:
And add the two reference clocks to /etc/chrony/chrony.conf:
Restart the service and verify that the reference clocks are used:
The PPS source should be marked as the selected one (*) after a few tens of seconds.
Reading the PPS device and writing to the shared memory segments 0 and 1 require root privileges. That is why the commands above start gpsd with sudo. If you start it from a cron job, add the job to the root crontab with sudo crontab -e.
These two segments are readable by the root user only. If chronyd cannot read them on your system, configure gpsd and Chrony to use segments 2 and 3 instead, which are world-readable.
Once the system clock is disciplined by PPS, every timestamp generated on the device, including the ZED camera timestamps, shares the same UTC-aligned time base.

