# PTP synchronization

PTP synchronization distributes time over Ethernet so supported devices can share a common clock without a dedicated trigger wire.
It is useful when direct FSYNC wiring is impractical, but the deployment still needs clock-aligned capture scheduling.

### Principles and theory

PTP synchronizes device clocks over Ethernet instead of distributing a dedicated electrical trigger. On supported RVC4 platforms,
that shared clock is then used to drive a common frame schedule across devices rather than only to timestamp frames after capture.

In practice what that sync looks like is that epoch time line is divided it into slots, based on the chosen FPS. So in pseudocode

```text
frame_period = 1 / target_fps
slot_index = ptp_time_since_epoch / frame_period
```

Each participating device computes the same `slot_index` from the same PTP-synchronized clock, so they all aim for the same N-th
capture slot.

A PID regulator in the camera stack then nudges the sensor rate slightly above or below the requested FPS until the sensor locks
to that slot schedule. For example, a 30 FPS stream may temporarily run a little faster or slower to remove phase error, then
continue tracking the shared cadence. After that, the [Sync
node](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/sync.md) still pairs the nearest frames together, but
it is working on frames whose capture timing was already driven from the same network-synchronized timeline.

### When to use it

Use PTP synchronization when:

 * devices communicate over Ethernet and cannot share a convenient FSYNC wire
 * cable runs or switch-based topologies make direct daisy-chaining impractical
 * the deployment needs clock-aligned capture scheduling across more than one device

### Support and constraints

PTP scales better than direct FSYNC wiring, but it is less accurate than a shared hardware trigger because timing is distributed
through the network path. It also depends on network equipment that correctly handles PTP traffic.

#### RVC2

### RVC2 implementation

