AnyLogic
Развернуть
Размер шрифта

Программное создание нестандартного маршрута

Транспортеры в режиме навигации по заданным путям двигаются из одной точки в другую по выбранному маршруту. Информация о маршруте хранится в объекте RouteData. Он содержит список задач по движению. Каждая задача описывает движение транспортера по одному сегменту маршрута. Сегмент заканчивается, когда меняется тип движения. Существуют три типа движения:

С помощью этого объекта можно задать маршрут транспортера, используя функцию findShortestPath(), и получить информацию о заданном пути, вызвав функцию getRouteData().

Пример нестандартной маршрутизации

Демо-модель: Custom Routing for Transporters Открыть страницу модели в AnyLogic Cloud. Там можно запустить модель или скачать ее по ссылке Исходные файлы модели.

В этом примере мы продемонстрируем способы создания нестандартных маршрутов для транспортера (мобильного робота).

Мы смоделировали перемещение материальных объектов между двумя узлами. Узлы объединены в сеть с помощью трех путей разной длины. В диаграмме процесса данное перемещение задается с помощью блока MoveByTransporter из Библиотеки производственных систем.

Объекты перемещаются из узла node1 в узел node2 с помощью одного мобильного робота, который задан с помощью блока TransporterFleet. Мы задаем правила движения материального робота в блоке TransporterControl. Выбрав опцию Другая для параметра Навигация в свойствах этого блока, мы можем указать наш собственный алгоритм маршрутизации для мобильного робота. Алгоритм описан в функции setRoute(source, target, unit). В свойствах блока TransporterControl мы переключаем параметр Найти путь в режим редакции динамического значения и размещаем здесь вызов нашей функции.

Функция должна возвращать объект RouteData, поэтому в свойствах функции мы выбрали опцию Возвращает значение и указали RouteData в поле Тип. В секции свойств Аргументы мы задали следующие аргументы:

ILocation source — Аргумент, передающий точку, в которой мобильный робот начинает движение по маршруту.
ILocation target — Аргумент, передающий точку, в которой мобильный робот завершает движение по маршруту.
AGV agv — Аргумент, задающий наш мобильный робот.

Эта функция используется для задания маршрута, и потому вызывается каждый раз, когда мобильный робот начинает движение.

Алгоритм маршрутизации в нашем примере выглядит следующим образом:

// проверка текущего состояния мобильного робота
if (agv.getState() == TransporterState.DELIVERING)
{
  switch (radio.value)
  {
    case 0:
      // использование маршрута по умолчанию
      return transporterControl.findShortestPath(source, target, null, null);
    case 1:
    {
      // использование маршрута по умолчанию за исключением заданных путей
      Path[] avPaths = {path1};
      // список avPaths передает алгоритму исключенные из маршрута пути
      return transporterControl.findShortestPath(source, target, null, avPaths);
    }
    case 2:
    {
      // создание структуры данных, где будет храниться нестандартный маршрут
      RouteData route = new RouteData();
      
      // первое задание по движению: из центра узла node1 на границу узла node1
      Point source1 = new Point(100.0, 100.0, 0.0);
      Point target1 = new Point(100.0, 110.0, 0.0);
      route.addPlainMovement(node1, source1, target1);

      // второе задание по движению: по пути path2
      route.addPathMovement(path2, 0.0, 78.0, METER);

      // третье задание по движению: внутри узла node2
      Point source2 = new Point(700.0, 110.0, 0.0);
      Point target2 = new Point(700.0, 100.0, 0.0);
      route.addPlainMovement(node2, source2, target2);

      return route;
    }
    default:
      return null;
  }
}
// использование кратчайшего пути, чтобы вернуться в базовое местоположение
else return transporterControl.findShortestPath(source, target, null, null);

В этом примере вы можете выбрать один из трех способов задать маршрут с помощью переключателя. Мы используем оператор switch в алгоритме маршрутизации, чтобы задать по одному маршруту для каждой кнопки переключателя. Целочисленное значение, используемое в каждом случае, — это индекс соответствующей кнопки. Обратите внимание, что индексация начинается с нуля.

С помощью оператора мы задаем три секции кода.

Использование стандартного маршрута

По умолчанию транспортеры в AnyLogic выбирают кратчайший маршрут, чтобы достигнуть цели. В этом примере мобильный робот использует кратчайший путь как маршрут доставки материального объекта, если в переключателе выбрана опция Default routing (shortest route).

Мы задаем этот маршрут, вызывая функцию findShortestPath() блока TransporterControl и передавая следующие аргументы:

