Главная страница
Навигация по странице:

  • РАБОТАЮЩЕГО ПОД УПРАВЛЕНИЕМ ОСРВ

  • 5.3. КОНЕЧНЫЕ АВТОМАТЫ

  • 5.4. ДИСТАНЦИОННОЕ УПРАВЛЕНИЕ РОБОТОМ, СОВЕРШАЮЩИМ СЛУЧАЙНЫЕ БЛУЖДАНИЯ

  • 5.5. ПОВЕДЕНЧЕСКОЕ ПРОГРАММИРОВАНИЕ

  • 5.6. НЕЙРОННЫЕ СЕТИ И ИСКУССТВЕННЫЙ ИНТЕЛЛЕКТ

  • Устройства управления роботами, схемотехника и программирование (М. Предко, 2004). Устройства управления роботами, схемотехника и программирование. Устройствауправления роботамисхемотехника и микроконтроллеров picmicro


    Скачать 6.79 Mb.
    НазваниеУстройствауправления роботамисхемотехника и микроконтроллеров picmicro
    АнкорУстройства управления роботами, схемотехника и программирование (М. Предко, 2004).pdf
    Дата29.08.2017
    Размер6.79 Mb.
    Формат файлаpdf
    Имя файлаУстройства управления роботами, схемотехника и программирование .pdf
    ТипРеферат
    #8441
    КатегорияПромышленность. Энергетика
    страница28 из 33
    1   ...   25   26   27   28   29   30   31   32   33
    5.2. ПРИМЕР ПРИЛОЖЕНИЯ,
    РАБОТАЮЩЕГО ПОД УПРАВЛЕНИЕМ ОСРВ
    В предыдущем разделе при обсуждении операционных систем реального времени мы так и не показали, как они позволяют упростить разработку приложений.
    Здесь мы рассмотрим этот вопрос на простом примере, чтобы вы воочию убеди- лись, как облегчается при использовании ОСРВ процесс добавления новых функ- ций к работающему приложению.
    Хотя примеры, приведенные выше, разрабатывались именно таким образом,
    чтобы облегчить модернизацию программ и обеспечить безболезненное добавле- ние новых интерфейсов, наиболее простой и эффективный способ модернизации,
    не требующий изменения уже работающих программ, основан на использовании многозадачной ОСРВ.
    Назовем наше приложение «Таракан», потому что функция робота будет за- ключаться в том, чтобы убежать подальше от источника света, скрывшись в самом

    Вдохните в робота жизнь 331
    темном углу комнаты. Для этого потребуются четыре задачи: первая будет выпол- нять биологический код, вторая - осуществлять опрос датчиков столкновений
    (контактных или инфракрасных), третья - опрашивать состояние световых дат- чиков, а четвертая - управлять работой двух двигателей, каждый из которых свя- зан со своим (левым и правым) колесом. Биологический код должен будет по состоянию датчиков принимать решение о направлении движения, изменяя его,
    чтобы робот огибал возникшее на пути препятствие, но в любом случае пытался оказаться подальше от источника света.
    Чтобы представить связи между задачами, вы можете нарисовать их на листе бумаги, изобразив сами задачи в виде вершин графа скругленной формы, а сема- форы, используемые для управления доступом к ресурсам, - в виде прямоуголь- ных блоков.
    Обратившись к табл.
    вы не сможете найти в ней какой-либо функции, по- зволяющей одной задаче узнать состояние другой. Для этого используется стан- дартный механизм пересылки сообщений. Одна задача всегда может послать дру-
    . гой сообщение, запросив нужные данные, а та, в свою очередь, пошлет первой задаче сообщение, где будут содержаться значения необходимых переменных.
    Биологический код для нашего примера выглядит следующим образом:
    void
    // Биологический код для приложения "Таракан" (Roach)
    int left, right;
    int msg message;
    while (1 1) <
    // Состояние световых датчиков.
    // Номер сообщения.
    // Текст сообщения.
    // Бесконечный цикл.
    if
    == free) { // Если нет активной message = biologic_task;
    bump - имя задачи,
    // обслуживающей детекторы msgnum =
    message = Read (msgnum);
    // Узнали состояние if (message != no_collision)
    // Нет столкновений.
    message =
    // Остановить двигатели.
    message);
    } else < // Двигаться от источника света.
    message = biologic_task;
    // Узнать состояние message = get_left_light_sensor; // левого message); // светового msgnum =
    left =
    message = biologic_task;
    SendC'light", message);
    message = get_right_light_sensor;
    SendC'light", message);
    msgnum = WaitO;
    right =
    // Узнать состояние
    // правого
    // светового датчика.

    332 Устройства управления роботами
    // "Отвернуться" от света:
    if (right >= left)
    . message =
    else message =
    message);
    >
    }
    // Задержка на 100
    // перед новым опросом датчиков.
    // Конец цикла while.
    } // Конец биологического кода.
    Здесь мы предполагали, что значение, получаемое от светового датчика, тем больше, чем сильнее он освещен. Чтобы удалиться от источника света, наш «тара- кан» включает двигатель, противоположный тому датчику, который освещен ярче.
    Например, если света расположен слева (выполняется ветвь «иначе»
    условного оператора то будет включен правый двигатель.
    Для работы с командами дистанционного управления перед входом в програм- му мы опрашиваем состояние семафора control_sem - этот вопрос будет обсуж- даться чуть позже.
    Для опроса датчиков столкновений предназначена следующая программа:
    void
    // Опрос датчиков столкновений.
    {
    left, right; // Счетчики для левого и правого датчиков.
    int msgnum; // Номер сообщения.
    msg message; // Текст сообщения.
    msg Sender; // Задача - отправитель сообщения.
    left = 0; right = 0; // Инициализация while (1 == 1) { // Бесконечный цикл.
    if (leftsensor collision) // Сработал левый if (left < 5)
    // Противодребезговая else ;
    else // Нет if (left > 0)
    // Противодребезговая задержка.
    if (rightsensor == collision) // Сработал правый if (right < 5)
    right++; // Противодребезговая else ;
    else // Нет if (right > 0) .
    // Противодребезговая msgnum = Check(); // Было сообщение?
    if (msgnum
    ( // Да, было.
    Sender =
    // Прочитать
    . // и подтвердить if (Left == 5)
    if (Right == 5)

    Вдохните в робота жизнь 333
    message = "Both"; // Оба else message = "Left"; // Левый else if (Right message = "Right" // Правый else if
    != 0) | (Left !=
    message = "Indeterminate" //
    else // Оба счетчика имеют нулевое значение.
    message =
    // Нет контакта.
    message); // Послать сообщение.
    }
    Dlay(10); // Теперь пусть выполняются и другие задачи.
    } // Конец цикла while.
    }
    Здесь в бесконечном цикле происходит опрос состояния обоих датчиков (в дан- ном случае неважно, какого типа эти датчики - они могут быть и дистанционными,
    и механическими; в комментариях к программе используется термин «контак-
    С помощью счетчиков реализуется необходимая задержка, устраняющая возможный дребезг контактов, если датчики являются механическими. Получив сообщение от другой задачи, программа посылает в ответ строку, описывающую состояние датчиков; при этом используется системный вызов Send. Обратите внимание на небольшую задержку в конце программы: она нужна, чтобы плани- ровщик мог передать управление какой-либо другой задаче.
    Если контакторы к текущему времени не находились в определенном состоя- нии хотя бы 50 мс, то их состояние считается неопределенным (посылается стро- ка
    Предварительный запрос от другой задачи нужен для того, чтобы программа знала, кому посылать сообщение о состоянии датчиков. При описании основных системных вызовов мы не конкретизировали, каким способом задача-получатель сообщения может узнать идентификатор задачи-отправителя. В большинстве
    ОСРВ сообщение на самом деле - не простая строка, а структура, состоящая из нескольких полей, в одном из которых хранится номер или имя отправителя.
    Следующая программа предназначена для управления двигателями. Она включает нужный двигатель на 100 мс и ожидает прихода сообщения, которое будет содержать указания для дальнейших действий. Перед включением двигате- ля проверяется состояние семафора и, если он свободен (сбро- устанавливаем его, чтобы другая задача, ответственная за опрос световых датчиков, могла узнать, что в данный момент ведется работа с двигателями (на- помним, что измерение сопротивления фоторезисторов в прошлой главе мы дого- ворились производить только при выключенных двигателях, когда уровень помех минимальный). Вот текст программы:
    void
    // Работа с двигателями.
    {
    int 'i;
    int msgnum; // Номер сообщения.
    message; // Текст сообщения.
    // Сброс счетчика.

    334 Устройства управления роботами while (1 == 1) {
    if
    == 0) { // Если прошло 100
    остановить motors = stop;
    i = 1;
    ;
    = Check(); // Есть сообщение?
    if (msgnum !=
    { // Да.
    message =
    ; // Прочитать его
    // и послать motors = message;
    if (message == stop)
    i = 1; // Было сообщение об остановке двигателей.
    } else {
    i = 10;
    // Освободить семафор.
    // Двигатель работает.
    // Занять семафор.
    >
    // Дать возможность выполняться другим задачам.
    // Конец цикла while.
    Четвертая задача предназначена для работы со световыми датчиками. Она ожидает запроса от другой задачи, а получив его, отсылает в ответ сообщение о состо- янии датчиков. Текст программы:
    void light()
    // Опрос световых датчиков.
    msgnum;
    message;
    msg Sender;
    while (1 == 1) {
    msgnum =
    Sender = Read(msgnum);
    msgnum =
    // Номер сообщения.
    // Текст сообщения.
    // Идентификатор задачи - отправителя сообщения.
    // Бесконечный цикл.
    // Ожидаем сообщение.
    // Запомнили идентификатор отправителя.
    // Подтвердили получение сообщения.
    // Ждем запрос.
    message =
    // Прочитали текст запроса.
    // Подтвердили получение if
    != Free) {
    // Выключить двигатели на время измерения:
    message = motor_stop;
    message);
    >
    if (message ==
    message =
    else message = RightLightLevel;
    message) ;

    Вдохните в робота жизнь 335
    // Конец цикла while.
    Здесь мы не вызываем в явном виде функцию задержки; ее роль играет функ- ция ожидания прихода сообщения от другой задачи.
    Для чтобы обеспечить одновременное выполнение всех четырех описан- ных задач, создадим еще одну задачу под названием void
    // Загрузка задач.
    Start(biologic, 2,
    3,
    3,
    Start(light, 3,
    // Запуск биологического кода.
    // Задача для работы с двигателями.
    // Задача для работы с контакторами.
    // Задача для работы
    // со световыми датчиками.
    // Завершение задач и освобождение ресурсов.
    Однако всего перечисленного еще недостаточно. Наше приложение работает правильно, но пока только один раз. «Убежав» от источника света, робот остается в темном месте комнаты до тех пор, пока не изменяется положение источника или пока вы сами не переносите «таракана» на новое, более освещенное место. Будучи достаточно ленивым, я решил добавить к приложению еще одну задачу для при- ема и декодирования подаваемых с помощью инфракрасного пульта дис- танционного управления.
    Мы будем использовать шесть кнопок: две - для старта и останова, еще две - для ускорения и замедления движения, и последние две - для поворота налево и направо. Ниже приведен текст программы:
    void
    // Дистанционное управление.
    // Занять семафор (ждать прихода команды).
    msg message; // Текст while (1 == 1) { // Бесконечный цикл.
    (RemoteControl = ButtonPress) { // Есть команда.
    { // Какая кнопка нажата?
    case Forward: // Команда "Вперед"
    // (ускорить if
    == Free)
    Forward);
    break;
    case Reverse: // Команда "Назад"
    // (замедлить if
    == Free)
    Get(control break;
    case TurnLeft: // Команда "Налево".
    it
    == Free)
    Send (motor, TurnLeft);

    336 Устройства управления роботами break;
    case TurnRight: // Команда if
    == Free)
    TurnRight);
    break;
    Case Stop: // Команда if
    == Free)
    Break;
    Case Start: // Команда "Старт".
    break;
    }
    Конец оператора witch.
    } // Конец оператора if.
    Dlay(10); // Дать возможность выполняться другим задачам.
    } // Конец цикла while.
    }
    Ниже приведена программа, которая обеспечивает запуск всех пяти задач:
    void
    // Загрузчик.
    . {
    Start(control, 1,
    Start(biologic,
    3,
    3,
    Start(light, 3,
    >
    Как вы видите, при добавлении новой задачи не пришлось изменять текст уже написанных программ: только добавилась новая строка в программу-загрузчик.
    Именно в этом и заключается важное преимущество операционных систем реаль- ного времени.
    Еще одно преимущество ОСРВ состоит в том, что при их использовании за- метно уменьшается размер памяти, требуемый для хранения данных.
    На разработку всех пяти вышеописанных программ я затратил несколько ча- сов. Если бы программа разрабатывалась как монолитное приложение теми мето- дами, которые были рассмотрены в предыдущей главе, то есть без поддержки
    ОСРВ, мне пришлось бы потратить несколько недель. Даже если не учитывать всех трудностей, которые при этом пришлось бы преодолеть, выигрыш при ис- пользовании ОСРВ очевиден.
    5.3. КОНЕЧНЫЕ АВТОМАТЫ
    Для проектирования кода верхнего уровня также можно использовать модель конечного автомата которую мы уже упоминали в предыдущей главе. Этот подход позволяет от вложенных условных операторов и запутанных

    Вдохните в робота жизнь 337
    проверок состояния различных флагов, которые в противном случае потребова- лось бы использовать в программе для принятия тех или иных решений.
    Первоначально конечные автоматы возникли как специальные цифровые устрой- ства (рис.
    которые могли выполнять заданную последовательность действий в определенном порядке.
    Ши<
    | Адрес
    J
    >ратор
    Данные Выходные сигналы
    Входные
    Адрес следующего состояния
    Рис.
    Аппаратная реализация конечного автомата
    По каждому фронту тактового генератора (на рис.
    тактовый вход не пока- зан) конечный автомат переходит в новое состояние - оно вычисляется исходя из текущего состояния автомата и значения входных сигналов. Состояние КА зада- ется значением адреса на входе постоянного запоминающего устройства
    (ПЗУ). Хранящаяся по этому адресу информация определяет, какими должны быть выходные сигналы А и какой адрес будет на входе ПЗУ в следующем так- те. Заметим, что заранее задана только часть адреса (некоторое число его разря- дов); остальные биты адреса зависят от входных сигналов КА.
    Для программной реализации КА хорошо подходит оператор выбора который мы уже использовали при разработке конечных автоматов для работы с периферийными устройствами.
    Приведем пример программной реализации КА для управления роботом. До- пустим, мы хотим, чтобы наш робот двигался случайным образом:
    // Случайные блуждания.
    State = 1;
    while(1 == 1)
    switch (State)
    case 1:
    // Начальное состояние.
    // Бесконечный цикл.
    // Конечный автомат: .
    // Двигаться вперед в течение 2 с.
    Dlay(2000);
    case 5
    // Задержка на 2 с (используются
    // прерывания от if (Collision == "No") // Нет столкновения.
    State = 5; // Номер следующего else // Есть столкновение, надо препятствие.
    State = 10; // Задний ход.
    break;
    // Поворот налево с).
    Dlay(750);
    if (Collision == "No") // Нет столкновения.
    State
    // Номер следующего состояния.
    else // Есть столкновение, надо объехать препятствие.

    338 Устройства управления роботами
    State = 10; // Номер следующего состояния.
    break;
    case 10: // Было столкновение, дать задний ход
    Move(Reverse) ;
    Dlay(1000) ;
    State = 15; // Номер следующего состояния.
    break;
    case 15: // Поворот направо (0,5 с).
    State = 1; // Номер следующего состояния.
    break;
    } // Конец оператора switch.
    } // Конец цикла while.
    } // Конец примера.
    Здесь перед переходом в очередное состояние выполняется задержка на опре- деленное время, то есть функция выполняет роль тактовых импульсов, вы- зывающих срабатывание аппаратного конечного автомата.
    При этом возникает новая проблема: во время действия задержки любые из- менения входных сигналов будут проигнорированы, так как новое состояние КА
    уже определено (переменная State уже получила нужное значение).
    Конечно, желательно, чтобы световые датчики и детекторы столкновений опра- шивались постоянно. В принципе это не так уж сложно осуществить, но тогда надо добиться, чтобы подпрограмма задержки работала вне цикла автомата,
    причем длительность задержки должна изменяться в зависимости от текущего состояния.
    В следующем примере каждое состояние конечного автомата разбито на два.
    Первое состояние определяет характер движения робота и число циклов длитель- ностью 50 мс каждый, в течение которых будет длиться задержка, а второе состо- яние соответствует периоду ожидания (в течение которого с каждым срабатыва- нием таймера уменьшается значение счетчика задержки), но в это же время происходит непрерывный опрос датчиков столкновений. Если какой-то датчик сработал, то выполняются необходимые действия.
    {
    int State = 1;
    int DlayCount = 0;
    while (1 == 1) {
    // Случайные блуждания, вариант 2.
    // Начальное состояние.
    // Счетчик задержки.
    // Бесконечный цикл.
    case 1: // Движение вперед (2 с)
    DlayCount = 40; // 40 раз выполнить
    // задержку на 50 мс.
    State = 2; // Выполнение задержки
    // (и опрос break;
    case 2: // Движение вперед (2 с).
    if (Collision == "No") ' // Нет столкновений.

    Вдохните в робота жизнь 339
    if (
    State = 2; // Если не 0, то оставаться
    // в текущем else
    State 5;
    else // Было столкновение.
    State = 10;
    break;
    case 5: // Поворот налево (0,75 с).
    DlayCount = 15; // Соответствует задержке 750
    State = 6; // Выполнение break;
    case 6: // Поворот налево (0,75
    if (Collision
    "No")
    if
    State = 6;
    else
    State = 1; I
    else
    State = 10;
    break;
    case 10; // Было столкновение (ехать назад в течение
    Move(Reverse);
    ;
    State = 15;
    break;
    case 15: // Поворот направо (0,5 с).
    State break;
    } // Конец оператора switch.
    // Общая задержка 50 мс.
    } // Конец цикла while.
    } // Конец примера.
    Здесь состояния с номерами 10 и 15 не имеют задержек, потому что определя- ют действия робота при срабатывании датчиков столкновений. Предполагается,
    что, отъезжая чуть назад, робот не столкнется с каким-либо другим предметом.
    Вообще-то это предположение не совсем корректно для нашего беспорядочно двигающегося робота.
    Лучше было бы разместить дополнительные датчики в задней части корпуса робота и опрашивать их состояние, пока он движется назад. При необходимости вы сможете самостоятельно внести соответствующие изменения в программу.
    Достоинства конечно-автоматного подхода к процессу разработки щей программы - его простота и легкость, с которой могут быть добавлены новые состояния. Так как программный код, соответствующий каждому отдельному со- стоянию, достаточно прост, он не отнимает много процессорного времени, давая возможность выполняться функциям нижних уровней.

    340 Устройства управления роботами
    Однако при усложнении логики работы программы код КА также становится достаточно сложным для понимания и отладки. Тем не менее конечно-автомат- ный подход в большинстве случаев достаточно перспективен при проектировании программного обеспечения для управления роботами.
    5.4. ДИСТАНЦИОННОЕ УПРАВЛЕНИЕ РОБОТОМ,
    СОВЕРШАЮЩИМ СЛУЧАЙНЫЕ БЛУЖДАНИЯ
    В этом разделе мы рассмотрим несложный пример использования программного конечного автомата, который позволяет роботу, в свободном состоянии соверша- ющему случайные блуждания, принимать и выполнять команды дистанционного управления.
    Допустим, робот должен двигаться вперед в течение двух секунд, на следую- щей секунде совершать поворот направо (затратив на это 0,75 с), после чего все повторяется заново. Натолкнувшись на какой-либо предмет, робот сначала отъез- жает назад (затратив на это полсекунды), а затем в течение следующих 0,5 с пово- рачивает в сторону, противоположную той, с которой зафиксировано срабатыва- ние контактора. После объезда препятствия робот снова возвращается к своему обычному циклу «вперед-направо».
    При использовании традиционного метода программирования (с помощью условных операторов) биологический код будет выглядеть следующим образом:
    while (1 == 1) {
    = 0; // Сначала столкновений нет.
    // Левый двигатель включен.
    // Правый двигатель включен.
    = RTC + 2000; . // В течение 2 с.
    while (Dlay != RTC)
    if
    // Сработал левый контактор?
    CollisionFlag = 1;
    else if
    // Сработал правый контактор?
    CollisionFlag = 2;
    if
    {
    // Код, выполняемый, когда столкновений нет.
    // Поворот направо.
    // Реверс правого двигателя.
    Dlay = RTC + 750; // Задержка 0,75 с.
    while (Dlay != RTC)
    if (GetLeftWhiskerO)
    // Сработал левый контактор?
    CollisionFlag = 1;
    else if (GetRightWhiskerO)
    // Сработал правый контактор?
    CollisionFlag =2;
    } // Конец условного оператора if.
    if (CollisionFlag •== 1) { // Столкновение зафиксировано слева.

    Вдохните в робота жизнь 341
    = RTC + 500;
    while
    != RTC);
    Dlay RTC
    500;
    while (Olay != RTC);
    } // Конец условного оператора if.
    // Обьезд.
    // Реверс правого двигателя.
    // В течение с.
    // Задержка.
    // Поворачиваем направо.
    // Реверс правого
    // Задержка с.
    if (CollisionFlag == 2){ // Столкновение зафиксировано справа.
    LeftMotor(LeftReverse);
    RightMotor(RightReverse);
    Dlay = RTC + 500; // 0,5 с.
    while (Dlay != RTC);
    LeftMotor(LeftReverse);
    Dlay = RTC + 500;
    while (Dlay != RTC);
    } // Конец условного оператора if.
    // Обьезд.
    // Реверс правого двигателя.
    // Реверс левого двигателя.
    // Поворачиваем налево.
    // 0,5 с.
    // Конец цикла while.
    Эта программа вполне работоспособна, но выглядит довольно неуклюже. Вряд ли вы смогли бы быстро разобраться, что делает робот, если бы не дополнитель- ные пояснения. Кроме весьма проблематично добавить к данному коду но- вые функции. Поэтому целесообразно выбрать какой-либо другой способ про- граммирования.
    Все намного проще, если мы используем конечно-автоматный подход:
    while (1 == 1) { // Бескойечный цикл.
    switch (State) {
    case 1: // Двигаться вперед в течение 2 с.
    State++; // Начать с состояния 2.
    StateDlay = RTC + 2000; // Задержка 2 с.
    // Левый двигатель работает.
    // Правый двигатель break;
    case 2: // Ждать if
    // Сработал левый контактор.
    State = 10;
    else if
    // Сработал правый контактор.
    State = 20;
    else if (StateDlay
    RTC)
    State++; // Нет break;
    case 3: // Поворот направо (0,75 с).
    State++;
    StateDlay = RTC + 750;
    // Левый двигатель работает.
    RightMotor(RightReverse); // Реверс правого break;

    342 Устройства управления роботами
    • case 4: // Ждать 0,75 с.
    if
    State = 10;
    else if
    State = 20;
    else if (StateDlay
    RTC)
    State break;
    case 10: // Препятствие слева.
    State++;
    StateDlay = RTC + 500;
    break;
    case
    // Ждать с.
    if (StateDlay
    RTC)
    State++;
    break; ' .
    case 12: // Объехать препятствие с).
    State++;
    StateDlay
    RTC + 500;
    break;
    case 13: // Ждать 0,5 с.
    if (StateDlay
    RTC)
    State break;
    case 20: // Препятствие справа.
    State++;
    StateDlay = RTC + 500;
    break;
    case 21: // Ждать 0,5 с.
    if (StateDlay
    RTC)
    State++;
    break;
    case 22: // Объехать препятствие (0,5 с).
    StateDlay = RTC + 500;
    break;
    case
    // Ждать if
    == RTC)
    State = 1;
    break;
    } // Конец оператора switch.
    } // Конец цикла while.

    Вдохните в робота жизнь 343
    Не так уж сложно добавить сюда какие-либо дополнительные функции. При этом просто увеличится число состояний. Заметим, что размер программы растет по линейному закону, в отличие от обычного метода программирования, когда сложность и длина программы при наращивании числа функций возрастают в гео- метрической прогрессии.
    Здесь приведен только пример биологического кода. В электронном приложе- нии к этой книге в файле Code\Statemc\wallhug.c приводится полный исходный текст программы для дистанционно управляемой модели мыши фирмы а в файле
    - аналогичный текст программы для управления роботом с двумя серводвигателями и световыми датчиками.
    Если вы сравните эти файлы, то с удивлением обнаружите, что биологический код в обоих случаях совершенно одинаков. Единственное отличие касается функ- ций и
    Скорость движения модели мыши может изме- няться с помощью команд дистанционного управления (для этого приходится ис- пользовать сигнал), а у второго робота серводвигатели вращаются с постоянной скоростью.
    Такой результат достигнут не только благодаря достоинствам конечно-авто- матного подхода. Следует не забывать и о нашей концепции «трех уровней», со- гласно которой необходимо отделять реализацию механических и электронных интерфейсов от высокоуровневого биологического кода. Как вы видите, сочета- ние этих двух подходов дает прекрасные результаты.
    5.5. ПОВЕДЕНЧЕСКОЕ ПРОГРАММИРОВАНИЕ
    Если задуматься, можно прийти к выводу, что поведение
    - это просто на- бор его реакций на те или иные внешние воздействия. Например, робот, имитиру- ющий поведение маленького ребенка, может действовать следующим образом:
    // Вижу игрушку, хочу
    { '
    папа! Можно мне вон ту
    Response =
    // Узнать реакцию родителей.
    while.
    "Да")
    (Response != "Хорошо, мы купим
    {
    // Реагировать на отказ родителей купить игрушку.
    Position(LieDown); // Лечь на пол, стучать ногами и руками
    Crying(Start); // и кричать.
    if
    {
    // Если нет ответа, то ждать:
    Response =
    // Узнать реакцию родителей.
    if (Response ! = "Перестань немедленно, а не то
    // Перестать капризничать.
    больше не
    Response = "Да";

    344 Устройства управления роботами
    } // Конец оператора if.
    ) // Конец оператора if.
    } // Конец цикла while.
    // Подняться с пола.
    Crying(Stop); // Перестать кричать.
    } // Конец.
    Этот шуточный пример довольно точно иллюстрирует поведение робота, ко- торый опрашивает состояние своих входных датчиков, чтобы узнать об окружаю- щей его ситуации, а затем согласно заложенному в него алгоритму выбирает, как реагировать на то или иное изменение обстановки. Даже на этом простом приме- ре нам удалось проиллюстрировать множественность целевых установок, харак- терную для реальных программ: цель ребенка — покупка понравившейся ему иг- рушки, но если дело заходит слишком далеко (к сожалению или к счастью,
    настоящего ребенка нельзя «выключить», но можно придумать более педагогич- ный выход из создавшегося положения), то перед угрозой наказания ребенок пе- рестает капризничать.
    Отличие большинства реальных случаев от нашего примера заключается в том,
    что робот в каждый момент времени не обязательно выполняет только одну зада- чу. Возможно, вы подумали, что очень сложно реализовать выполнение сразу многих функций в одной программе, но на самом деле это вполне возможно и часто не требует какого-то особо искусного программирования.
    Единственное, что действительно представляет трудность, - выбор подходя- щего для данной ситуации механизма арбитража, который комбинировал бы ре- шения, принимаемые по нескольким алгоритмам, чтобы выработать то единствен- ное, что должно подаваться на двигатели
    Рассмотрим характерный для многих практических случаев пример, когда по- мимо основного кода верхнего уровня, принимающего решения и контролирую- щего поведение робота, имеется некоторая фоновая задача, которая при выполне- нии определенных условий включается в работу и перехватывает управление роботом.
    Допустим, мы хотим, чтобы, завидев человека, робот тут же развернулся в его сторону и начал движение либо к нему, либо от него - в зависимости от того рас- стояния, на котором находится человек.
    Для нашего проекта, который на этот раз так и останется только на бумаге,
    выберем робота с двумя сервоприводами (по одному для каждого колеса) и ульт- развуковым дальномером. Допустим, для управления положением колес робота в выходной порт записываются целые 8-разрядные числа:
    соответствует ко- манде «полный реверс», 0 - «стоп», +127 - «полный вперед». Пусть имеются две функции: distance - для определения расстояния до человека и vector - для определения угла его расположения относительно робота. Обе функции воз- вращают целые числа со знаком (типа int). Данные о режиме работы обоих дви- гателей будем хранить в структуре

    Вдохните в робота жизнь 345
    struct motor {
    int left;
    int right;
    // Левый двигатель.
    // Правый двигатель.
    Для простоты будем полагать, что робот находится на ровной площадке размеров, так что не требуется отвлекаться на опрос датчиков столкнове- ний. Единственное, чем будет занят робот, - движение по своему маршруту (со- гласно заложенному в него алгоритму) и измерение расстояния до человека. На практике, конечно, придется побеспокоиться о том, чтобы различать нескольких людей, да и вообще как-то отличать человека от обычных предметов. Хотя здесь мы не обсуждаем все эти задачи, но при используемом подходе добавление новых функций к биологическому коду не составляет никакой проблемы.
    Сначала давайте выясним, как сделать, чтобы робот поворачивался в сторону человека:
    motor directionBehavior(motor Data)
    { // Управление двигателями (поворот в сторону человека).
    // Узнать направление.
    // Надо повернуться налево.
    // Медленный поворот.
    int
    // Направление.
    =
    = 0;
    dir =
    if
    (dir > 0)
    if (dir <
    =
    = slowTurn;
    } else if (dir <
    =
    =
    } else { // Быстрый поворот.
    =
    = fastTurn;
    else if (dir < 0) // Надо повернуться if (dir > -tuneAngle) { // Медленный поворот.
    = slowTurn;
    = -slowTurn;
    } else if (dir > -turnAngle) {
    = mediumTurn;
    = -mediumTurn;
    } else { // Быстрый поворот.
    = fastTurn;
    = -fastTurn;
    return Data; // Вернуть два числа - команду двигателям.
    } // Конец.
    Здесь предполагается, что все углы и скорости объявлены как глобальные пе- ременные, то есть в главной программе. Если угол поворота, который необходимо

    346 Устройства управления роботами выполнить роботу, слишком велик, то поворот происходит быстро. После того как угол достигнет заданного предела, скорость замедляется. Когда робот развернул- ся в сторону человека, оба двигателя выключаются.
    Если расстояние до человека больше заданного порога, то робот должен дви- гаться в его сторону:
    motor
    Data)
    // Управление двигателями (движение в сторону человека).
    int
    // Расстояние до человека.
    dist =
    // Узнать расстояние до человека.
    =
    = 0;
    if (dist > closeClosest)
    if (dist > closeFurthest)
    =
    = forwardFull;
    else
    =
    =
    ( forwardFull « (dist - closeClosest) ) /
    (closeFurthest - closeClosest);
    return Data;
    } // Конец.
    Чем дальше человек, тем быстрее робот стремится к нему подъехать. Когда рас- стояние сокращается до некоторого предела, команды перестают вырабатываться.
    Обратите внимание, что для вычисления скорости мы сначала выполняем опера- цию умножения, а только потом - деления. Дело в том, что при делении целочислен- ных величин, если делитель больше делимого, результат будет нулевым. Поэтому сначала полная скорость умножается на разность текущего и минимального рассто- яний, и только затем результат делится на весь диапазон расстояний (от максималь- ного до минимального). В результате скорость сближения убывает по линейному закону. Напомним, что использование вещественной арифметики существенно уве- личило бы размер программы, так как все операции над числами в формате с плава- ющей точкой в микроконтроллерах реализованы только программно.
    Наконец, если расстояние до человека слишком мало, то робот должен двигать- ся назад:
    motor
    Data)
    // Управление двигателями (пятимся назад).
    int dist;
    dist = distanceO; // Узнать расстояние до человека.
    =
    0;
    if (dist <
    if (dist <
    =
    = reverseFull; // Полный else
    =
    right =
    (reverseFull * (awayFurthest -
    /
    (awayFurthest - awayClosest);
    return Data;
    } // Конец.

    Вдохните в робота жизнь 347
    Для выполнения всех трех задач составим главную программу:
    void
    // Фоновое приложение.
    motor motor closeData;
    motor awayData;
    motor while (1 1) {
    pause(RunDlay);
    // Команда двигателям.
    //
    всех трех команд.
    // Бесконечный цикл.
    // Сначала робот подчиняется
    // заложенному в алгоритму.
    directionData = directionBehavior(directionData);
    closeData =
    awayData =
    // Сформировали три команды, теперь комбинируем из них одну:
    =
    +
    +
    =
    +
    + awayData. right;
    // Послать команду для выполнения.
    pause(LoopDelay); // Дать роботу время на выполнение
    // команды и новый цикл измерений.
    } // Конец оператора while.
    } // Конец программы.
    В табл. 5.2 перечислены все используемые здесь параметры и приведены их значения по умолчанию.
    Таблица 5.2. Параметры фоновой задачи управления роботом
    Параметр
    Значение по

    5
    /5
    40
    36
    48 дюймов
    50
    36 дюймов
    48 дюймов
    -50
    Описание
    Максимальный угол, при котором еще происходит
    медленный поворот
    Угол для средней скорости поворота
    Медленная скорость поворота
    Стандартная скорость поворота
    Скорость быстрого поворота
    Минимальное расстояние до человека
    Предельное расстояние, на котором скорость
    приближения к человеку должна быть максимальной
    Максимальная скорость приближения к человеку
    Минимальное расстояние до человека, на котором
    робот должен начать удаляться от него с максимальной
    скоростью
    Максимальное расстояние до человека, на котором
    робот должен начать удаляться от него с минимальной
    скоростью
    Максимальная скорость при движении от человека

    348 Устройства управления роботами
    Значения этих параметров можно несколько изменить в ту или иную сторону,
    чтобы добиться наиболее естественного поведения робота.
    Разберем простейшую ситуацию. Допустим, робот находится от человека на расстоянии 47 дюймов см) и ориентирован так, что человек оказывается на
    15° левее продольной оси робота. Наши три программы сформируют в этом слу- чае три команды, представленные в табл. 5.3.
    Таблица 5.3. Команды, сформированные программами
    как левый двигатель (соответствующий параметр - будет вращать- ся медленнее правого (соответствующий параметр - Right), то робот будет пово- рачиваться налево, в сторону человека. При этом он будет приближаться к нему,
    пока не окажется слишком близко, после чего либо остановится, либо начнет отъезжать назад. Поведение робота было бы аналогичным, если бы он управлялся с помощью или
    Но приведенная здесь про- грамма заметно проще той, что пришлось написать для реализации ПИД-регуля- тора.
    Еще раз обращаю ваше внимание на тот факт, что все параметры в программе целочисленные. Везде, где это возможно, я старался избегать использования арифметики с плавающей точкой.
    5.6. НЕЙРОННЫЕ СЕТИ И ИСКУССТВЕННЫЙ ИНТЕЛЛЕКТ
    Рассказывая о роботах, было бы невозможно обойти молчанием такое понятие,
    как искусственный интеллект. Многие полагают, что роботы (и наделенные искусственным интеллектом, должны быть столь же разумны, как и человек. В предыдущей главе этой книги мы рассматривали множество различ- ных интерфейсов, позволяющих роботу воспринимать те или иные условия и проявлять Свою реакцию на их изменение, а в этой главе обсудили, как можно реализовать алгоритмы, заставляющие робота демонстрировать окружающим нечто похожее на разумное поведение. Но это были лишь попытки имитировать настоящий интеллект; наши конструкции не только не являлись ра- зумными формами жизни, но даже не могли претендовать на «звание» искусст- венного интеллекта.
    Очень приблизительное определение искусственного интеллекта выглядит следующим образом: это умение машины
    поставленные задачи, пыта-
    противодействие окружающей обстановки и
    то есть
    fuzzy - нечеткий) отличаются от обычных что оперируют близкими человеку качественными понятиями «большой», «средний», «малый» и т.п. - Прим. перев.

    Вдохните в робота жизнь 349
    извлекая из собственного опыта знания, которые затем можно будет
    для того, чтобы
    свои задачи еще более эффективно.
    В этом определении не упоминаются обработка визуальной информации, уме- ние вести разговор или разрушить укрепления противника и другие аналогичные способности, которые, может быть, ассоциируются у многих с термином «искус- ственный интеллект». Легко впасть в заблуждение, если трактовать это понятие слишком широко.
    Но даже реализация интеллекта в представленном здесь узком смысле - не такая уж простая задача. Дело осложняется тем, что мы не можем точно опреде- лить, что же такое «знание» или «обучение».
    Здесь уместно вспомнить известный эксперимент с червяком в лабиринте.
    Червяка помещали в лабиринт, имеющий форму буквы «Т». Двигаясь от основа- ния лабиринта вперед, червяк должен был выбрать, в какую сторону повернуть:
    налево или направо. В одном коридоре его ждал удар электрическим током, а в про- тивоположном - корм. После нескольких неудачных попыток червяк в конце концов запомнил, куда следует иДти, и всегда выбирал коридор с едой.
    Этот эксперимент получил широкую известность благодаря не столько тому,
    что была доказана способность червей к получению простейших навыков, сколь- ко другому замечательному факту. После того как достаточное количество особей было обучено поворачивать в определенном (одном и том же для всех) направле- нии, они были скормлены своим сородичам, которые еще не прошли такого обучения. Спустя некоторое время с насытившимися «новичками» провели ана- логичный эксперимент. Оказалось, что при первом же прохождении лабиринта вместо ожидаемых 50% «попаданий» они выбирали правильное направление в 56%
    Оставляя в стороне вопрос об обучении за обеденным столом, обсудим, каким способом можно заставить программу вести себя так же, как и не слишком интел- лектуальный червяк. Иными словами, после нескольких тренировочных «забе- гов» в лабиринте робот, управляемый нашей программой, наконец должен научить- ся выбирать правильное направление. Если оперировать теми же понятиями, что и в опыте с червями, мы должны как-то запрограммировать боль от удара электри- ческим током и удовольствие, получаемое при приеме пищи (а возможно, и чувство радости от того, что электроды оказались в другом коридоре). Ведь даже заставить программу сделать случайный выбор в самом первом опыте - и то задача не из тривиальных.
    Эксперименты над плоскими червями в лабиринте впервые были проведены американ- ским исследователем в 1912 году. Они показали, что черви способны обучаться и переобу- чаться, но полученный навык держался недолго (10-15 ч). Затем подобные эксперименты в различ- ных модификациях (в том числе и опыты с кормлением необученных особей обученными) были повторены многими учеными. Справедливости ради следует заметить, что многие исследователи оспа- ривают существование эффекта передачи опыта при кормлении, так как при повторении экспериментов не получили аналогичного результата. Те же, кому удалось зафиксировать передачу навыков столь без- жалостным образом, расходятся друг с другом в объяснении данного феномена. Диапазон предположе- ний довольно широк - от передачи информации на уровне РНК до телепатии. - Прим.

    350 Устройства управления роботами
    Когда речь идет о тренировке животных (или человека), все эти вопросы инту- итивно понятны и близки нам, но как перевести их на язык программирования?
    Как заставить робота или компьютер чувствовать голод, жажду, боль, удоволь- ствие?
    При рождении мы получаем некоторый стандартный набор рефлексов, зало- женных на генетическом уровне, и с их помощью постепенно обучаемся жить в мире,
    руководствуясь соответствующими концепциями и обобщая свой опыт каким-то неосознаваемым способом.
    В детстве я однажды довольно сильно обжег руку утюгом. До сих пор, когда в моем сознании совмещаются образы боли, одежды, утюга и руки, я всегда вспо- минаю о том случае, и мое тело автоматически делает шаг назад, а рука отдергива- ется, дабы уберечься от ожога. После этого я много раз обжигался в разных мес- тах, но ни один из этих инцидентов (хотя некоторые из них тоже были весьма болезненными) не оставил в моей памяти такого заметного следа, и я не пытаюсь инстинктивно защитить другую руку или ногу. Уверен, вы тоже сможете припом- нить какой-нибудь случай из своей жизни, когда некоторая комбинация внешних воздействий глубоко врезалась в вашу память и с тех пор при возникновении похожих ситуаций вы инстинктивно действуете так, чтобы оградить себя от по- вторения неприятных
    По большому счету, обучение людей или животных не должно отличаться от обучения компьютеров. Вспомните приведенное выше определение искусствен- ного интеллекта - ведь оно похоже на описание действий любого разумного су- щества, хотя, к сожалению, не дает нам возможности понять, как именно мы обобщаем наблюдаемые факты, чтобы выбрать эффективный способ действий.
    Я верю в то, что в ближайшем будущем появятся компьютерные программы,
    которые смогут и сдать экзамен, и поддержать разговор, но их, скорее всего, нельзя будет сравнить с настоящим (пусть даже и искусственным) интеллектом, если они не будут обладать возможностью обучаться, подобно тому как это делают живот- ные и человек. Вероятно, пройдет немало лет, прежде чем ученые действительно смогут понять, как можно научить программы воспринимать и обобщать инфор- мацию, приходящую из окружающего мира.
    Современное состояние науки об искусственном интеллекте позволяет пред- положить, что первые шаги к пониманию принципов работы нашего сознания мы можем преодолеть, изучая работу основных клеток, из которых состоит мозг жи- вотных и человека, - нейронов.
    Эксперименты с искусственными моделями нервных клеток ученые начали проводить в 40-х годах XX века, пытаясь имитировать работу мозга. Большое
    Если читатель увлекается не только программированием, но и психологией,
    вероятно, слышал о нейролингвистическом программировании (НЛП), в котором среди прочих используется техника так называемых «якорей», когда за той или иной комбинацией внешних воздействий психотерапевт закрепляет в подсознании человека нужную реакцию. - Прим. перев.

    Вдохните в робота жизнь 351
    количество нейронов соединялось, образуя так называемые искусственные ней-
    ронные сети.
    Если вы знакомы с цифровой электроникой, то можете представить нейрон в виде некоторого многовходового логического элемента (AND, OR, XOR и т.п.).
    Но на самом деле это аналоговый элемент, который воспринимает несколько вход- ных сигналов, причем имеет различную чувствительность к тем сигналам, кото- рые поступают на разные его входы. Суммарное воздействие всех входных сигна- лов определяет нейрона - степень его возбуждения. Эта величина подвергается обработке и в виде результирующего сигнала подается на единствен- ный выход нейрона. Выходной его сигнал, в свою очередь, является входным для многих других нервных клеток, которые соединены с рассматриваемым нейроном.
    Можно придумать несколько хороших определений нейронной сети, но наи- лучшее из них выглядит следующим образом: нейронная сеть - это один или множество связанных друг с другом простых процессорных элементов, работаю- щих параллельно, функционирование которых зависит от структуры сети, степе- ни связи между элементами и алгоритма их
    Проще говоря, нейронная сеть - это набор связанных элементов, каждый из которых воспринимает свои входные сигналы и вырабатывает по некоторому правилу выходной сигнал. На рис. 5.2 показан пример простой нейронной сети,
    которая по состоянию двух световых датчиков и двух детекторов столкновений формирует команды для двух двигателей робота.
    Рис.
    Нейронная сеть
    двигателями робота
    На языке математики все это можно описать простой формулой:
    Выходы = f (Входы),
    где f - некоторое правило, согласно которому набор значений входных сигналов преобразуется в соответствующий набор значений выходных сигналов.
    DARPA Neural Network Study, 1988. - AFCEA International Press. - P. 60.

    352 Устройства управления роботами
    Алгоритм, определяющий правило, может быть реализован с помощью логических функций, конечно-автоматных моделей или просто в виде некоторой последовательности операторов любого языка программирования, но важно по- нимать, что данный алгоритм не предопределяет реакцию сети на то или иное входное воздействие, а только описывает способ, который используется нейрон- ной сетью для ее обучения.
    Такое обучение строится на примерах, что позволяет провести аналогию с тре- нировкой животных. На вход сети подается тот или иной набор внешних воздей- ствий, и выходные сигналы сравниваются с теми, которые мы желали бы иметь в данных условиях. Если ошибка сети (разница между желаемым и действитель- ным значениями выходного сигнала) велика, то чувствительность входов каждо- го нейрона по определенным правилам изменяется таким образом, чтобы снизить эту ошибку. Так повторяется много раз для различных наборов входных воздей- ствий и соответствующих наборов желаемых реакций, пока сеть не научится пра- вильно реагировать на предлагаемые воздействия.
    Очень важно правильно выбрать структуру нейронной сети, то есть количе- ство составляющих ее нейронных элементов и связи между ними. Если нейронов будет слишком мало или связи между ними окажутся неэффективными, то сеть не сможет научиться тем вещам, которым мы хотим ее обучить. Если нейронов,
    наоборот, будет слишком много, то процесс обучения грозит затянуться на не- определенное время.
    После начальной тренировки сеть может быть использована для управления роботом, но при этом ее обучение продолжится, если она сама будет способна каким-то образом оценивать качество своего поведения. Например, показанная на рис. 5.2 нейронная сеть может следить за временем, которое потребовалось ей на то, чтобы в определенной ситуации найти источник света, минимальное количе- ство раз столкнувшись с окружающими предметами.
    Кроме имитации поведения бабочки, летящей на свет, такой механизм обучения может быть использован и для более полезных применений, например для управле- ния захватом робота-манипулятора, который должен найти и подобрать определен- ный предмет. Человек делает это совершенно не задумываясь, но программирование такой задачи традиционными методами довольно затруднительно.
    Способ обучения нейронной сети, основанный на примерах, может быть реа- лизован различными способами. По существу, такое обучение сродни тренировке собак: дрессировщик дает команду, после чего поощряет правильное ее выполне- ние и наказывает за неправильное. Это многим показажется удивительным, но существуют также методы обучения без учителя, когда на входы нейронной сети подаются различные наборы воздействий, но никто не говорит ей, какими в каж- дом из этих случаев должны быть ее выходные сигналы.
    Для выбора правильного набора параметров нейронной сети можно использо- вать так называемые генетические алгоритмы. Они, как и сами нейронные сети,
    заимствованы исследователями у живой природы, поскольку основаны на имита-

    Вдохните в робота жизнь 353
    происходящих в ней процессов размножения, изменчивости и естественного отбора. Генетический алгоритм позволяет набору (популяции) нескольких ней- ронных сетей, предназначенных для решения некоторой задачи, эволюциониро- вать таким образом, чтобы в результате сформировать сеть, которая смогла бы решить эту задачу самым эффективным образом.
    Обладает ли нейронная сеть искусственным интеллектом? Многие исследова- тели склонны ответить на этот вопрос положительно, ведь способ формирования реакции нейронной сети на входные воздействия очень напоминает процесс при- нятия решений живыми организмами. Но, на мой взгляд, это было бы правильнее назвать «искусственным рефлексом». Пока что нейронная сеть скорее моделиру- ет рефлекторное движение руки человека, стукнувшего молотком по своему паль- цу, чем проявление настоящего интеллекта.
    12-2101

    1   ...   25   26   27   28   29   30   31   32   33


    написать администратору сайта