Multi-robot control for warehouse sorting

Status
Completed
Period
Summer 2026
Role
R&D intern, Libiao Robotics

Situation

A sorting warehouse runs many small robots on one grid. Each accepts only short commands such as move forward, turn and stop, so every route becomes a sequence of them. The hard part is the shared floor: robots that meet in an aisle can wait for each other forever.

The first version of the simulation mixed traffic data into the map itself; a second, layered version separated the parts.

Role

R&D intern, Jun–Aug 2026. Worked on a simulation-based multi-robot control system for warehouse sorting, integrating task scheduling, path planning, traffic control, and robot communication.

Constraints

The second version started from constraints, not from a number of layers.

  • Robots accept only forward, turn and stop, so the planner prices every turn as time.
  • The simulated robot behaves like hardware: it accelerates, brakes and confirms every command.
  • The operator window is only a view; the rest must run without it.

Process and architecture

Running the first version

These captures use synthetic tasks in my personal planning frontend. The architecture and time reservations described afterward belong to the second version.

The running simulator with colored AGV routes, a populated robot status list and dispatch logs.
My personal planning frontend running synthetic work, with active routes, vehicle states and dispatch logs. This capture uses the first version.Main branch · runtime screenshot ·
The sorting task panel with pickup and dropoff settings, return-home control and a populated task queue.
Sorting tasks queued in the simulator. The image is cropped to the original task panel.Main branch · runtime screenshot detail ·

Layers the build can check

Reorganized an existing operational simulation into six layers and added seven architecture tests to improve maintainability. Control logic sees robots only through a driver interface. The tests read the compiled code and fail the build if a layer uses one above it or business logic reads the system clock.

The second version's layers, from top to bottom. Composition: wiring and tests. Client: map view and operator window; a warehouse system was designed but not built. Control: motion and traffic control; tasks and network protocols were designed but not built. Device: the driver interface and the simulator; a real-robot driver was designed but not built. Domain: grid map and path planners. Foundation: contracts, clock and messaging. Each layer uses only the layers below it, and a test fails the build otherwise. Composition Wiring and tests Client Map view, operator window Warehouse system Control Motion, traffic control Tasks, network protocols Device Driver interface, simulator Real-robot driver Domain Grid map, path planners Foundation Contracts, clock, messaging Built Designed, not built Uses only the layers below; a test fails the build otherwise
The second version's layers, from top to bottom. Composition: wiring and tests. Client: map view and operator window; a warehouse system was designed but not built. Control: motion and traffic control; tasks and network protocols were designed but not built. Device: the driver interface and the simulator; a real-robot driver was designed but not built. Domain: grid map and path planners. Foundation: contracts, clock and messaging. Each layer uses only the layers below it, and a test fails the build otherwise. Composition Wiring and tests Client Map view, operator window Warehouse system Control Motion, traffic control Tasks, network protocols Device Driver interface, simulator Real-robot driver Domain Grid map, path planners Foundation Contracts, clock, messaging Built Designed, not built Uses only the layers below; a test fails the build otherwise
Each layer may use only the layers below it, and a test fails the build when a reference points upward. Dashed parts were designed but not built during the internship.Second version · redrawn from the internship codebase ·

Traffic control booked in time

The first version locked only the next cell. Robots meeting head-on in an aisle each held the cell the other needed, so neither could move. Its fallback painted the blocking cell as a wall on the shared map, misleading every other planner.

In the second version, a robot books its whole route before moving: every cell, with the time window it will be there. The planner searches over cells and time, so it can plan a wait or a detour. Conflicts surface at booking, not when robots are already nose to nose.

Bookings are all or nothing, and a stopped robot keeps its cell booked so others can see it. A wait graph and a collision check remain as backstops.

A schematic head-on case: one aisle, cells a to e, with a side bay f next to cell d. Robot A heads east from a; robot B heads west from e. Left, each robot locks only the next cell: they meet in the middle, each holds the cell the other needs, and neither moves again. Right, each robot books cells together with times: B's planner sees A's bookings, steps into the bay, waits there while A passes, then continues west. No cell is booked by both robots at the same time. a b c d e f A B A heads east; B heads west. The side bay f opens off cell d. Lock the next cell time a b c d e f A A A A A A A A A B B B B B B B B B Book cells and times time a b c d e f A A A A A A A A A B B B B B B B B B Each robot holds the cell the other one needs. B's plan waits in the bay; no cell is booked twice at once.
A schematic head-on case: one aisle, cells a to e, with a side bay f next to cell d. Robot A heads east from a; robot B heads west from e. Left, each robot locks only the next cell: they meet in the middle, each holds the cell the other needs, and neither moves again. Right, each robot books cells together with times: B's planner sees A's bookings, steps into the bay, waits there while A passes, then continues west. No cell is booked by both robots at the same time. a b c d e f A B A heads east; B heads west. The side bay f opens off cell d. Lock the next cell time a b c d e f A A A A A A A A A B B B B B B B B B Each robot holds the cell the other one needs. Book cells and times time a b c d e f A A A A A A A A A B B B B B B B B B B's plan waits in the bay; no cell is booked twice at once.
Locking only the next cell lets robots trap each other in one aisle. Booking cells with times lets the second robot plan its wait in the bay before it moves.Schematic · not a real map ·

A learned speed layer

On my own initiative, I added a learned local layer: a PPO policy adjusts each robot's speed along its A* path. (simulation only; not covered by my supervisor's written confirmation) It ran on the first version: A* still chose each route and cell locks still gated each move; the policy only set speed.

The PPO panel showing inference mode, the actor and critic architecture, recent actions and kinematic settings.
The learned local layer running in inference mode with the saved model. The image is cropped to the original ML panel.Main branch · runtime screenshot detail ·
The active PPO training panel with configured episode and fleet settings, progress bars, rewards and a reward curve.
A short training demonstration with live progress and reward traces. The original UI has a defect in its average-loss display; these captures document execution, not convergence.Main branch · runtime screenshot detail ·
The reward chart and state-feature list for the PPO layer, including position, route, LiDAR, neighboring robots and motion constraints.
Reward traces and the model's state-feature groups, captured lower in the same ML panel.Main branch · runtime screenshot detail ·

Results and evidence

Validated the architecture by replacing GDI+ with SkiaSharp through changes limited to the rendering layer. It was a planned test: drawing code that leaked into other layers would have forced edits there.

Diagnosed deadlocks and rebuilt traffic control around spatiotemporal reservations, validating 20 robots over 90,000 simulation ticks without a collision. That is one long run with random destinations. It does not prove that deadlock is impossible, that throughput rose, or that real robots would be safe.

With four robots, the trained policy cleared all conflicts and deadlocks and cut average task time from 35.4 s to 26.6 s. (one fixed-seed simulation run per scenario, against the same run with the learned layer off; task time also fell with six robots and in a head-on corridor; throughput never dropped below the baseline; with six robots, conflicts rose from 1 to 6; traffic control resolved them and no task failed)

Reflection and next

The learned layer’s result was mixed, and one fixed-seed run per scenario cannot separate a better policy from a lucky one.

Writing each stage’s acceptance check before its code kept the second version honest. Fault injection, run replay, and the task and network layers were designed but not built.

Boundaries

Company code is not public. The runtime screenshots show my personal planning frontend with synthetic tasks. The promotional visualization at the top is not an interface capture; the architecture and reservation figures are redrawn schematics. Everything here ran in simulation; none of it is a claim about physical robots.

My supervisor confirmed in writing the statements about my role, scope, layers, rendering swap and traffic run; the learned layer is not among them.