Перенесу в свою тему некоторые сообщения, которые я разместил в теме
http://roboforum.ru/forum102/topic17000.html т.к. по сути дела это есть продолжение моей работы над автономным роботом. Переношу еще и потому, чтобы не злоупотреблять гостеприимством автора этой темы Scorpio.
Приведу цитату из главы 2.4. книги Рассела и Норвига "Искусственный интеллект Современный подход", ссылку на которую я давал ранее.
"Простейшим видом агента является простой рефлексный агент. Подобные агенты выбирают действия на основе текущего акта восприятия, игнорируя всю остальную историю актов восприятия."
Видимо, написание сценария для робота-лунохода в качестве такого простейшего агента-робота можно обсуждать в данной теме. О других , более сложных видах интеллектуальных агентов можно говорить после разбора этого простейшего вида.
У такого робота в наличии должен иметься базовый набор рефлексов - простейших поведений. Каждый рефлекс я запишу в виде простого продукционного правила ЕСЛИ-ТО:
-----------------------Правила----------------------------
-------------------Правила миссии 1-----------------------
Правило01: ЕСЛИ МИССИЯ=МИССИЯ1 ТО СоздатьФакт(ВПЕРЕД1)
Правило02: ЕСЛИ МИССИЯ=МИССИЯ1 И ФАЗА=ВПЕРЕД1 ТО Вперед(ВПРАВО1, 50)
Правило03: ЕСЛИ МИССИЯ=МИССИЯ1 И ФАЗА=ВПРАВО1 ТО Вправо(ВЛЕВО1, 30)
Правило04: ЕСЛИ МИССИЯ=МИССИЯ1 И ФАЗА=ВЛЕВО1 ТО Влево(ЗВУК1, 80)
Правило05: ЕСЛИ МИССИЯ=МИССИЯ1 И ФАЗА=ЗВУК1 ТО Звук(СТОП, "ОК")
--------------End of Правила миссии 1---------------------
--------Правила рефлекторного поведения робота------------
------------------Сенсорные правила-----------------------
Правило06: ЕСЛИ ПРЕПЯТСТВИЕ=ПОЯВИЛОСЬ ТО СоздатьФакт(ПАУЗА), Звук(NULL, "Ошибка: препятствие")
Правило07: ЕСЛИ ПРЕПЯТСТВИЕ=ИСЧЕЗЛО ТО СоздатьФакт(ПРОДОЛЖИТЬ)
--------------End of Сенсорные правила--------------------
------------------Эффекторные правила---------------------
Правило08: ЕСЛИ ДЕЙСТВИЕ=СТОП ТО Стоп()
Правило09: ЕСЛИ ДЕЙСТВИЕ=ПАУЗА ТО Пауза()
Правило10: ЕСЛИ ДЕЙСТВИЕ=ПРОДОЛЖИТЬ ТО Продолжить()
------------End of Эффекторные правила--------------------
-----End of Правила рефлекторного поведения робота--------
-----------------End of Правила---------------------------
-----------Исполнительный механизм робота-----------------
Представим исполнительный механизм робота (его эффекторы) в виде набора специальных функций, принимающих на вход два параметра:
1. Значение шаблона факта ДЕЙСТВИЕ, который нужно создать просле окончания выполнения функции
2. Числовое значение, необходимое для выполнения этой функции.
Например, функция Вперед(ВПРАВО1, 50) после своего успешного выполнения должна выдать факт ВПРАВО1. Результатом выполнения должно быть перемещение робота вперед на 50 каких-то единиц измерения, например, см.
Еще исполнительный механизм должен не просто выполнять функцию, а иметь возможность приостановки своей работы в случае выполнения встроенной в него функции Пауза() или полной отмены выполнения текущей функции при выполнеии функции Стоп().
Функция Продолжить() продолжает выполнение приостановленной функции, если таковая имеется.
Исполнительный механизм робота работает асинхронно по отношению к основному циклу движка продукционных правил.
-------End of Исполнительный механизм робота--------------
----Принципы действия движка продукционных правил---------
1. Движок состоит из списка шаблонов правил (см выше Правила), списка поступивших в программу фактов, FIFO очередь экземпляров сработавших правил (Agenda), и некоторых других вспомогательных узлов.
2. В простейшем случае в бесконечном цикле программа последовательно просматривает список шаблонов правил и если находит правило, в котором участвуют имеющиеся факты, то создает экземпляр правила, которому назначает эти факты. Каждый такой экземпляр правила попадает в Agenda.
3. С другого края Agenda программа забирает правило и выполняет его.
4. Один и тот же набор фактов не может повторно привести к срабатыванию одних и тех же правил, иначе программа зациклится.
--End of Принципы действия движка продукционных правил----
--------Функционирование робота без препятствий-----------
1. Вначале в программе нет никаких фактов и никакое правило не выполняется.
2. Для старта сценария Миссия1 нужно ввести в список фактов факт МИССИЯ1.
3. После этого сработает Правило01, после выполнения которого появится факт ВПЕРЕД1.
4. Сработает Правило02, т.к. в программе по-прежнему имеется факт МИССИЯ1 и появился новый факт ВПЕРЕД1, после выполнения которого появится факт ВПРАВО1, а робот выполнит перемещение вперед на 50.
5. И т.д. вплоть до выполнения последнего правила миссии1 Правило05.
6. Итог: видим работу обычного конечного автомата с тем отличием, что он основан на правилах и специальном вспомогательном факте типа ФАЗА.
--------End of Функционирование робота без препятствий----
--------Функционирование робота с препятствиями-----------
1. Вначале в программе нет никаких фактов и никакое правило не выполняется.
2. Для старта сценария Миссия1 нужно ввести в список фактов факт МИССИЯ1.
3. После этого сработает Правило01, после выполнения которого появится факт ВПЕРЕД1.
4. Сработает Правило02, т.к. в программе по-прежнему имеется факт МИССИЯ1 и появился новый факт ВПЕРЕД1, после выполнения которого появится факт ВПРАВО1, а робот выполнит перемещение вперед на 50.
5. Допустим, что во время выполнения функции перемещения вперед на 50 в программу помещается факт типа ПРЕПЯТСТВИЕ со значением ПОЯВИЛОСЬ.
6. Сработает Правило06, которое создает факт ПАУЗА и передает исполнительному механизму на выполнение функцию Звук(NULL, "Ошибка: препятствие")
7. Сработает Правило09, которое приведет к паузе в работе робота.
8. Робот будет бездействовать до того момента, пока в него не поступит факт типа ПРЕПЯТСТВИЕ со значением ИСЧЕЗЛО.
9. Это приведет к срабатыванию Правило07, которое разрешает исполнительному механизму продолжить свою работу.
10. Выполнение миссии1 продолжится вплоть до выполнения последнего правила Правило05.
11. Итог: работу ЛЮБОЙ миссии на основе конечного автомата в любой момент может прервать какое-нибудь неожиданное событие и если реакция на него предусмотрена в роботе, это прерывание будет корректно обработано.
-----End of Функционирование робота с препятствиями-------
При таком подходе видим выделенные явным образом следующие элементы:
1. Базу знаний в виде набора шаблонов правил.
2. Набор данных (факты), которые управляют ходом выполнения программы.
3. Универсальный движок продукционных правил, который в реальной конструкции не такой простой как в примере.
4. Сенсорная подсистема робота.
5. Эффекторный механизм.
В свою очередь, база знаний делится на несколько частей, первая из который (Миссия1) интересует нас сейчас больше всего
Вот имплементация Лунохода вместе с простейшим симулятором и средой разработки на языке CLIPS под Windows в том виде, как было описано выше:
Здесь все то же, но с исходниками CLIPS в проекте для MSVS2010:
Небольшое пояснение.
1. Все, что в этих файлах, не требует никакой инсталляции.
2. Все файлы представлены в кодировке ANSI.
3. После скачивания файлов рекомендую на всякий случай проверить их антивирусом.
4. Скачав и распаковав файл по первой ссылке можно зайти в каталог Lunochod1 и запустить файл CLIPSIDE.exe
5. После запуска в верхнем меню программы CLIPS 6.3 File->Load Batch... можно выбрать файл Lunochod1NoBarrier.bat
6. Начнет выполняться bat файл, который загрузит из вложенного каталога Lunochod1 программные модули на языке CLIPS.
7. После успешной загрузки всех модулей программа автоматически стартует и после выполнения выдаст в окне Dialog Window лог своей работы.
8. В этом логе заглавными буквами выводится название модуля, затем через два двоеточия собственно логируемая информация.
9. При повторном запуске программы можно выбрать файл Lunochod1Barrier.bat в котором симулятор устанавливает и убирает препятствие на пути лунохода.
10. Для удобства тех, кто по каким-то причинам не пожелает запустить программу, в том же самом каталоге, где расположены модули, я разместил текстовые файлы с логами Mission1BarrierLog.txt и Mission1NoBarrierLog.txt.
11. В логах видно, что в цикле чередуется работа модулей MAIN, SIMULATOR, MISSION, SENSOR, SOLVER, EXECUTOR.
Более подробное пояснение работы программы исмеет смысл делать, если кто-то проявит интерес.
12. Для языка CLIPS у меня имеется достаточно книг и другой документации в т.ч. на русском языке, которой я легко поделюсь, если кому-то она понадобится.
13. На основе данного простейшего проекта можно создать более сложные сценарии и внутреннюю организацию робота.
14. CLIPS легко может работать под разными ОС включая Android, поэтому следующим шагом можно было бы перейти к аппаратной реализации лунохода, чтобы не погрязнуть в симуляторах. Это можно обсудить отдельно.
Поясню программу Лунохода1, которую я представил чуть выше.
Язык CLIPS позволяет с помощью специального bat файла выполнять некоторые операции.
Ниже представлен файл Lunochod1NoBarrier.bat:
- Код: Выделить всё • Развернуть
(defmodule MAIN (export deftemplate ?ALL))
(load Lunochod1/Main.ecl)
(load Lunochod1/SimulatorNoBarrier.ecl)
(load Lunochod1/Mission1.ecl)
(load Lunochod1/Sensor.ecl)
(load Lunochod1/Solver.ecl)
(load Lunochod1/Executor.ecl)
(reset)
(run )
в котором первая строка сообщает, что все шаблоны фактов модуля MAIN экспортируются и становятся доступными для использования в других модулях. В каждом модуле работает отдельный движок продукционных правил, поэтому чтобы передать что-то из одного модуля в другой, нужно экспортировать требуемые конструкции.
Затем последовательно загружаются все файлы с модулями программы.
В конце командой reset очищается память, а командой run программа стартует начиная с модуля MAIN.
Файл Main.ecl с модулем MAIN
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.0
;;; MAIN Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Главный модуль программы.
;;;======================================================
; Система должна работать циклически, поэтому нужен факт cycle, обозначающий текущий номер цикла
(deffacts MAIN::cycle-start
(cycle -1) ; Начальное значение номера цикла
)
;;;======================================================
(defrule MAIN::Cycle-Start
(cycle -1)
=>
(printout t "MAIN::Program Lunochod started" crlf)
)
(defrule MAIN::Cycle-Next ; Правило, определяющее последовательность работы всей программы.
?f <- (cycle ?current-cycle)
=>
(retract ?f)
(bind ?next-cycle (+ ?current-cycle 1))
(assert (cycle ?next-cycle))
(printout t "MAIN::Cycle=" ?next-cycle crlf)
(focus SIMULATOR MISSION SENSOR SOLVER EXECUTOR)
)
Язык CLIPS позволяет писать модульные программы, чем я и воспользовался. В программе Lunochod1 имеются следующие модули: SIMULATOR MISSION SENSOR SOLVER EXECUTOR.
Начнем анализ программы с модуля MAIN.
Перед стартом программы в памяти размещается факт cycle со значением -1 в конструкции deffacts MAIN::cycle-start.
Рассмотрим на примере самого первого правила программы как устроены правила и как они работают:
- Код: Выделить всё • Развернуть
(defrule MAIN::Cycle-Start
(cycle -1)
=>
(printout t "MAIN::Program Lunochod started" crlf)
)
Шаблон правила задается ключевым словом defrule. MAIN:: определяет принадлежность правила какому-то модулю. В нашем случае это модуль MAIN. Далее следует название правила: Cycle-Start.
После названия следует условная часть правила (ЕСЛИ). (cycle -1) означает, что если в памяти будет обнаружен факт cycle со значением -1, то правило сработает.
Знак => означает ТО и разделяет условия и действия, которые требуется совершить в случае срабатывания правила.
В нашем случае происходит вывод в консоль (символ t) текста "MAIN::Program Lunochod started", который завершается переводом строки (символ crlf).
Как только программа обнаружит в рабочей памяти факт cycle со значением -1, то по шаблону правила Cycle-Start будет создан объект - экземпляр правила, у которого условная часть заполнена конкретными значениями условий.
Правило Cycle-Next:
- Код: Выделить всё • Развернуть
(defrule MAIN::Cycle-Next ; Правило, определяющее последовательность работы всей программы.
?f <- (cycle ?current-cycle)
=>
(retract ?f)
(bind ?next-cycle (+ ?current-cycle 1))
(assert (cycle ?next-cycle))
(printout t "MAIN::Cycle=" ?next-cycle crlf)
(focus SIMULATOR MISSION SENSOR SOLVER EXECUTOR)
)
Правило Cycle-Start после использования факта cycle не уничтожает его, а правило Cycle-Next командой (retract ?f) делает это. После этого рабочая память фактов становится пустой. Однако с помощью (assert (cycle ?next-cycle)) правило Cycle-Next создает другой факт cycle со значением, большим на 1, чем было у предыдущего только что удаленного факта cycle.
Следующей строкой (printout t "MAIN::Cycle=" ?next-cycle crlf) осуществляется вывод текста в терминал.
Оператор focus устанавливает последовательность выполнения модулей после того, как в текущем модуле будут исчерпаны все экземпляры правил. Правила могут сработать только один раз для данного конкретного сочетания фактов.
Следующим модулем, который будет исполняться после модуля MAIN - модуль SIMULATOR.
Файл SimulatorNoBarrier.ecl с модулем SIMULATOR для случая, когда на пути лунохода нет препятствий, предельно прост:
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.0
;;; SIMULATOR Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Модуль симулятора внешней среды, сенсоров и пользователя.
;;;======================================================
(defmodule SIMULATOR (export deftemplate ?ALL) (import MAIN deftemplate ?ALL))
(defrule SIMULATOR::Mission1-Start ; Правило старта Миссии1
?c <- (cycle 0)
=>
(assert (mission mission1))
(printout t "SIMULATOR::Mission1:Start." crlf)
)
Он состоит всего лишь из одного правила: когда будет получен факт cycle со значением 0, то создать факт mission со значением mission1. Однажды созданный, этот факт будет существовать в системе до окончания миссии1 и будет являться флагом для работы робота над выполнением этой миссии.
Для нашего удобства в терминал командой (printout t "SIMULATOR::Mission1:Start." crlf) выводится контрольное сообщение.
Файл SimulatorBarrier.ecl с модулем SIMULATOR для случая, когда на пути лунохода имеется препятствие:
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.0
;;; SIMULATOR Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Модуль симулятора внешней среды, сенсоров и пользователя.
;;;======================================================
(defmodule SIMULATOR (export deftemplate ?ALL) (import MAIN deftemplate ?ALL))
(defrule SIMULATOR::Mission1-Start ; Правило старта Миссии1
?c <- (cycle 1)
=>
(assert (mission mission1))
(printout t "SIMULATOR::Mission1:Start." crlf)
)
(defrule SIMULATOR::Barrier-Set ; Правило, устанавливающее препятствие на пути робота.
?c <- (cycle 2)
=>
(assert (barrier detected))
(printout t "SIMULATOR::Barrier Set." crlf)
)
(defrule SIMULATOR::Barrier-Removed ; Правило, устраняющее препятствие на пути робота.
?c <- (cycle 4)
?f <- (barrier detected)
=>
(retract ?f)
(printout t "SIMULATOR::Barrier Removed." crlf)
)
В дополнение к тому, что делает модуль SIMULATOR для случая без препятствий, правило SIMULATOR::Barrier-Set устанавливает препятствие на пути робота в цикле 2, а правило SIMULATOR::Barrier-Removed удаляет это препятствие в цикле 4.
Файл Mission1.ecl с модулем MISSION:
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.0
;;; MISSION Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Модуль пользовательского сценария.
;;;======================================================
(defmodule MISSION (export deftemplate ?ALL) (import MAIN deftemplate ?ALL) (import SIMULATOR deftemplate ?ALL))
(deftemplate MISSION::command ; Шаблон факта команды, поступающей в сенсорный модуль
(slot name)
(slot param (type INTEGER) (default 0))
)
(deftemplate MISSION::answer ; Шаблон факта ответа, поступающего из модуля EXECUTOR
(slot name)
(slot param)
)
(deffacts MISSION::mission1-facts ; Шаблон факта фаз выполнения миссии.
(phase forward1)
)
;;;======================================================
(defrule MISSION::Mission1-Forward1 ; Правило первой фазы Миссии1
?c <- (cycle ?current-cycle)
?f <- (mission mission1)
?m <- (phase forward1)
=>
(retract ?m)
(printout t "MISSION::Mission1.Command.Forward1(5)" crlf)
(assert (command (name forward) (param 5))) ; Для модуля SOLVER
(assert (phase right1))
)
(defrule MISSION::Mission1-Right1 ; Правило второй фазы Миссии1
?c <- (cycle ?current-cycle)
?f <- (mission mission1)
?m <- (phase right1)
?n <- (answer (name forward) (param OK))
=>
(retract ?m)
(retract ?n)
(printout t "MISSION::Mission1.Command.Right1(3)." crlf)
(assert (command (name right) (param 3))) ; Для модуля SOLVER
(assert (phase left1))
)
(defrule MISSION::Mission1-Left1 ; Правило третьей фазы Миссии1
?c <- (cycle ?current-cycle)
?f <- (mission mission1)
?m <- (phase left1)
?n <- (answer (name right) (param OK))
=>
(retract ?m)
(retract ?n)
(printout t "MISSION::Mission1.Command.Left1(8)." crlf)
(assert (command (name left) (param 8))) ; Для модуля SOLVER
(assert (phase end1))
)
(defrule MISSION::Mission1-End1 ; Правило четвертой фазы Миссии1
?c <- (cycle ?current-cycle)
?f <- (mission mission1)
?m <- (phase end1)
?n <- (answer (name left) (param OK))
=>
(retract ?m)
(retract ?n)
(retract ?f)
(printout t "MISSION::Mission1.Command.End()." crlf)
(halt)
)
Конструкция deftemplate MISSION::command создает шаблон факта команды, поступающей в модуль SOLVER, а шаблон факта deftemplate MISSION::answer позволяет получить ответ модуля SOLVER о результате выполнения команды.
Конструкция deffacts MISSION::mission1-facts перед началом выполнения модуля MISSION размещает в рабочей памяти факт phase со значением forward1.
Правило MISSION::Mission1-Forward1 срабатывает сразу же, как только управление переходит в этот модуль, т.к. в наличии будут все условия для его срабатывания. Оно удаляет факт фазы, выводит в теминал лог, а также создает факт command для модуля SOLVER с указанием направления движения робота и величиной перемещения. Это правило создает еще факт phase со значением right1, что указывает на следующий этап работы конечного автомата сценария.
Правило MISSION::Mission1-Right1 сработает, если появится дополнительное условие -факт answer от модуля SOLVER с подтверждением полного выполнения предыдущего этапа сценария.
Аналогично работают и все остальные правила. Последнее правило Mission1-End1 не создает новой команды, а завершает работу программы.
Теперь переходим к рассмотрению модулей, описывающим внутреннее устройство робота.
Файл Sensor.ecl с модулем SENSOR:
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.0
;;; SENSOR Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Модуль обработки сенсорных данных.
;;;======================================================
(defmodule SENSOR (export deftemplate ?ALL) (import MAIN deftemplate ?ALL) (import MISSION deftemplate ?ALL))
(defrule SENSOR::Barrier-Detected ; Правило обнаружения препятствия.
?c <- (cycle ?current-cycle)
?f <- (barrier detected)
=>
(assert (sensor barrier)) ; Для модуля SOLVER
(printout t "SENSOR::Error: Barrier Detected!" crlf)
)
(defrule SENSOR::Barrier-Removed ; Правило определения отстутсвия препятствия.
?c <- (cycle ?current-cycle)
(not (barrier detected))
=>
(assert (sensor nobarrier)) ; Для модуля SOLVER
(printout t "SENSOR::Message: No Barrier." crlf)
)
Правило Barrier-Detected позволяет обнаружить препятствие, если оборудование робота создаст факт barrier со значением detected и внесет его в рабочую память этого модуля. Как видно из кода, во всех правилах здесь, как и в других модулях, присутствует конструкция вида ?c <- (cycle ?current-cycle), которая позволяет привязать выполнение всех правил к текущему циклу работы всей программы.
Если препятствие обнаружено правилом Barrier-Detected, то командой (assert (sensor barrier)) будет создан факт sensor со значением barrier. Этот факт предназначен модулю SOLVER.
Правило Barrier-Removed создает аналогичный факт для модуля SOLVER со значением nobarrier в каждом цикле, если препятствия на пути робота нет.
Файл Solver.ecl с модулем SOLVER:
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.0
;;; EXECUTOR Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Модуль принятия решений.
;;;======================================================
(defmodule SOLVER (export deftemplate ?ALL) (import MAIN deftemplate ?ALL) (import MISSION deftemplate ?ALL) (import SENSOR deftemplate ?ALL))
(deftemplate SOLVER::action ; Шаблон факта действия, поступающего в модуль EXECUTOR
(slot name) ; Название действия.
(slot param) ; Параметр действия.
(slot status) ; Статус действия.
)
;;;======================================================
(defrule SOLVER::Decision-Motion-Start
?c <- (cycle ?current-cycle)
?f <- (sensor nobarrier)
?n <- (command (name ?motion) (param ?p))
=>
(retract ?f)
(retract ?n)
(printout t "SOLVER::" ?motion ".Start()." crlf)
(assert (action (name ?motion) (param (- ?p 1)) (status request))) ; Для модуля EXECUTOR
)
(defrule SOLVER::Decision-Motion-Cycle
?c <- (cycle ?current-cycle)
?f <- (sensor nobarrier)
?n <- (action (name ?motion) (param ?p) (status OK))
=>
(retract ?f)
(retract ?n)
(if (> ?p 0)
then
(printout t "SOLVER::" ?motion ".Continue()." crlf)
(assert (action (name ?motion) (param (- ?p 1)) (status request))) ; Для модуля EXECUTOR
else
(printout t "SOLVER::" ?motion ".End()." crlf)
(assert (answer (name ?motion) (param OK))) ; Для модуля MISSION
)
)
В этом модуле конструкция deftemplate SOLVER::action создает шаблон факта, который позволяет модулю SOLVER отправлять команды в модуль EXECUTOR и получать от него подтверждение выполнения команд в слоте status факта action.
Правило SOLVER::Decision-Motion-Start в случае, если нет препятствия и имеется факт command с параметрами срабатывает и среди прочего создает факт action для модуля EXECUTOR. Наследники этого факта затем будут циркулировать в программе до тех пор, пока не выполнятся все шаги. Количество шагов указано в слоте param этого факта.
Циклическое выполнение обеспечивает правило SOLVER::Decision-Motion-Cycle, которое при поступлении в последующих циклах от модуля EXECUTOR факта action со слотом status равным OK вырабатывает факт-наследник action с уменьшенным на 1 значением параметра param.
Файл Executor.ecl с модулем EXECUTOR:
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.0
;;; EXECUTOR Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Модуль выполнения действий.
;;;======================================================
(defmodule EXECUTOR (import MAIN deftemplate ?ALL) (import SOLVER deftemplate ?ALL))
(defrule EXECUTOR::Action-Forward
?c <- (cycle ?current-cycle)
?f <- (action (name forward) (param ?p) (status request))
=>
(retract ?f)
(printout t "EXECUTOR::Action=Forward.Step()." crlf)
(assert (action (name forward) (param ?p) (status OK))) ; Для модуля SOLVER
)
(defrule EXECUTOR::Action-Left
?c <- (cycle ?current-cycle)
?f <- (action (name left) (param ?p) (status request))
=>
(retract ?f)
(printout t "EXECUTOR::Action=Left.Step()." crlf)
(assert (action (name left) (param ?p) (status OK))) ; Для модуля SOLVER
)
(defrule EXECUTOR::Action-Right
?c <- (cycle ?current-cycle)
?f <- (action (name right) (param ?p) (status request))
=>
(retract ?f)
(printout t "EXECUTOR::Action=Right.Step()." crlf)
(assert (action (name right) (param ?p) (status OK))) ; Для модуля SOLVER
)
Этот модуль совсем прост. Для каждого направления движения имеется по одному правилу, которое срабатывает при получении из модуля SOLVER факта action с соответствующим значением слота name. При срабатывании каждого правила робот делает элементарный шажок в требуемом направлении, что выражается пока лишь в выводе на теминал логирующего сообщения. После этого правила создают ответный факт action в модуль SOLVER. У этого факта все слоты кроме последнего совпадают с тем фактом action, по которому это правило сработало.
Вот следующая итерация программы лунохода для ОС Windows:
В ней я произвел некоторые изменения, среди которых я сделал мультиагентную среду, а также текстовое поле, где могут перемещаться роботы-агенты.
В данной программе сначала запускается агент Lunochod1, а спустя несколько тактов - Lunochod2. Луноходы выполнены в виде стрелочек разного цвета: Lunochod1 - зеленый, Lunochod2 - желтый. Агенты выполняют одинаковую миссию Mission1, которая заключается в движении вперед на 5 шагов, повороте вправо на 90 градусов, движении после поворота по прямой 3 шага, поворота налево на 90 градусов и движении по прямой 8 шагов.
В нижней части терминала имеется три статусных строки, верхняя из которых предназначена Lunochod1, ниже - Lunochod2.
На пути Lunochod2 встречается препятствие (символ 0), которое он обнаруживает своим сенсором препятствий и останавливается с выдачей сообщения об ошибке выполнения его миссии. Lunochod1 успешно выполняет свою миссию и останавливается после ее окончания. Через некоторое время работа программы завершается, о чем свидетельствует приглашение среды CLIPS в нижней строке терминала.
Подробности запуска программы читайте во вложенном файле README.txt
Надеюсь, вас не расстраивает тот факт, что выглядит данная программа пока слишком примитивно? Но без хотя бы простейшей визуализации двигаться дальше было бы трудно. А затевать мультяшки для малых деток я не стал. Надеюсь, что красоту дорисует ваше воображение, а вы с пониманием отнесетесь к такому примитивизму.
Мультиагентность нужна не только для создания нескольких роботов, взаимодействующих между собой, но и позволит создавать роботов, в которых будут копошиться разные мысли. В качестве мыслей будут агенты. Как их организовать - надеюсь, увидим позже.
Даже в таком простейшем виде можно путем простых правок в коде программы изменить поведение роботов.
Файл Simulator.ecl модуль SIMULATOR.
- Код: Выделить всё • Развернуть
;;;======================================================
;;; Lunochod V 1.0.1
;;; SIMULATOR Module
;;; For ECLIPS Version 6.3
;;; 2016.12.02 Victor Kazarinov
;;;======================================================
;;; Модуль симулятора внешней среды, сенсоров и пользователя.
;;;======================================================
(defmodule SIMULATOR (export deftemplate ?ALL) (import MAIN deftemplate ?ALL) (import MAIN deffunction ?ALL) (import MAIN defglobal ?ALL))
(defrule SIMULATOR::Mission1-Lunochod1-Start ; Правило старта Миссии1
?c <- (cycle 0)
=>
(bind ?*gamefieldref* (sys-2darray-create ?*gamefieldDimX* ?*gamefieldDimY* 1 1 ?*backgroundSym*)) ; Создать игровое поле размером 20х20 символов.
(field-fill ?*gamefieldDimX* ?*gamefieldDimY* 1 ?*gamefieldref*)
; Создать агента lunochod1
(assert (agent-position (agent-name lunochod1) (posx 10) (posy 9)))
(assert (agent-direction (agent-name lunochod1) (direction right)))
(assert (agent-image (agent-name lunochod1) (sym 26) (color 10)))
(assert (mission-phase (agent-name lunochod1) (mission-name mission1) (phase forward1))) ; Назначить агенту миссию.
(agent-goto 26 10 9 10 9 10 ?*backgroundSymBackColor*)
(agent-goto ?*barrierSym* 24 10 28 13 15 ?*backgroundSymBackColor*) ; Установить препятствие на пути lunochod2.
;(tui_status-print "SIMULATOR::Mission1:Start." 0)
)
(defrule SIMULATOR::Mission1-Lunochod2-Start ; Правило старта Миссии1
?c <- (cycle 3)
=>
; Создать агента lunochod2
(assert (agent-position (agent-name lunochod2) (posx 20) (posy 10)))
(assert (agent-direction (agent-name lunochod2) (direction right)))
(assert (agent-image (agent-name lunochod2) (sym 26) (color 14)))
(assert (mission-phase (agent-name lunochod2) (mission-name mission1) (phase forward1))) ; Назначить агенту миссию.
(agent-goto 26 20 10 20 10 14 ?*backgroundSymBackColor*)
)
Как видно из кода симулятора, для создания нового робота достаточно всего несколько строк, создающих новые факты и описывающих его положение на экране, направление движения в начальный момент времени, внешний вид (символ, которым робот будет отображен и его цвет), и с какой фазы какой миссии нужно этого агента запускать:
- Код: Выделить всё • Развернуть
; Создать агента lunochod1
(assert (agent-position (agent-name lunochod1) (posx 10) (posy 9)))
(assert (agent-direction (agent-name lunochod1) (direction right)))
(assert (agent-image (agent-name lunochod1) (sym 26) (color 10)))
(assert (mission-phase (agent-name lunochod1) (mission-name mission1) (phase forward1))) ; Назначить агенту миссию.
(agent-goto 26 10 9 10 9 10 ?*backgroundSymBackColor*)
Последняя строка этого кода фактически размещает на экране робота по созданному шаблону.
Все это означает, что роботов можно стартовать имеющейся миссией не только вправо, но и в любую другую сторону, написав вместо right слово up, left или down. Также видно, что можно стартовать не только с начала миссии, но и выполнить любой ее участок до окончания миссии. Для этого нужно заглянуть в файл Mission1.ecl и взять оттуда название других фаз. Если хотите, попробуйте сами, я этого всего еще сам не делал и поэтому не отладил код.