
Maria Santos
Infrastructure Lead
Maria oversees Kavod's distributed systems infrastructure, building resilient platforms that serve millions across Africa.
Why Autonomous Freight Matters for Africa
Africa's rail freight infrastructure has been chronically underinvested for decades. Moving goods from Mombasa to Kampala takes an average of 14 days by conventional rail — roughly the same speed as in 1975. Meanwhile, road haulage is expensive, dangerous, and responsible for a disproportionate share of carbon emissions on the continent.
Kavod Rail was founded to change that equation. Our thesis is straightforward: by layering autonomous control systems on top of existing rail corridors, we can dramatically improve throughput, reliability, and cost-per-tonne-km — without waiting for entirely new track to be built.
This post covers the technical architecture behind our autonomous freight pilot, which completed its first 600 km corridor run in January 2026.
The Autonomous Routing Engine
Problem Formulation
Rail routing is fundamentally a constrained optimization problem. Given a set of freight orders (origin, destination, tonnage, priority, deadline), the routing engine must assign orders to trains and compute schedules that minimize total cost while respecting:
- Track capacity constraints — single-track sections require careful scheduling to avoid conflicts
- Locomotive power constraints — maximum trailing tonnage depends on gradient, curvature, and consist configuration
- Maintenance windows — certain track sections are offline during scheduled maintenance
- Customs and border dwell times — cross-border corridors introduce stochastic delays
We model this as a mixed-integer linear program (MILP) and solve it using Google OR-Tools with a custom branching heuristic tuned for our problem structure.
from ortools.linear_solver import pywraplp
def build_routing_model(orders, trains, track_graph):
solver = pywraplp.Solver.CreateSolver("SCIP")
# Decision variables: x[o][t] = 1 if order o is assigned to train t
x = {}
for o in orders:
for t in trains:
x[o.id, t.id] = solver.BoolVar(f"x_{o.id}_{t.id}")
# Each order assigned to exactly one train
for o in orders:
solver.Add(sum(x[o.id, t.id] for t in trains) == 1)
# Capacity constraints per train
for t in trains:
solver.Add(
sum(o.tonnage * x[o.id, t.id] for o in orders) <= t.max_tonnage
)
# Objective: minimize weighted delivery time + fuel cost
objective = solver.Objective()
for o in orders:
for t in trains:
cost = estimate_cost(o, t, track_graph)
objective.SetCoefficient(x[o.id, t.id], cost)
objective.SetMinimization()
solver.Solve()
return extract_assignments(x, orders, trains)For real-time re-routing (e.g., when a track section is unexpectedly blocked), we fall back to a faster greedy heuristic with local search that produces solutions within 5% of optimal in under 200 ms.
Corridor Optimization
Not all corridors are equal. We rank corridors using a composite score that factors in:
- Freight demand density (tonnes/km/year)
- Track condition (surveyed via our inspection drones)
- Electrification status (diesel vs. electric traction)
- Political and regulatory readiness
Our first pilot corridor — Mombasa to Nairobi (SGR) — scored highest on all four dimensions. The second corridor, Dar es Salaam to Dodoma, is scheduled for Q2 2026.
Safety Systems
Autonomous rail is only viable if it is demonstrably safer than human-operated trains. Our safety architecture follows a defense-in-depth model with three independent layers.
Layer 1: Perception
Each locomotive is equipped with:
- Forward-facing LiDAR (Velodyne VLP-32C) — 200 m range, 360° horizontal FoV
- Stereo camera pair — 1080p, used for visual confirmation and object classification
- Thermal camera — critical for detecting livestock and people on the track at night
- Radar — long-range (800 m) obstacle detection, works through rain and dust
Sensor data is fused in real-time using an extended Kalman filter running on an NVIDIA Orin module. The fused perception output is a 3D occupancy grid updated at 20 Hz.
Layer 2: Decision and Control
The decision layer implements a finite state machine (FSM) with clearly defined states:
| State | Description | Transition Condition | |---|---|---| | CRUISE | Normal operation at target speed | Default | | APPROACH | Reducing speed near stations/junctions | Proximity trigger | | CAUTION | Reduced speed, obstacle in far zone | LiDAR/radar alert | | EMERGENCY_BRAKE | Full service brake application | Obstacle in near zone | | STOPPED | Train at standstill | Zero velocity confirmed |
Transitions between states are governed by hard-coded rules — no ML in the safety-critical loop. Machine learning is used upstream for perception, but the actual braking decision is deterministic and formally verified.
Layer 3: Remote Oversight
A human operator at the Kavod Rail Operations Centre in Nairobi monitors all autonomous trains via a real-time dashboard. The operator can override any decision, issue a remote emergency stop, or take manual control via a low-latency satellite link (Starlink).
We maintain a maximum 1.2-second round-trip latency for remote override commands. If connectivity is lost for more than 5 seconds, the train automatically enters EMERGENCY_BRAKE state.
Sensor Fusion in Detail
Fusing data from four different sensor modalities is non-trivial. Each sensor has different latencies, noise characteristics, and failure modes. Our fusion pipeline handles this with a three-stage architecture:
- Per-sensor preprocessing — Each sensor has a dedicated processing thread that converts raw data into a common coordinate frame (train-centric, East-North-Up).
- Temporal alignment — We use hardware-triggered timestamps (PTP-synchronized) and interpolate sensor readings to a common 50 Hz clock.
- Bayesian fusion — The extended Kalman filter maintains a probabilistic estimate of each detected object's position, velocity, and class. When sensors disagree, the filter naturally weights the more reliable sensor based on its noise model.
LiDAR ──> Preprocessing ──┐
Camera ──> Preprocessing ──┤
Thermal ─> Preprocessing ──┼──> Temporal Align ──> EKF Fusion ──> Occupancy Grid
Radar ───> Preprocessing ──┘In our testing, the fused system achieved a 99.7% detection rate for obstacles larger than 0.5 m at distances up to 150 m, with a false-positive rate below 0.3%.
Pilot Results
The first autonomous run covered 472 km from Mombasa to Nairobi carrying 2,800 tonnes of containerized freight. Key metrics:
- Journey time: 8.2 hours (vs. 12+ hours typical for crewed trains on the same corridor)
- Fuel consumption: 14% lower than crewed baseline (smoother acceleration/braking profiles)
- Safety incidents: Zero
- Remote operator interventions: 3 (all precautionary, none required emergency braking)
What's Next
We are working with the Kenya Railways Corporation and the Tanzania Railways Corporation to expand autonomous operations to additional corridors. On the technology side, our priorities for 2026 are:
- V2I communication — enabling the train to receive real-time signal and switch status from trackside infrastructure
- Platoon mode — running multiple autonomous trains in close succession on the same corridor to maximize throughput
- Predictive maintenance — using onboard vibration sensors and wheel-flat detectors to schedule maintenance before failures occur
Learn more about Kavod Rail at kavodrail.com.
Try Kavod Rail today
Discover how Kavod Rail can help you build better, faster. Get started for free and see the difference.
Get Started

