В пункты получения сортировочного логистического центра непрерывно поступают посылки, которые роботы должны сортировать - развести в соответствующие пункты назначения центра.
Сортировочный центр - прямоугольная площадка, разделённая на клетки, некоторые из которых помечены, как пункты получения и назначения для посылок. Также возможно указать, что роботы не могут находится на клетке - это стена.
Роботы могут двигаться вперед и поворачиваться в одном из 4 направлений. Роботы выполняют действия по командам системы управления за различные, заданные моделью, дискретные времена:
- бездействие (время задается системой управления)
- движение на одну клетку вперед
- поворот на 90 градусов
- взятие посылки (в пункте получения)
- сдача посылки (в пункте назначения)
В момент получения посылки роботом, случайным образом выбирается её пункт назначения - куда нужно отвести.
Столкновением роботов считается одновременное использование одной клетки двумя роботами:
- находятся в одной клетке
- движутся в одну клетку
- один движется в клетку, в которой находится другой
- один движется в клетку, откуда движется другой
-
предполагается, что уже установлены:
- python 3.12
- simpy (библиотека python)
-
перейти в нужную директорию, например в домашнюю:
cd ~
-
склонировать репозиторий:
git clone https://github.com/juk-r/robotic-sorting.git
-
добавить в PYTHONPATH, например для linux:
export PYTHONPATH="${PYTHONPATH}:~/robotic-sorting"
-
запустить пример:
python robotic-sorting -map "robotic-sorting/data/small_map.json" -type "robotic-sorting/data/example/robot-type.json" -position "robotic-sorting/data/example/position.json" -distribution "robotic-sorting/data/example/distribution.json" -algorithm "robotic-sorting/brains/random_brain.py" -mode run -time 1000
-
проверить, что в консоль выведено количество посылок:
11
Запуск производится командой следующего вида (из директории содержащей robotic-sorting
):
python robotic-sorting -map FILE -type FILE -position FILE -distribution FILE -algorithm FILE -mode {run,record,average} -time TIME [-output OUTPUT] [-count COUNT]
с параметрами:
-map
- файл конфигурации карты-type
- файл конфигурации типа роботов, времен действий-position
- файл конфигурации расположения роботов-distribution
- файл конфигурации распределения вероятности-algorithm
- файл алгоритма-time
- модельное время, которое будет работать модель-mode
- тип запускаrun
- выводит количество доставленных посылокrecord
- выводит все действия роботов в форматеcsv
, рекомендуется указывать файл выводаaverage
- выводит количество доставленных посылок и стандартное отклонение при указанном количестве запусков
-output
- файл в который выводится результат, по умолчанию выводится в стандартныйstdout
-count
- количество запусков для типаaverage
Конфигурация задается несколькими .json
файлами и выбранным алгоритмом. Запуск производится из консоли.
Конфигурация склада задается файлом .json
, соответствующим схеме, содержит:
span
- расстояние между клеткамиcells
- прямоугольный двумерный массив клеток (1 координата - строка сверху вниз, 2 координата - столбец слева направо), каждая из которых содержит необязательные:free
- может ли робот находиться, по умолчанию может:true
inputId
- уникальный номер пункта получения, по умолчанию его нетoutputId
- уникальный номер пункта назначения, по умолчанию его нет
Можно посмотреть пример карты.
Конфигурация задается файлом .json
, соответствующим схеме, содержит:
timeToMove
- время для движения вперед на 1 клеткуtimeToTurn
- время для поворота на 90 градусовtimeToTake
- время, чтобы взять посылкуtimeToPut
- время, чтобы положить посылку
Можно посмотреть пример.
Конфигурация задается файлом .json
, соответствующим схеме, содержит:
robots
- список, элементы которого содержат:id
- необязательный idx
- позиция по 1 координате, считая с 0y
- позиция по 2 координате, считая с 0direction
- направление одно из:up
- вверхleft
- влевоdown
- внизright
- вправо
Можно посмотреть пример.
Для каждого пункта получения определяется распределение вероятностей пунктов назначений для поступающих посылок файлом .json
, соответствующим схеме, содержит:
distribution
объект, в котором:- ключ - уникальный номер пункта получения или "other" для всех незаданных
- значение "uniform" - равномерное распределение
- значение - объект:
- ключ - уникальный номер пункта назначения или "other", тогда у незаданных пунктов назначений будет равномерное распределение
- значение - вероятность это пункта назначения
Можно посмотреть пример распределения.
Модель разделена на 2 части: сменная система управления и модель (управляемого) склада.
До запуска, модель склада:
- считывает файлы конфигурации,
- расставляет роботов и уведомляет о каждом систему управления,
- запрашивает у системы управления первое действие для каждого робота,
Во время исполнения, модель повторяет следующее:
- проверяет возможность выполнения полученного действия робота.
- если возможно, выполняет действие робота
- если действие не может быть выполнено, возникает ошибка или оповещается система управление в зависимости от вида ошибки,
- когда действие закончилось, запрашивает следующее действие у системы управления,
Когда моделирование закончено, то есть прошло заданное время или доставлено заданное количество посылок, модель склада выводит требуемые результаты.
- /brains/ - алгоритмы управления
- /mail_factories/ - генераторы посылок
- /maps/ - карты, основная и дополнительные которые хранят дополнительную информацию
- /mail_factories/ - генераторы посылок для пунктов получения.
- /structures.py - неизменяемые структуры данных
- /modelling.py - основной класс
Model
, связывающий остальные классы и получающий управление после получения команды моделирования. - /brains/brain.py - абстрактный класс
Brain
, описывающий интерфейс системы управления. - /maps/map.py - карта склада
Map
хранит статическую информацию. - /cell.py - класс
Cell
, реализующий клетку карты - /robot.py - робот
Robot
, выполняющий действия.
- Для каждого робота модель резервирует клетку, соответствующую начальному положению.
- Для каждого робота модель вызывает
Brain.new_robot
. - Для каждого робота модель узнает первое действие: вызывает
Brain.get_next_action
.
Производится вызовом методов класса Model
:
run_for_time
- для моделирования в течении заданного времениrun_for_mails
- для моделирования заданного количество посылок
После того, как модель получило очередное действие очередного робота, она выполняет это действие следующим образом:
- бездействовать: модель добавляет событие, что робот закончит действие через заданное время
- двигаться: модель резервирует следующую клетку, добавляет событие через нужное для перемещения время, отменяет резервирование предыдущей клетки.
- если следующей клетки не существует, возникает исключение
PositionOutOfMap
- если данное действие приведет к столкновению, то оно не выполняется и вызывается метод системы управления
collision_callback
, затем зановоget_next_action
.
- если следующей клетки не существует, возникает исключение
- повернуть: добавляет событие через нужное для поворота время.
- взять: модель пытается забрать посылку, вызывая
Cell.get_input
и добавляет событие через нужное для получения время.- если у робота уже есть посылка, возникает
DoubleMailTake
- если клетка не является пунктом получения, возникает
NotInputCell
.
- если у робота уже есть посылка, возникает
- положить: модель пытается положить посылку и добавляет событие через нужное для сдачи время.
- если у робота нет посылки, возникает
MailToPutAbsence
- если направление посылки не совпадает с пунктом назначения или клетка не является пунктом назначения, возникает
IncorrectOutput
.
- если у робота нет посылки, возникает
После обработки очередного действия очередного робота, модель узнает для этого робота новое действие, вызывая Brain.get_next_action
.
Модель системы управления необходимо реализовать на python специальным классом, который наследуется от класса Brain
и состоит из методов:
new_robot(Robot)
, вызывается моделью склада для каждого добавленного робота до запуска модели.get_next_action(Robot) -> Robot.Action | (Robot.Action.idle, int)
, вызывается моделью склада для каждого робота, метод возвращает предстоящее (одно из 5) действие для данного робота.- Для бездействия, возвращается дополнительный параметр - время бездействия.
collision_callback(Robot) -> None
, вызывается моделью склада, если полученное действие не может быть выполнено. Не обязательный метод, если метод не представлен, то действие, приводящее к столкновению, вызывает исключение.
В файле .py
, содержащем выбранный алгоритм, должен быть один и только один класс, наследованный от Brain
.
Модель система управления может получить всю информацию о текущем состоянии модели склада из поля _model
(экземпляр класса Model
), которое содержится в классе Brain
.
Класс Model
содержит неизменяемую часть - карта склада - поле map
(экземпляр класса Map
), и переменною - состояние роботов - поле robots
(список роботов - экземпляры класса Robot
).
Карта склада может быть получена из полей карты Map
:
inputs
- список координат пунктов полученияoutputs
- список координат пунктов назначениеinputs_ids
- список id пунктов получениеoutputs_ids
- список id пунктов назначенияheight
,width
- размеры карты поx
иy
- метод
has(Position)->bool
- проверка существования клетки с заданной координатой - метод
[Position]
(индекс) - получить клетку (экземпляр классаCell
).
Каждая клетка содержит неизменяемые поля:
free
(bool
) - может ли робот находиться на нейinput_id
(int
) - id пункта получения илиNone
, если нетoutput_id
(int
) - id пункта назначения илиNone
, если нетreserved
(bool
) - какой-то робот зарезервировал клетку - использует, другие не могут в нее перемещаться.
Каждый робот, содержит неизменяемые поля, соответствующие конфигурации:
id
(str | None
) - id робота, заданный конфигурацией. Если не задан, то будетNone
type
RobotType
- тип робота, информация о свойствах робота:type.time_to_move
(int
) - время, чтобы проехать 1 клеткуtype.time_to_turn
(int
) - время, чтобы повернуть на 90 градусовtype.time_to_take
(int
) - время, чтобы взять посылкуtype.time_to_put
(int
) - время, чтобы положить одну посылку
Поскольку переменная часть модели состоит только из состояния роботов, то о текущем состоянии модели склада можно узнать из полей класса Robot
. (Список всех роботов находится в self._model.robots
):
position.x
,position.y
- целые координаты клетки, на которой находится робот (начиная с 0)direction
одно из 4 направление (Direction
)mail
(Mail
) - посылка, которую везет робот илиNone
, если нет посылки:mail.id
(int
)- уникальный номер посылкиmail.destination
(int
) - направление, в которое нужно доставить