# Item sorter robot

:::{commons-figure} https://commons.wikimedia.org/wiki/File:UR16e_robot_arm.png
:figwidth: 35%
:align: right
A robot arm with the pendant.
:::


Robot arms can automatize industrial processes like [sorting trash for recycling](https://youtube.com/shorts/h5mPruRoEWY) and [manufacturing cars](https://www.dailymotion.com/video/x8qgyps). In this problem we are going to do neither of these two but build up on the top of the [inventory system](inventory-system) instead and prepare an order for shipment.

Previously we built a GUI for order processing. Now, the robot will automatically collect the items in an order in a box after an order is processed as follows.

{#item-positions}
The robot picks first one type three types of countable items which are in the boxes represented by `a`, `b` and `c`. After picking them, the arm places them in the shipment box represented by `S`:

```
 0  1  2  3 ️→ (y)
 1  a
 2  b  
 3  c     S
 4
 ↓
(x)
```
Note that the x and y axis are rotated according to the coordinate system of the robot. In the simulator 🟥, 🟩, and 🟦 colored dashed lines are x, y and z axis, respectively.

The robot picks one items from `a`, two items from `b` and one item from `c` according to the first order.

:::{video} ../img/ISv2SorterRobot.webm
Inventory system sorter robot demonstration.
:::

:::{note}
This problem assumes that you have installed [the robot simulator](project:#robot-simulator).
:::

Requirements and assumptions:
1. Continue code from the previous project ([inventory system](inventory-system)). You already committed the inventory system project, so the state of the old project will not be lost. 

   :::{warning}
   Do not create a new solution and build up on the previous one.
   :::
1. Assume that your orders can have up to three countable items, which are placed in inventory boxes `a`, `b`, `c`. The shipment box is placed on `S`. So you have to pick items in the order from the inventory boxes and place them in the shipment box `S`:
1. Use the following class:

  :::{literalinclude} ../code-wi/ISv2SorterRobot/Robot.cs 
  :language: cs
  :::

1. Create a class `ItemSorterRobot` that inherits from `Robot`. 

   `ItemSorterRobot` includes a configurable URScript template `UrscriptTemplate` that has a placeholder `{0}` which represents the x coordinate of the item that has to be picked. We don't need another parameter, because y-coordinate of the item boxes are the same and the shipment boxes position is also fixed. `UrscriptTemplate` could look like this:
   
   ```cs
       public const string UrscriptTemplate = @"
   def move_item_to_shipment_box():
       SBOX_X = 3
       SBOX_Y = 3
       ITEM_X = {0}
       ITEM_Y = 1
       DOWN_Z = 1
   
       def moveto(x, y, z = 0):
       ...
   "
   ```
   
   `SBOX` stands for shipment box, `ITEM` for the item types and `DOWN` for the down movement for picking up the items from the item boxes. `_X` and `_Y` correspond to x, y coordinates, respectively.

   `UrscriptTemplate` is used by the method `PickUp(uint itemId)`. You can insert `itemId` to the `UrscriptTemplate` by using `string.Format(UrscriptTemplate, itemId)` like we have seen in section {ref}`strings` and then send the resulting program using `Robot.SendUrscript()`.
   
1. You have to get the list of order lines from an order so you can control the robot program accordingly. For example, `ProcessNextOrder` could return a list of order lines.

1. Whenever you send a program, the old program is overwritten. As we don't have any feedback from the robot, use about 10 seconds for each movement to complete.

  If you use `Thread.Sleep(10000)`, then the GUI will freeze until the end of the sleep. You can use `Task.Delay()` as an alternative, but you have to write `async` in the function definition as follows:
  
  ```cs
    public async void Button_OnClick()
    {
        StatusMessages.Text += "Processing order" + Environment.NewLine;
        foreach (var orderLine in OrderBook.ProcessNextOrder())
            for (var i = 0; i < orderLine.Quantity; ++i)
            {
                StatusMessages.Text += $"Picking up {orderLine.Item.Name}" + Environment.NewLine;
                robot.PickUp(orderLine.Item.InventoryLocation);
                await Task.Delay(9500);
            }
    }
  ```
  
  `async` makes a function *asynchronous*. Asynchronous functions do not stop program execution (e.g., GUI) while doing operations themselves.
  
1. For the item box coordinates use the positions [above](#item-positions). The distance between 0-1, 1-2 etc, is 10 cm.

   For example, the origin of the coordinate system drawn [above](#item-positions) corresponds to the robot tool coordinates `(0, 0.1)`. So `a` would be at position `(0 + 0.1, 0.1)` and `b` at `(0 + 2 * 0.1, 0.1)`.

1. For picking up, the robot needs to move down 10 cm.

   Don't care about grabbing and releasing the item – assume there is an tool attached to the robot and it automatically picks up and releases the items. So you don't have to care about this.

1. Add an additional field `uint InventoryLocation` to `Item`. This is the location of the item in the inventory which we will use to pick up items from with the robot arm.

1. Test your system with the following objects and code:

   ```cs
        var item1 = new UnitItem
        {
            Name = "M3 screw",
            PricePerUnit = 1,
            InventoryLocation = 1
        };
        var item2 = new UnitItem
        {
            Name = "M3 nut",
            PricePerUnit = 1.5m,
            InventoryLocation = 2
        };
        var item3 = new UnitItem
        {
            Name = "pen",
            PricePerUnit = 1,
            InventoryLocation = 3
        };
        var orderLine1 = new OrderLine
        {
            Item = item1,
            Quantity = 1
        };
        var orderLine2 = new OrderLine
        {
            Item = item2,
            Quantity = 2
        };
        var orderLine3 = new OrderLine
        {
            Item = item3,
            Quantity = 1
        };
        var order1 = new Order
        {
            OrderLines = [orderLine1, orderLine2, orderLine3],
            Time = DateTime.Now - TimeSpan.FromDays(2)
        };
        var order2 = new Order
        {
            OrderLines = [orderLine2],
            Time = DateTime.Now
        };

        var customer1 = new Customer
        {
            Name = "Ramanda",
            Orders = []
        };
        var customer2 = new Customer
        {
            Name = "Totoro",
            Orders = []
        };


        customer1.CreateOrder(OrderBook, order1);
        customer2.CreateOrder(OrderBook, order2);
    ```

1. Assume that the shipment boxes are automatically moved by a conveyor belt after one order is processed. In other words, there is an empty box waiting at shipment box position after you are done with the previous order.

1. Optional: Add a `TextBlock` which shows status messages as shown in the video.
1. Include the updated class diagram
1. Create a video