RVC2 does not use Ethernet-based PTP for this synchronization workflow. When an RVC2 deployment needs aligned exposure starts, use
[hardware synchronization (FSYNC)](https://docs.luxonis.com/hardware/platform/deploy/data-sync/hardware-sync.md); when software
grouping is sufficient, use [time based
synchronization](https://docs.luxonis.com/hardware/platform/deploy/data-sync/time-based-sync.md).

#### RVC4

### RVC4 implementation

RVC4 supports PTP-based device time synchronization on supported Ethernet deployments. Configure one device as the PTP master,
keep the others as slaves, and then enable `TIME_PTP` frame sync in the application so sensors use the shared clock as their
timing source and converge onto the same frame slots. By default, this aligns end of exposure; if your workflow needs
start-of-exposure alignment instead, that sync point can be changed.

> **Luxonis OS requirement**
> For PTP synchronization, update RVC4 devices to Luxonis OS `1.35.0` or newer. If your device is running an older OS version, follow the [Luxonis OS update guide](https://docs.luxonis.com/software-v3/sw-stack/luxonis-os.md) first.

> **Current sensor support**
> PTP frame was tested on `OG05`, `IMX586`, `OV9282` sensors from the latest batch. If PTP does not work in your setup, contact Luxonis support.

### PTP network equipment

PTP sync only works when the network switch supports PTP traffic. We have tested the following switches and confirmed that they
work with OAK4 PTP sync:

 * MikroTik CRS312-4C+8XG (recommended, used in our tests, requires PoE+ injectors when powering PoE devices)
 * TP-Link TL-SG1005P
 * Ubiquiti Flex 2.5G PoE (4-port variant)
 * TP-Link TL-SG1008P

In our testing, the 8-port Ubiquiti variant did not work because it blocked PTP traffic. Other switches may also work if they
explicitly support PTP packet handling. For better sync performance, use a PTP-capable switch that can prioritize PTP packets and
re-timestamp PTP packets by updating the timing correction for packet residence time inside the switch. The MikroTik CRS312-4C+8XG
is our recommended option because we have validated this type of setup on it.

#### Switch prioritization details

When the switch supports traffic classification rules, configure it to prioritize all IEEE 1588 Ethernet frames by matching the
Ethernet protocol (EtherType / MAC Protocol) value `0x88F7`.

Then map that traffic to traffic class `7` and use strict prioritization for that class. In practice, this means the rule should
apply to every IEEE 1588 frame regardless of its PTP message type, rather than only to selected Sync, Follow_Up, Delay_Req, or
Delay_Resp packets.

Each switch configures these capabilities differently, so the exact menu names, rule fields, and queue settings vary by vendor and
model. For the MikroTik CRS312-4C+8XG that we used in testing and recommend for PTP deployments, follow the steps below:

We validated PTP packet prioritization and boundary-clock operation on the MikroTik CRS312-4C+8XG. Configure it with WinBox as
follows:

 1. Install WinBox on the computer you will use to manage the switch.
 2. Connect to the switch with WinBox.
 3. Open New Terminal.
 4. Run the commands below one line at a time.

```text
/interface ethernet switch set switch1 qos-hw-offloading=yes

/interface ethernet switch qos profile
add name=PTP traffic-class=7

/interface ethernet switch rule
add switch=switch1 mac-protocol=0x88F7 new-qos-profile=PTP comment="Prioritize Layer 2 PTP"

/interface ethernet switch qos tx-manager queue
set [find where traffic-class=7] schedule=strict-priority

/system ptp
add name=ptp1 profile=default domain=0 transport=l2-forwardable delay-mode=e2e priority1=255 priority2=255 comment="PTP boundary clock"

/system ptp port
add ptp=ptp1 interface=combo1
add ptp=ptp1 interface=combo2
add ptp=ptp1 interface=combo3
add ptp=ptp1 interface=combo4
add ptp=ptp1 interface=ether1
add ptp=ptp1 interface=ether2
add ptp=ptp1 interface=ether3
add ptp=ptp1 interface=ether4
add ptp=ptp1 interface=ether5
add ptp=ptp1 interface=ether6
add ptp=ptp1 interface=ether7
add ptp=ptp1 interface=ether8
```

These commands switch QoS settings, enable QoS hardware offload, prioritize IEEE 1588 traffic by mapping EtherType `0x88F7` to
traffic class `7`, apply strict priority to that class, and configure the switch as a PTP boundary clock on the listed `combo` and
`ether` ports.

If you only want PTP on specific ports, remove the corresponding `/system ptp port add ...` lines before applying the
configuration.

### Setting it up and running

SSH onto the master device and enable master mode:

```bash
ssh root@IP_ADDRESS  # SSH into the the master device
luxonis-ptp-config enable
luxonis-ptp-config mode master
```

SSH onto the slave device and enable slave mode:

```bash
ssh root@IP_ADDRESS  # SSH into the the slave device
luxonis-ptp-config enable
luxonis-ptp-config mode slave
```

If camera configuration has been overridden from the default, also run this on every participating device:

```bash
luxonis-ptp-config sync_frames true
```

In application code, enable:

```python
cam.initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.TIME_PTP)
```

This tells the camera to use the PTP-synchronized device clock as the source for frame timing. The camera stack then continuously
adjusts the actual sensor cadence around the requested FPS so each device stays locked to the same slot on the shared timeline.
The [Sync node](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/sync.md) can then group the nearest matching
frames from those already aligned captures.

PTP sync and external FSYNC use the same `depthai-core` examples (follow instructions in
[README](https://github.com/luxonis/depthai-core/blob/main/examples/README.md) to prepare your environment for running). For PTP,
run them with the `--ptp-sync` flag:

```bash
# first follow README to prepare your environment, then
python3 examples/python/Misc/MultiDevice/multi_device_frame_sync.py --ptp-sync  # for Python
```

 * [Python multi-device frame sync
   example](https://github.com/luxonis/depthai-core/blob/main/examples/python/Misc/MultiDevice/multi_device_frame_sync.py)
 * [C++ multi-device frame sync
   example](https://github.com/luxonis/depthai-core/blob/main/examples/cpp/Misc/MultiDevice/multi_device_frame_sync.cpp)

### Observed sync accuracy

In our two OAK4-CS (with OG05B10 sensors) test setup, we observed the following sync deltas:

| Setup | Avarage sync delta | p99 sync delta |
| --- | --- | --- |
| 2x OAK4-CS | 64.12 us | 237.00 us |

In a higher-load test setup, eight OAK4-D devices (with IMX586 sensors) were connected through a MikroTik CRS312-4C+8XG switch
configured for PTP traffic prioritization and hardware re-timestamping. The devices used different video encoding modes to vary
Ethernet load. As expected, higher network congestion increased delay variation and degraded PTP synchronization accuracy. Note
that for multi-device PTP deployments, video encoding is recommended instead of streaming raw frames because lower network load
helps preserve PTP performance.

| Encoding | Resolution | Average delta | p99 delta |
| --- | --- | --- | --- |
| MJPEG | 640x480 | 113.80 us | 198.47 us |
| MJPEG | 1280x720 | 394.79 us | 829.00 us |
| H.264 | 640x480 | 58.96 us | 92.04 us |
| H.264 | 1280x720 | 63.25 us | 100.67 us |
| H.264 | 1920x1080 | 74.38 us | 115.11 us |
| H.265 | 640x480 | 73.89 us | 122.69 us |
| H.265 | 1280x720 | 62.69 us | 95.82 us |
| H.265 | 1920x1080 | 80.77 us | 120.62 us |
| H.265 | 4000x3000 | 83.97 us | 142.39 us |

These numbers are indicative rather than guaranteed. Actual sync accuracy depends on switch behavior, topology, and network load.

CAM_A synchronization delta over time for 4000x3000 H.265:

All CAMs synchronization delta over time for CAM_A=1080p, CAM_B/CAM_C=1280×800 H.265:
