People often describe the challenge of running a battery-swap network as a routing problem. Get a charged pack from point A to point B in time for a rider. That framing is too narrow. By the time you are routing, you are already reacting. The interesting problem is pre-positioning: getting a charged pack to the right station before the rider needs it, not after they have already arrived and found an empty slot.
The difference in rider experience between these two modes is significant. A reactive routing model means a rider arriving at a station, finding nothing ready, and waiting for either a pack to finish charging or a logistics run to deliver one. A pre-positioning model means the pack is there when the rider arrives. The 90-second swap only happens when inventory has been correctly pre-staged. Getting that pre-staging right is where most of the engineering work lives.
The Input Signal: What the Dispatch Engine Reads
Our dispatch engine runs on three main input categories. The first is historical demand patterns by corridor and hour. Over the course of our Pune pilot, we accumulated swap event logs that tell us which stations see demand spikes at which times on which days of the week. A station near a restaurant cluster sees predictable demand every day between 11am and 1pm. A station near a consumer electronics hub sees higher demand on weekend afternoons. These patterns are not perfectly stable, but they are stable enough to be useful for pre-staging decisions 20-30 minutes in advance.
The second input category is real-time location data from riders who have the BatteryPool app active. We can see when a cluster of registered riders is moving toward a corridor, which gives us advance notice before demand actually appears at the station. This matters during event-driven demand spikes: a major delivery platform pushing a flash sale, a train station with delayed departures, anything that moves riders toward a zone before normal demand would predict it.
The third input is current station inventory state: how many charged packs are in each slot, how many are currently in the charge cycle, and the projected completion time for packs currently charging. This is the hardest part to get right because pack charge completion time is not fixed. A pack at 40% State of Health completes a cycle faster than one at 95% SoH because the usable capacity window is smaller. The dispatch engine has to account for this to avoid staging decisions based on nominal charge times that do not reflect actual pack state.
The Pre-Positioning Decision Logic
The core decision the dispatch engine makes is: which station needs a charged pack queued, and when. This is a prioritization problem across 12+ stations with variable current inventory levels, variable incoming demand signals, and a fleet of packs in various stages of the charge cycle at the depot and at station chargers.
We frame this as a demand coverage score per station per time window. A station with three charged packs available and low incoming demand scores low priority for additional staging. A station with one charged pack available and a demand signal showing five riders within 2 km heading toward it in the next 30 minutes scores high. The dispatch engine reorders this priority queue every few minutes and queues pack delivery or repositioning decisions accordingly.
In practice, the decisions the engine makes most often are modest: pre-charge a pack that is sitting at 60% at a high-demand station before it is needed, rather than waiting until a rider has taken the last fully charged pack. The dramatic cases, a sudden demand spike requiring emergency repositioning of packs, are relatively rare in steady-state operations. The value of the system is mostly in eliminating the slow accumulation of small coverage gaps, not in heroic last-minute logistics.
What the Engine Gets Wrong
Honest evaluation of any demand prediction system has to start with where it fails. Our current model struggles most with demand events that have no historical precedent at a given location. If a new delivery platform signs up five riders who all work the same neighborhood corridor, our model will underpredict demand there until we have accumulated enough swap event data to build a reliable pattern. During that ramp-up period, riders may find lower availability than they would expect in a more established corridor.
We also see degraded prediction quality during irregular weather conditions. A day of heavy rain in Pune changes rider behavior in ways our historical patterns do not cleanly model. Some riders stop entirely, others push harder because delivery demand stays elevated while supply drops. The net effect on any given station is hard to predict from historical data alone because the interaction of these factors varies.
The right mental model for fleet operators using our network is: in established corridors with 3-6 months of swap history, pre-positioning reliability is high. In newer corridors or during unusual demand conditions, treat availability as "likely but not guaranteed" and check the app for real-time station inventory before heading to a station if the swap is time-critical.
Where We Are Taking This
The current dispatch engine was built to handle the Pune pilot geography: 12+ stations, three partner fleets, and a handful of individual riders with known usage patterns. Scaling to a larger city or a denser station network will require rethinking some of the assumptions in the current model, particularly around how we handle overlapping demand from multiple independent fleets using the same corridors.
We are also building toward tighter integration with fleet management systems. If a fleet operator's dispatch software knows which riders are being sent where on which shifts, that information is significantly more useful than a location ping alone. We have REST API hooks in our Fleet Pro tier for this reason. The more context the dispatch engine has about planned rider activity, the earlier it can begin staging inventory to support it.