Question raised
Logistics sorting and distribution, the warehouse uses guide rails to transmit goods. The goods are relatively large and need to be transported by a forklift.
Now there is a batch of goods from Shenzhen-Guangzhou-Foshan-Guangxi. A batch of goods will be unloaded by Guangzhou, and another batch will be unloaded by Foshan, and the last batch will be delivered to the end of Guangxi.
This means that when loading the car, the goods in Guangxi should be placed in the innermost, followed by Foshan and Guangzhou should be placed in the outermost.
Question, how to implement control rails through algorithms and intelligently transmit goods according to this priority to facilitate forklift handling and loading.
Note:
- 1. The goods are collected at different locations in the warehouse, through different guide rail routes, and are finally collected on the same guide rail and transmitted to the corresponding shipment port. Do not allow cargo to be transported on the rails to be confused or blocked;
- 2. There are multiple shipping ports in the warehouse. In reality, one batch will not be loaded, and then the car will be moved to another shipping port;
- 3. The task of forklifts is only responsible for loading the trucks in the order of shipment, and the work of sorting the goods destination should not be handed over to the forklifts;
Analysis results
OK, this is a typical problem that combines logistics planning, warehousing automation and algorithm scheduling. Let us analyze in detail and give a .NET implementation idea and example.
Problem analysis
- Core Objectives:Control the guide rail system in the warehouse and press a batch of specific goods (sent to Shenzhen->Guangzhou->Foshan->Guangxi)Loading the carRequiredReverse order(That is, Guangzhou goods are first shipped, Foshan goods are second, and Guangxi goods are last shipped) is accurately transported to the designated shipping port for forklifts to be loaded directly in order.
-
Key constraints:
- Loading order (LIFO):Guangxi goods inside -> Foshan goods -> Guangzhou goods outside.
- FIFO based on destination:Guangzhou goods arrive first at the shipping port -> Foshan goods -> Guangxi goods.
- Cargo distribution:The goods are located in different locations in the warehouse.
- Guide rail network:Multiple guide rails are gathered to the final outbound rail.
- Anti-blocking:Rail transmission cannot be messy or blocked.
- Multiple shipping ports:The system needs to manage multiple shipment ports and corresponding loading tasks.
- Forklift Responsibilities:Only responsible for transporting in order of arrival, not sorting.
- Intelligent scheduling:The algorithm needs to decide when and which rails enter, especially the assembly point and the final outbound rails.
Core Challenge
- Sorting and scheduling coupling:Not only do you need to know the correct order of shipment, but you also need to ensure that the goods can arrive physically in this order, and you need to use the guide rails (especially the collection point and the final guide rail section).
- Resource (rail section) conflict:Multiple items may require a certain section of the rail or a collection point at the same time.
- Path planning:You need to know the path of the goods from the starting point to the shipment port.
- Real-time:The system needs to be dynamically adjusted according to the warehouse status and rail occupation.
Algorithm/system design ideas
The system can be divided into several logical levels:
-
Order/task management:
- Receive transportation orders (Shenzhen->Guangzhou->Foshan->Guangxi).
- Determines all goods contained in this order and their location in the warehouse.
- Determines which shipment port the order is assigned to.
- The order of this order is generatedTarget outbound sequence(Guangzhou goods -> Foshan goods -> Guangxi goods).
-
Warehouse Management/Path Planning Layer (WMS/Pathfinder):
- Maintain warehouse layout model (rails, assembly points/intersections, buffer zones, shipment ports).
- Maintain the real-time location of the cargo.
- Provides path planning function: calculates the optimal/feasible rail path from the current position of the cargo to the target shipment port.
- Provides track segment occupation status query.
-
GRCS - Guide Rail Control System:
- The core intelligence layer。
- Receive from order managementTarget outbound sequenceand allocated shipping ports.
- Interact with WMS/Pathfinder to get the cargo location and path.
- Key decisions:Based on the target sequence, decideWhen will it be allowed to enter the assembly area or the final outbound rail。
- Resource lock/appointment:To prevent blockage, when a cargo is approved to enter a critical path (such as the final outbound rail), the system needs to lock/arrange the path segment until the cargo passes.
- Instructions are issued:Send instructions to the physical guide rail controller (PLC, etc.), control switches, start/stop conveyor belts, etc.
Simplify the simulation algorithm process
In a simulation environment, we can simplify this process and focus on highlightingSortandRelease in orderLogic:
-
Define the data structure:
-
CargoItem
: Represents the goods, including ID, current location, destination, order ID, and the serial number of the destination in the route. -
RouteStop
: Represents a station in the transportation route, including the city name and serial number. -
TruckLoadOrder
: Represents a loading task, including order ID, route (destination list), goods list, assigned shipping port ID, and target shipment sequence (sorted cargo ID list). -
LoadingBay
: Indicates the shipping port, including ID, current status (idle, waiting for goods, goods arrive), currently being processedTruckLoadOrder
。
-
-
initialization:
- create
TruckLoadOrder
Example, containing all goods and their destination information. - Calculate the target outbound sequence:According to the order number of the destination of the goods in the routeAscending orderSort. Destinations with small serial numbers (Guangzhou = 1) are ranked first, and those with large serial numbers (Guangxi = 3) are ranked behind.
- create
-
Scheduling simulation:
- Simulates a central controller (representing the scheduling logic of GRCS).
- Controllers process in sequence
TruckLoadOrder
target outbound sequence. - For the first shipment in the sequence (for example, a shipment in Guangzhou):
- The controller issues an instruction to the "Virtual Rail System": "Request to ship cargo X to shipment port Y".
- The Virtual Rail System simulates finding goods, planning paths (which may take time), and checking whether paths (especially the final rail section) are available.
- If the path is available, the simulated cargo starts moving. Lock the final rail section.
- Simulate shipping time.
- The goods arrive at the shipping port Y, updated
LoadingBay
The status is "Cargo Arrival". - The controller (or shipment port) notifies the "virtual forklift" to be transported.
- Simulate forklift handling time.
- After the handling is completed,
LoadingBay
The state becomes idle, releasing the final rail section. - The controller processes the next cargo in the sequence.
-
Key control points:The core of the scheduling algorithm isStrictly follow the target outbound sequenceCome and "release" the goods into the final outbound rail. Even if a cargo in Guangxi is shorter or ready earlier, it cannot be allowed to enter the final guide rail section leading to the designated shipping port before the cargo in Guangzhou or Foshan. The system needs to have it somewhere before the assembly pointwait, until it's its turn.
Example of Implementing Simulation with .NET
using System;
using;
using;
using;
using;
// --- Data structure definition ---
public enum CargoStatus
{
AtOrigin,
WaitingForDispatch, // Waiting for dispatch instructions at the starting point or buffer
EnRoute,
ArrivedAtBay,
Loaded
}
public enum LoadingBayStatus
{
Idle,
WaitingForItem, // Waiting for the next sequence of goods
ItemArriving, // The goods are entering
ItemPresent, // The goods have arrived, waiting for the forklift
ForkliftOperating // The forklift is working
}
// Goods information
public class CargoItem
{
public string Id { get; set; }
public string OriginLocation { get; set; } // Simplify to a string
public string DestinationCity { get; set; }
public int DestinationSequence { get; set; } // The serial number of the destination in the route (Guangzhou=1, Foshan=2, Guangxi=3)
public string TruckLoadOrderId { get; set; }
public CargoStatus Status { get; set; } = ;
public override string ToString() => $"Cargo {Id} (go to: {DestinationCity}, order: {DestinationSequence})";
}
// Route stop
public class RouteStop
{
public string City { get; set; }
public int Sequence { get; set; } // 1: Guangzhou, 2: Foshan, 3: Guangxi
}
// Shipping port
public class LoadingBay
{
public string Id { get; set; }
public LoadingBayStatus Status { get; set; } = ;
public string HandlingOrderId { get; set; } = null;
public string ExpectedItemId { get; set; } = null; // The currently waiting goods ID
private readonly SemaphoreSlim _accessSemaphore = new SemaphoreSlim(1, 1); // Control access to the final guide rail of the shipment port
// Simulate cargo arrival
public async Task<bool> TryOccupyForArrival(string itemId, string orderId)
{
if (!await _accessSemaphore.WaitAsync(0)) // Try to acquire the lock immediately, 0 means not waiting
{
($"Shipping port {Id} is busy and cannot receive goods {itemId}.");
return false; // If it has been occupied, it cannot enter
}
// Get the lock
Status = ;
HandlingOrderId = orderId;
ExpectedItemId = itemId; // Exactly which goods are entering
($"Shipping port {Id} is locked, ready to receive goods {itemId} (order: {orderId}).");
return true;
}
// The goods arrive completely
public void ItemArrived(string itemId)
{
if (ExpectedItemId == itemId)
{
Status = ;
($"The cargo {itemId} has arrived at the shipping port {Id}, waiting for the forklift.");
}
else
{
($"Error: The goods {itemId} that reached the shipment port {Id} is not the expected {ExpectedItemId}!");
// Error handling logic may be required
Release(); // Release the lock
}
}
// The forklift is transported and the shipment port is released
public void Release()
{
Status = ;
($"Shipping port {Id} is idle.");
ExpectedItemId = null;
HandlingOrderId = null;
_accessSemaphore.Release(); // Release the lock
}
}
// Loading orders for individual trucks
public class TruckLoadOrder
{
public string OrderId { get; set; }
public List<RouteStop> Route { get; set; }
public List<CargoItem> Items { get; set; }
public string AssignedLoadingBayId { get; set; }
public List<string> TargetDeliverySequence { get; private set; } // The goods ID sorted by destination order
private int _currentIndex = 0;
// Calculate the target outbound sequence
public void CalculateSequence()
{
TargetDeliverySequence = Items
.OrderBy(item => ) // Sort by destination number ascending order
.Select(item => )
.ToList();
}
public string GetNextItemId()
{
if (_currentIndex < )
{
return TargetDeliverySequence[_currentIndex];
}
return null; // All goods have been processed
}
public void ItemDispatched()
{
_currentIndex++;
}
public bool IsComplete() => _currentIndex >= ;
}
// --- Analog Controller ---
public class WarehouseController
{
private readonly Dictionary<string, LoadingBay> _loadingBays;
private readonly Dictionary<string, CargoItem> _allCargoItems; // Simulate cargo information in WMS
private readonly Queue<TruckLoadOrder> _orderQueue = new Queue<TruckLoadOrder>();
public WarehouseController(List<LoadingBay> bays, List<CargoItem> items)
{
_loadingBays = (b => );
_allCargoItems = (i => );
// Associate the goods with their orders (simplify processing, assuming that all goods belong to one order)
var orderId = "ORDER_SZ_GX";
var route = new List<RouteStop>
{
new RouteStop { City = "Guangzhou", Sequence = 1 },
new RouteStop { City = "Foshan", Sequence = 2 },
new RouteStop { City = "Guangxi", Sequence = 3 }
};
foreach (var item in items)
{
= orderId;
var stop = (r => == );
= ;
}
var truckOrder = new TruckLoadOrder
{
OrderId = orderId,
Route = route,
Items = items,
AssignedLoadingBayId = ().Id // Assigned to the first shipment port
};
();
_orderQueue.Enqueue(truckOrder);
}
public async Task RunSimulation()
{
("Start the warehouse scheduling simulation...");
while (_orderQueue.Count > 0)
{
var currentOrder = _orderQueue.Peek(); // View the next order, but not remove it
var bay = _loadingBays[];
if (())
{
($"Order {} Completed loading.");
_orderQueue.Dequeue(); // Complete, process the next order
continue;
}
// Check whether the shipping port is idle and you can receive the next item
if ( == )
{
string nextItemId = ();
if (nextItemId != null)
{
CargoItem itemToDispatch = _allCargoItems[nextItemId];
// Key: Try to occupy the shipment port, and only if you succeed can you truly dispatch the goods
if (await (, ))
{
// The occupation is successful, the goods have been dispatched, and the transportation is simulated
(); // Move to the next
($"Controller: Approve scheduling {itemToDispatch} to shipment port {}");
= ; // Update status
// Start an asynchronous task to simulate cargo transportation and processing
_ = (async () => await SimulateItemTransportAndHandling(itemToDispatch, bay));
}
else
{
// The shipping port is busy, waiting for the next cycle inspection
($"Controller: Shipping port {} Busy, {itemToDispatch} cannot be dispatched for the time being.");
await (500); // Wait for a while and try again
}
}
}
else
{
// The shipping port is not idle, wait
// ($"Controller: Waiting for shipping port {} idle...");
await (1000); // Wait for the shipment port to complete processing
}
}
("All orders are processed and the simulation is over.");
}
// Simulate the transport of individual goods and forklift handling
private async Task SimulateItemTransportAndHandling(CargoItem item, LoadingBay bay)
{
($"Rail System: Start transporting {item} from {} to {}...");
= ;
await ((GetRandomDuration(2, 5))); // Simulate transportation time
// The goods arrive at the shipping port
= ;
(); // Notify that the goods at the shipment entrance are at the door
// Simulate forklift operation
if ( == )
{
($"Forklift: Start transporting {item} from shipment port {}...");
= ;
await ((GetRandomDuration(3, 6))); // Simulate the forklift handling time
= ;
($"Forklift: Completed transport {item}.");
(); // Release the shipment port and allow the next cargo to enter
}
}
private Random _random = new Random();
private int GetRandomDuration(int minSeconds, int maxSeconds)
{
return _random.Next(minSeconds, maxSeconds + 1);
}
}
// --- Main program ---
public class Program
{
public static async Task Main(string[] args)
{
= .UTF8;
// 1. Initialize the repository element
var loadingBays = new List<LoadingBay>
{
new LoadingBay { Id = "Bay-01" }
// More shipping ports can be added
};
var cargoItems = new List<CargoItem>
{
// Note: Id is only available, OriginLocation is only an example
new CargoItem { Id = "GZ-001", OriginLocation = "Area A", DestinationCity = "Guangzhou" },
new CargoItem { Id = "FS-001", OriginLocation = "Area B", DestinationCity = "Foshan" },
new CargoItem { Id = "GX-001", OriginLocation = "Area C", DestinationCity = "Guangxi" },
new CargoItem { Id = "GZ-002", OriginLocation = "Area D", DestinationCity = "Guangzhou" },
new CargoItem { Id = "FS-002", OriginLocation = "Area E", DestinationCity = "Foshan" },
new CargoItem { Id = "GX-002", OriginLocation = "Area F", DestinationCity = "Guangxi" },
new CargoItem { Id = "GZ-003", OriginLocation = "Area A", DestinationCity = "Guangzhou" }
};
// 2. Create and run the controller
var controller = new WarehouseController(loadingBays, cargoItems);
await ();
("Press any key to exit...");
();
}
}
Code explanation and key points:
-
Data structure:Clear classes are defined to represent goods, shipment ports, orders, etc.
CargoItem
Contains the destination and sequence number in the route (DestinationSequence
), this is the key to sorting. -
()
:This is the core sorting logic. Using LINQOrderBy
according toDestinationSequence
Sort goods ascending order to generate a list of goods IDsTargetDeliverySequence
. This represents the order in which the goods should arrive at the shipping port. -
WarehouseController
:Simulate the central scheduling system.- It holds an order queue
_orderQueue
。 - exist
RunSimulation
In a loop, it checks the target sequence of the current orderTargetDeliverySequence
, find out the next item to be dispatched (GetNextItemId
)。 -
Key Controls:It checks the target shipment (
LoadingBay
) Is it idle (Status ==
)。 -
:This method uses
SemaphoreSlim
To simulate exclusive access to the final rail section of the shipment port. If the shipping port is busy (the semaphore has been occupied),TryOccupyForArrival
returnfalse
, the controller will wait,Won'tIssue a dispatch command. The controller only approves the dispatch of the goods and updates the order progress after the shipping port is idle and the semaphore is successfully obtained (ItemDispatched
)。 -
Asynchronous simulation:use
and
Simulating time-consuming operations (transportation, forklift handling) makes the simulation closer to reality.
- It holds an order queue
-
LoadingBay
:Represents the status of the shipment port and usesSemaphoreSlim
Control access to oneself and ensure that only one cargo can enter or stay in the shipping port area at a time. -
Limitations of simulation:
- Detailed rail network path planning and conflict detection were not implemented. It assumes that once the controller approves the dispatch, the underlying "virtual rail system" can manage to deliver the goods, and only focus on itFinal shipping port rail sectionoccupancy control.
- Error handling is relatively simple.
- Random time simulation is not accurate enough.
- No exceptions that may occur during the cargo are handled.
Summarize
The core of this solution is:
- Pre-calculate the correct order of outbound storage:Based on the LIFO loading principle, the destination order is launched (Guangzhou -> Foshan -> Guangxi).
- Central control and release one by one:The controller strictly follows the calculated order, and only one correct piece of goods is approved (release) at a time to enter the final rail section leading to the designated shipping port.
-
Resource locking:Use similar semaphores (
SemaphoreSlim
) mechanism to ensure that the final rail section and shipment port are occupied by one cargo, and other goods (even if they are ready) cannot enter and must wait.
In this way, the system ensures that the order in which the goods arrive at the shipment port is consistent with the expected loading order of the forklift, avoids chaos and blockage, and leaves the complexity of the sort to the algorithm and control system, rather than the forklift operator. A real system would be much more complex than this simulation, requiring more sophisticated path planning, conflict detection and real-time state synchronization, but the basic logic is similar.