ILocation source — Место, где мобильный робот начинает движение по маршруту.
ILocation target — Место, куда двигается мобильный робот.
null — Мы не хотим исключать из нашего маршрута какие-то узлы, поэтому передаем здесь null.
null — Мы не хотим исключать из нашего маршрута какие-то пути, поэтому передаем здесь null.

Исключение путей и узлов из стандартного маршрута

При создании маршрута для транспортера может возникнуть необходимость исключить те или иные пути или узлы, но при этом все-таки выбрать кратчайший путь к цели. В этом примере, выбрав в переключателе опцию Exclude path1, мы говорим мобильному роботу выбрать кратчайший маршрут доставки материального объекта, но исключить из этого маршрута путь path1.

Сначала мы создаем локальную переменную avPaths (массив элементов типа Path). В нашем примере этот массив содержит лишь один элемент — путь path1. Чтобы задать несколько путей, перечислите их через запятую в фигурных скобках.

Path[] avPaths = {path1};

Затем мы вызываем функцию findShortestPath() снова, но на этот раз передаем нашу локальную переменную avPaths в качестве последнего аргумента, чтобы исключить заданный путь из маршрута.

return transporterControl.findShortestPath(source, target, null, avPaths);

В AnyLogic также есть возможность включить в маршрут заданные пути с помощью функции findShortestPath(ILocation source, ILocation target, Node[] nodesToAvoid, Path[] pathsToAvoid, Path[] pathsToInclude).

Создание нестандартного маршрута с помощью объекта RouteData

Вы можете создать маршрут транспортера «с нуля», вручную задав все необходимые задания по движению и поместив их в объект RouteData. Таким образом вы сможете максимально управлять движением транспортера.

В этом примере мы используем такой подход, чтобы задать маршрут доставки материальных объектов по пути path2. Этот маршрут используется, если в переключателе выбрана опция Custom route.

Сначала мы объявляем новый объект RouteData:

RouteData route = new RouteData();

Затем мы создаем первое задание по движению: движение типа PLAIN из центра узла node1 в точку соединения узла node1 и пути path2.

Мы задаем две локальные переменные, в которых будут храниться точка начала движения (source1) и точка завершения движения (target1). Аргументы передают X-, Y-, Z- координаты точки. Мы задаем source1, в котором будет храниться центральная точка узла node1, и target1, в котором будет храниться точка соединения узла node1 и пути path2.

Point source1 = new Point(100.0, 100.0, 0.0);
Point target1 = new Point(100.0, 110.0, 0.0);

Мы используем функцию addPlainMovement() объекта RouteData, чтобы создать задание по движению и добавить его в маршрут.

route.addPlainMovement(node1, source1, target1);

У этой функции есть следующие аргументы:

  • Сетевой элемент, в котором происходит движение.
  • Точка начала движения.
  • Точка завершения движения.

Вторая задача по движению описывает движение типа PATH по пути path2:

route.addPathMovement(path2, 0.0, 78.0, METER);

Чтобы добавить в маршрут задачу по движению типа PATH, мы используем функцию addPathMovement() объекта RouteData.

У этой функции есть следующие аргументы:

  • Путь, по которому происходит движение.
  • Расстояние между точкой на пути, где начинается движение, и начальной точкой пути. В данном случае движение начинается в начальной точке пути, поэтому мы передаем значение 0.0.
  • Расстояние между точкой на пути, где завершается движение, и начальной точкой пути. Длина пути должна задаваться в указанных единицах длины. В этом примере мы рассчитываем длину пути в метрах. В масштабе по умолчанию (1 метр = 10 пикселям) длина пути path2 составляет 78 метров.
  • Константа для единиц измерения длины.

Третье задание по движению описывает движение типа PLAIN из точки соединения пути path2 с узлом node2 в центр узла node2.

Задание маршрута для возвращения в исходное местоположение

Алгоритм говорит мобильному роботу выбирать кратчайший маршрут каждый раз, когда он должен вернуться в исходное местоположение. Такое поведение задается с помощью оператора if и проверки текущего состояния мобильного робота: если мобильный робот в настоящий момент доставляет материальный объект, он будет двигаться по одному из маршрутов, описанных выше. В любом другом состоянии он будет использовать кратчайший маршрут, заданный с помощью функции findShortestPath().

// проверка текущего состояния мобильного робота
if (agv.getState() == TransporterState.DELIVERING)
{ // секция кода, где описываются правила, согласно которым мобильный робот выбирает маршрут для доставки }
else return transporterControl.findShortestPath(source, target, null, null);
Как мы можем улучшить эту статью?