Two-way ranging measures the distance between two UWB devices directly, by timing a three-frame exchange — no clock synchronisation between them is required.
It is the default ranging method on Leantegra anchors and tags, selected by the UWB RTLS method parameter (1 = TWR, 2 = TDoA).
Each completed exchange yields one distance in centimetres between the two devices.
A position needs a range to at least three anchors, but the poll and the final are broadcast once rather than repeated per anchor. Every anchor in range hears the same poll, replies in its own response window, and hears the same final:
| Per anchor | Total for n anchors | |
|---|---|---|
| Polls | — | 1, broadcast |
| Responses | 1 | n, staggered into separate windows |
| Finals | — | 1, broadcast |
| Turnaround delays | — | 2 |
The turnaround count is what makes this matter. Each delay costs 1300 µs whatever the PHY, so holding the total at two rather than two-per-anchor removes airtime no radio setting could recover. It is also why the saving grows with anchor count: a fourth anchor adds one response window, not a whole exchange.
An anchor that does not hear the poll simply does not respond, and the position is formed from those that did — a missing anchor costs nothing beyond its own empty window.
A single round trip would work only if both clocks ran at exactly the same rate. They do not — a crystal offset of a few parts per million becomes centimetres of error over a ranging interval.
The second round trip lets the responder cancel that drift: the reply delays measured on each side appear in both halves of the calculation, so the clock-rate error divides out instead of accumulating. This is why the exchange is three frames rather than two.
One complete exchange occupies:
airtime = 2 × sendPollResponseDelay + finalFrameDuration
sendPollResponseDelay already includes the poll duration. This figure sizes the TDMA slot guard time only; it never affects a measured distance.
The default physical layer, applied across the UWB device line:
| Parameter | GATT | Value |
|---|---|---|
| Channel | 0x510A | 4 (3993.6 MHz) |
| Data rate | 0x510B | 850 kbps |
| Preamble length | 0x510C | 2048 |
| PRF | 0x510D | 16 MHz |
| PAN | 0x510E | deployment-specific |
Channel 4 provides roughly 4.2 dB more link budget than channel 7 in free space. At 850 kbps a single-anchor exchange takes about 9.6 ms and a three-anchor position about 14.6 ms; at 110 kbps both take roughly half as long again, because the payload is sent 7.7× slower.
The data-rate enumeration is LowDR = 1, MidDR = 2, HighDR = 3. Radio parameters persist to flash immediately but take effect after the next restart, and antenna delay is calibrated per product for the channel in use.
The same PHY settings apply to UWB TDoA; the ranging method is selected separately by 0x5106.
TWR capacity is bounded by conversations: a position is one exchange that occupies the medium exclusively — a broadcast poll, a response from each anchor, a broadcast final. The whole exchange runs inside one TDMA slot, so capacity is how many slots fit in a second:
locations per second = ranging slots ÷ superframe period
concurrent tags = locations per second ÷ update rate
One position is a broadcast poll, n staggered responses and a broadcast final, with two turnarounds:
position = 2 × frame + 2 × PollResponseDelay + n × response window
frame = preamble + SFD + PHR + payload
2600 µs of every position is fixed — the response delay applied twice, regardless of anchor count — and the rest follows the PHY. Preamble dominates at long preamble lengths, payload dominates at low data rates:
| PHY | Preamble | SFD + PHR | Payload | Frame | Position — 3 anchors |
|---|---|---|---|---|---|
| 110 kbps, 2048 | 2035 µs | 255 µs | 1455 µs | ≈ 3.74 ms | ≈ 22.1 ms |
| 850 kbps, 2048 — default | 2035 µs | 33 µs | 188 µs | ≈ 2.26 ms | ≈ 14.6 ms |
| 850 kbps, 512 | 509 µs | 33 µs | 188 µs | ≈ 0.73 ms | ≈ 7.1 ms |
| 6.8 Mbps, 256 | 254 µs | 33 µs | 23 µs | ≈ 0.31 ms | ≈ 5.0 ms |
Preamble length is fixed airtime regardless of data rate, which is why dropping from 2048 to 512 at the same 850 kbps roughly halves the frame. At 110 kbps the payload becomes the larger term instead.
A fourth anchor adds one response window — about 2.5 ms at the default PHY — rather than a further 9.6 ms exchange of its own. That is what keeps redundancy affordable.
Frame durations assume a 20-byte payload; the final carries one reply timestamp per anchor and is correspondingly longer. Devices log their measured figures at start-up, and a bench capture is the way to confirm them for a specific build.
A position needs several ranges, so a slot holds several exchanges. One exchange gives one distance, and a distance is not a position — trilateration needs at least three anchors. The count is a runtime parameter,max_anchor_num_twr(0x5110, range 3–255, default 3), and it multiplies the slot budget directly:
slot = exchange × anchors per tag + guard
Four working points, with a 10% guard in a 500 ms superframe. Both columns count ranging slots only — the beacon and contention window take three slots of every superframe, see Unified TDMA:
| Profile | Data rate | Preamble | Position | Tags per second (per anchor) | Locations per second (3 anchors) |
|---|---|---|---|---|---|
| Maximum range | 110 kbps | 2048 | ≈ 22.1 ms | ≈ 56 | ≈ 34 |
| Long range — default PHY | 850 kbps | 2048 | ≈ 14.6 ms | ≈ 84 | ≈ 52 |
| Balanced | 850 kbps | 512 | ≈ 7.1 ms | ≈ 160 | ≈ 118 |
| High capacity | 6.8 Mbps | 256 | ≈ 5.0 ms | ≈ 244 | ≈ 160 |
| Column | Slot holds | Answers |
|---|---|---|
| Tags per second (per anchor) | a poll, one response, a final | how many ranges one anchor can service — proximity and zone use, where a distance is enough |
| Locations per second | a poll, three responses, a final | how many positions a site can produce — trilateration needs three ranges |
The gap between the columns is the cost of turning distances into coordinates — around 1.6× rather than the 3× a per-anchor exchange would cost, because the poll and final are shared. At 2 Hz per tag, halve the locations figure for the tag count: the default PHY carries 26 tags at 2 Hz.
Tags and update rate trade directly: at the default PHY, 10 tags at 2 Hz and 20 tags at 1 Hz cost the same airtime.
The slot column assumes a 10% guard. Confirm the position duration on a bench unit before committing a schedule — devices log their measured frame and delay figures at start-up.
max_anchor_num_twr is a ceiling, not a count. A tag ranges with anchors until it reaches that many and then stops looking. It is set once for a deployment, and the slot is sized to it:
| Cap | Budget | Slot | Locations/s | Tags at 2 Hz |
|---|---|---|---|---|
| 2 — distances only, no position | 12.1 ms | 14 ms | ≈ 64 | 32 |
| 3 — minimum for a 2D position, default | 14.6 ms | 17 ms | ≈ 52 | 26 |
| 4 — 3D, or redundancy against blockage | 17.1 ms | 19 ms | ≈ 46 | 23 |
| 6 — dense overlap | 22.1 ms | 25 ms | ≈ 34 | 17 |
A site with mixed anchor density needs no reconfiguration. The schedule is sized once for the cap and every area works within it: where only two anchors are in range a tag ranges with two and leaves the rest of its slot idle; where six are in range it stops at the cap. Tags roaming between a two-anchor rail run, a three-anchor bay and a four-anchor cell all share one schedule.
The consequence is that the cap is a worst-case figure. Raising it from 3 to 4 costs every tag in the deployment a third of its capacity, including tags in areas that never see a fourth anchor — so raise it only if the extra anchor is genuinely needed for accuracy or blockage tolerance.
Note also that two anchors give distances but not a position. An area with only two anchors in range produces ranges the backend can use for a constrained solution — a rail, where one dimension is already known — but not a free 2D fix.
The guard absorbs three things, and none of them are large:
| Source | Magnitude |
|---|---|
| Clock drift between a device and the schedule | ≈ 20 µs over a 500 ms superframe at ±20 ppm |
| Receiver enable margin | tens of µs |
| Inter-slot processing on the MCU | the dominant term |
None of these scale with exchange length, so a percentage guard is a convenience rather than physics. At 10% it is 1.5 ms on the default profile, which is comfortable — but only 0.4 ms at the fastest, where processing time does not shrink to match. Treat 0.5 ms as a floor regardless of percentage, and confirm the real figure on a bench unit before committing a schedule.
Shortening a frame removes the energy that gave it reach, so the two columns trade directly. Range figures are indicative, for clear line of sight, and should be confirmed by survey:
Fieldbus Anchor — no front-end amplification, uplink through a WiFi module:
| Profile | Locations/s | Range per anchor | Limited by |
|---|---|---|---|
| Maximum range | ≈ 34 | ≈ 85–140 m | airtime |
| Long range — default | ≈ 52 | ≈ 60–100 m | airtime |
| Balanced | ≈ 118 | ≈ 30–50 m | airtime |
| High capacity | ≈ 160 | ≈ 15–25 m | airtime — but see below |
At the high-capacity profile the UART uplink carries the traffic comfortably — 71 tags per second means 213 frames per second on the uplink — three ranges per position — against a 480 ceiling. The blocking send then costs roughly 440 ms of every second of the anchor's main loop, which is worth budgeting for on a master also running a fieldbus chain.
Locator Pro — PA / LNA on UWB and BLE, Ethernet uplink:
| Profile | Locations/s | Range per anchor | Limited by |
|---|---|---|---|
| Maximum range | ≈ 34 | ≈ 420–700 m | airtime |
| Long range — default | ≈ 52 | ≈ 300–500 m | airtime |
| Balanced | ≈ 118 | ≈ 150–250 m | airtime |
| High capacity | ≈ 160 | ≈ 75–125 m | airtime |
Locator Pro holds roughly 5× the range at every profile, so it can take a faster PHY and still cover more ground than an unamplified anchor manages at the default — the balanced profile on Locator Pro still reaches further than a Fieldbus Anchor at long range. Its uplink carries the result without spending main-loop time.
Antenna delay is calibrated per product for the channel and PHY in use. Moving between profiles without recalibrating shows up as a constant distance offset on every measurement.
Where a site needs both high tag counts and reach, UWB TDoA is the structural answer rather than a PHY change: it is bounded by transmissions instead of conversations, and scales an order of magnitude further on the same radio settings.
Locator Pro changes both sides of the calculation.
Range. Its PA / LNA front ends amplify both UWB and BLE, so one anchor covers substantially more ground than an unamplified unit. For TWR this does not raise the measurement ceiling — that is set by airtime — but it reduces the number of anchors needed to cover an area, and therefore the number of cells a large site has to be divided into.
Backhaul. Measurements have to leave the anchor as well as be made. Locator Pro uplinks directly over Ethernet LAN rather than through a chain:
| Backhaul | Constraint on measurement rate |
|---|---|
| CAN-FD chain | shared bus at 125 kbit/s by default; every slave's results cross it, and the bit rate is capped by chain length |
| WiFi | shared medium, variable latency, contention with other site traffic |
| Ethernet LAN | not a practical limit at these rates |
On a chained deployment the backhaul can bind before the UWB airtime does — see the worked example on the CAN-FD page. With Locator Pro the UWB schedule is the only ceiling worth planning against.