RCML
RCML (англ. Robot Control Meta Language, произносится [ар-си-эм-эль] — компилируемый статически типизированный язык программирования высокого уровня. Разработан для получения одинакового результата независимо от исполнения робота[1]. Позволяет создавать условия для совместной работы нескольких роботов. Используется для описания действий робота или группы роботов[2]. Включает ряд визуальных аспектов представления кода относительно классов и объектов из языков программирования, реализующих парадигму объектно-ориентированного программирования[3]. Введение в RCMLЦели RCML
Связанные области
Синтаксис RCMLСинтаксис RCML близок к языкам программирования C, Java и JavaScript. Сходство синтаксиса необходимо для обеспечения лёгкого перехода для программистов с других языков[4]. Особенности RCMLRCML ориентирован на робототехнику и имеет довольно скудную составляющую как язык программирования, так как не предназначается для создания прикладного ПО общего назначения и нацелен на взаимодействие с робототехникой, позволяя достигать в этом отношении новых результатов. Понятие робота в RCMLРобот в RCML представляется как некий исполнительный ресурс, который может быть задействован для выполнения определённой задачи (функции), а затем освобождён для повторного задействования, но, например, в уже другой задаче. Модуль робота предоставляет среде RCML описание класса робота, закреплённого за ним, предполагается, что локально в объектном мире, где используется RCML, может быть, как один, так и несколько роботов одного класса, закреплённых за одним модулем робота. Причём в среде RCML в рамках модуля робота присутствует два ключевых типа объектов, в соответствии с рисунком: ![]()
Следует отметить, что может быть подключено много классов роботов одновременно, то есть много модулей роботов, и каждый из них может предоставлять доступ сразу к нескольким роботам своего класса. Роботы в рамках одного класса должны быть одинаковы полностью, как в физическом представлении, так и в функциональном. Модули роботов![]() Модули роботов занимают одно из ключевых положений в RCML, поскольку именно через них осуществляется связь и передача команд физическому роботу. Модуль робота отвечает за передачу команд от интерпретатора RCML одному или нескольким роботам одного класса (или типа), которые объединены под этим модулем. Рекомендуется для каждого класса или типа робота использовать отдельный модуль. Интерпретатор RCML через задекларированный API устанавливает связь с модулем робота, который в свою очередь устанавливает связь с каждым закреплённым за ним роботом. Таким образом, через модуль робота скрывается реализация связи и управления роботом от интерпретатора, что позволяет подключать к нему самых разных роботов. Модули функцийЧерез модули функций возможно добавление в RCML новых функций, которые не целесообразно или невозможно реализовывать на данном языке, например, какие-либо сложные вычисления. Таким образом, через отдельный API модули функции позволяют реализовать связь RCML с программным обеспечением других производителей. Модули управленияМодули управления служат для связи различных управляющих устройств со средой RCML с целью использования данных устройств в ручном управлении роботами, чьи модули предоставляют такую возможность. Данный тип модулей подобен модулям роботов в том плане, что через заданный API происходит разрыв зависимостей между управляющим устройством и роботом. Таким образом, реализуется возможность управления одним и тем же роботом разными устройствами, а также возможность применения одного и того же устройства управления для разных роботов. Разумеется, при этом достигается тот же эффект сокрытия реализации связи устройства управления от среды RCML и достигается возможность подключения самых разных устройств управления. Использование робота в программеЧтобы задействовать робота в программе, необходимо указать его класс и функцию, которую он должен выполнить. Именование класса робота совпадает с именованием модуля робота в файле config.ini, но класс робота в RCML программе должен указываться через ключевое слово robot и знак подчёркивания. Например, нужно вызвать робота из модуля test, тогда указание его класса будет иметь вид:
Встретив наименование класса робота в тексте программы, RCML пошлёт запрос к соответствующему модулю робота и остановит выполнение программы, пока не будет найден свободный робот требуемого класса. Вызов функции роботаФункции роботов программируются разработчиком робота вместе с модулем робота и описываются в документации к модулю робота. Вызов функции визуально похож на вызов метода объекта в С-подобных языках программирования. Следует указание класса робота, затем через знак указателя Синтаксис вызова функции робота:
Пример вызова функции do_something из модуля робота test Например, из робота класса test нужно вызвать функцию do_something с одним аргументом 1000:
Встретив подобную конструкцию, интерпретатор зарезервирует робота указанного класса, дождется, когда будет задействован реальный физический робот, и затем передаст команду представлению робота об исполнении указанной функции с указанными параметрами. После исполнения функции робот будет автоматически освобожден и переведен в статус свободного. Следует отметить, что при таком указании вызова функции робота интерпретатор дождётся подтверждения выполнения функции от представления робота и только затем продолжит выполнение остальной программы. Работа с конкретным экземпляром роботаЧасто бывает необходимо вызвать не одну функцию у робота, а сразу несколько, и их должен выполнить один робот как заданную последовательность действий. Если вызвать необходимую последовательность функций, то при наличии нескольких роботов одного класса вполне вероятно, что заданные функции будут выполняться разными роботами. В случае если же робот заданного класса всего один в наличии, то для каждой функции он будет каждый раз задействован и освобождён. Наиболее эффективно и рационально задействовать робота единожды и передавать ему команды так, как это необходимо, а затем его освободить, таким образом реализовав сеанс работы робота. Для этого требуется задействовать робота нужного класса и запомнить связь с задействованным конкретным роботом. Это можно сделать, сохраняя робота в специальный тип переменных, перед идентификатором которых должен быть поставлен символ
Чтобы вызвать выполнение функции у данного задействованного робота, нужно вызывать функцию, обращаясь к данной переменной, а не к классу робота. Например, вызов у используемого робота той же самой функции
После выполнения функции робот так же останется задействованным, и можно вызывать следующую функцию у данного экземпляра. Высвобождение задействованного роботаРобота, сохранённого в тип переменной
Все роботы, задействованные и не освобождённые через оператор Автоматический выбор роботаОдна из возможностей RCML — это автоматический подбор робота под задачу. Чтобы использовать данную возможность, нужно указывать только ключевое слово robot вместо конкретного класса робота в тех местах, где требуется указание класса робота: вызовы функций робота или присвоение робота в переменную. Например: robot->do_something(1000);
@r = robot;
@r->do_something();
Использование только ключевого слова В случае использования специальной переменной Указание режимов выполнения функцийИсполнение функций, написанных на RCML, может выполняться в двух основных режимах:
В случае выполнения функции «без ожидания», создаваемый поток может быть перенесён в отдельное вычислительное ядро средствами ОС, и таким образом может быть получен эффект параллельного выполнения кода на RCML. По умолчанию все функции вызываются в режиме с ожиданием выполнения функции. Этот режим является режимом по умолчанию. Сменить режим выполнения функций можно несколькими способами:
Пример использования флагов выполнения функции В программе используется два робота. В данном случае роботы представлены тестовым модулем, который симулирует работу абстрактного робота. По умолчанию режим выполнения функций с ожиданием. function main() {
@rt_1=robot_test;
@rt_2=robot_test;
@rt_1->do_something(1000);
@rt_2->print("Hello world!\n", 0);
} В результате выполнения программы тестовый робот Однако, если использовать флаг без ожидания function main() {
@rt_1=robot_test;
@rt_2=robot_test;
~@rt_1->do_something(1000);
@rt_2->print("Hello world!\n", 0);
} Выполнение программы будет происходить следующим образом. После того как передана команда ИсключенияRCML позволяет обрабатывать исключительные ситуации, аналогично языкам программирования C, Java и JavaScript. Однако в RCML, оператор Всего у оператора
Несмотря на то, что оператор Пример использования указанных режимов Пример использования указанных режимов для обработки успешности выполнения роботом своей функции с выдачей ему трёх попыток с лимитом времени по 2 секунды на каждую: function main() {
try("error_try_count", 3) {
try(“error_time_limit”, 2000) {
robot->do_something();
} catch { //если время вышло
throw; //то бросаем исключение, чтобы исчерпать попытку
}
} catch {
//этот блок выполнится, когда все попытки будут исчерпаны,
//а результат так и не будет получен
}
}
Через оператор Режим ручного управленияСреда RCML может предоставить возможность ручного управления конкретным экземпляром робота посредством конкретного управляющего устройства при вызове системной функции Основной принцип действия среды RCML при переходе в режим ручного управления заключается в связывании осей робота, по которым он может так или иначе передвигаться, с осями управляющего устройства, по которым данное устройство может фиксировать изменения. ![]() На рисунке есть гусеничный робот (изображён слева), который может переходить в своё новое абсолютное положение на плоскости посредством ряда изменений своего положения по двум осям: оси передвижения @r = robot_tarakan;
hand_control(@r, “joy”, “R”, “Y”, “A”, “X”);
Пакетная передача команд роботамУ представления робота в среде RCML есть очередь команд, которая наполняется командами путём вызова функций робота из кода на RCML. При поступлении команды в пустую очередь, команда будет передана роботу на исполнение. Пока исполняется первая команда, все вновь поступившие команды становятся в очередь. Робот выполняет функцию в материальном мире обычно медленнее, чем RCML интерпретатор успевает выполнить очередной код на RCML и дойти до следующего вызова функции робота, т.е. обычно действия робота "медлительнее" действий вычислительного процессора. Однако бывает иная ситуация, когда роботу необходимо выполнить серию быстрых перемещений без остановки, а расчёт параметров этих перемещений занимает больше времени, чем выполняется перемещение. Тогда эффективнее заранее рассчитать параметры перемещений и передать роботу сразу пакет команд с рассчитанными параметрами, чтобы робот не замедлялся в ожидании очередной команды. Бывают ситуации, что сам механизм вызова функций работает медленнее, чем робот исполняет команды, и возникает задержка в быстрой серии перемещений. Чтобы скомпенсировать этот эффект, был введён механизм пакетной передачи команд роботу. Команды, получаемые посредством вызова функций робота, можно скомпоновать в единый пакет и передать целиком представлению робота. Чтобы отправить команду в пакет, нужно поставить перед вызовом функции символ Пример отправки команды в пакете //отправка команды в пакет
>robot_test->do_something(1000);
//отправка пакета на выполнение
system.send_package(); В данном примере сначала будет послан запрос на свободного робота класса Возможно составление пакета сразу для двух роботов, команды из этого пакета будут переданы сразу двум представлениям роботов, дополнительно можно комбинировать типы вызовов функций. Пример составления пакета команд для двух роботов >robot_test->do_something(1000);
>robot_test->do_something(1000);
system.send_package();
Согласно данному примеру, будут задействованы два робота одновременно, а не один и тот же два раза подряд. В таком случае, выполнение первых команд в очереди каждого представления робота начнётся одновременно. Данный механизм позволяет синхронизировать начало выполнения разными роботами своих команд. Примеры на RCMLПростейшая программа на RCMLПростейшая программа на RCML имеет следующий вид: function main() {
return;
}
Программа сразу после запуска завершит работу. Программа "Hello,_world!Вывод в консоль строки "Hello world!", через модуль тестового робота. function main() {
robot_test->print("Hello world!\n", 0);
}
Пример программы работающей с пулом роботовКак отмечалось ранее RCML ориентирован на работу с пулом (множеством) роботов, из которого выделяются исполнители для решения динамически возникающих задач. Пусть есть пул роботов, некоторые роботы из этого пула способны выполнить необходимую технологическую функцию function main() {
loop {
have_new_task = get_data_from_sensor();
if (have_new_task) {
~robot->do_something();
}
system.sleep(300);
}
}
В данной программе в цикле с интервалом 300 мс, опрашивается внешний сенсор посредством функции В случае если через очередные 300 мс, снова потребуется выполнение функции, а первый задействованный робот ещё не закончил работу, то RCML задействует второго робота из пула, и т.д. После выполнения заданной функции роботы будут автоматически освобождены и возвращены в общий пул. В случае если все роботы будут задействованы, программа будет ожидать освобождения робота. Данный приём позволяет динамически распределять среди роботов задачи из очереди и задействовать сразу нескольких роботов. Пример программы для работы с пулом разнотипных роботовПусть имеется задача перемещения деталей весом от 1 до 15 кг, детали поступают последовательно, однако их необходимо перемещать по возможности наиболее быстро. Имеется пул разнотипных роботов, среди которых роботы класса function main() {
loop {
detail_weight = get_weight_from_sensor(); //Получение веса детали
if (detail_weight < 5) { //Если вес до 5 кг
~robot->move_detail(); //Можно задействовать любого робота
}
if ((detail_weight >= 5) && (detail_weight < 10)) { //Если вес от 5 до 10 кг
~robot_heavy->move_detail(); //Можно задействовать только более грузоподъемного робота
}
if (detail_weight >= 10) { //Если вес от 10 кг
>robot_heavy->move_detail(); //Один робот обязательно должен быть более грузоподъемный
>robot->move_detail(); //Второй робот может быть любым
~system.send_package(); //Отправка пакета команд для роботов на выполнение
}
system.sleep(300);
}
}
В случае если вес детали менее 5 кг, то деталь может нести робот любого класса, строка 5. Однако, RCML сначала опросит всех роботов класса Однако в случае, если вес детали от 5 до 10 кг, то можно задействовать только более грузоподъемного робота, строка 7. В случае если вес детали от 10 кг, то надо задействовать двух роботов, среди которых один должен быть более грузоподъёмным, а второй любым. Стоит отметить, что в данном случае команда на перемещение детали передаётся двум роботам одновременно, посредством механизма составления пакетов команд (строки 11-15). Следует отметить, что данный пример предполагает, что детали поступают строго последовательно, т.е. следующая деталь поступает только тогда, когда робот забрал предыдущую и переносит её некоторое время. Таким образом, очередь заданий для роботов также последовательна и в случае, если поступает несколько тяжёлых деталей, а затем лёгкая, то лёгкая деталь будет перемещена, только когда все тяжёлые детали будут перемещены, из-за этого возможен простой роботов класса Пример программы с непоследовательным выбором роботами задач из очередиУсложним предыдущий пример. Пусть детали поступают в некий контейнер беспорядочно, система технического зрения наблюдает контейнер и распознает детали в нём, получая координаты и тип детали, а по типу определяет её вес. При распознавании очередной детали нужно поставить задачу роботам на перемещение детали. При распознавании деталей некая функция function executeMoveTask(detail_index) {
detail_weight = get_weight_by_index(detail_index); //Получение веса детали
detail_coords = get_coords_by_index(detail_index);
if (detail_weight < 5) { //Если вес до 5 кг
~robot->move_detail(detail_coords); //Можно задействовать любого робота
}
if ((detail_weight >= 5) && (detail_weight < 10)) { //Если вес от 5 до 10 кг
~robot_heavy->move_detail(detail_coords); //Можно задействовать только более грузоподъемного робота
}
if (detail_weight >= 10) { //Если вес от 10 кг
>robot_heavy->move_detail(detail_coords); //Один робот обязательно должен быть более грузоподъемный
>robot->move_detail(detail_coords); //Второй робот может быть любым
~system.send_package(); //Отправка пакета команд для роботов на выполнение
}
}
function main() {
loop {
new_detail_index = get_new_detail_index(); //Получение очередного индекса детали
if (new_detail_index) { //Новая деталь поступила
~executeMoveTask(new_detail_index); //Выполняем задачу по перемещению
}
system.sleep(300);
}
}
В данном примере при поступлении новой детали в контейнер, будет получен её уникальный индекс (строка 19), который будет передан в функцию В сумме это даёт следующий эффект: если в контейнер поступило некоторое большое количество тяжёлых деталей весом до 10 кг, и из пула свободных роботов были задействованы все грузоподъёмные роботы Пример создания RCML программы, универсальной для разных классов роботовRCML даёт возможность программисту явно указать, что некоторые роботы могут выполнять одну и ту же функцию одинаково и тем самым они могут считаться взаимозаменяемыми при выполнении данной функции, хотя при этом роботы имеют различный API предоставляемый для программиста на уровне RCML. В вышеприведённых примерах встречаются строки вида Пусть у классов роботов Следующий пример показывает как унифицировать API роботов в рамках конкретной программы, чтобы разные классы роботов могли выполнять одну и ту же функцию. function robot_heavy::move_to(x, y, z, w, p, r) {
//Далее следует код для перемещения в заданную точку,
//путём обращения к функциям специфичным для роботов класса robot_heavy
robot->set_real_di("x",x);
robot->set_real_di("y",y);
robot->set_real_di("z",z);
robot->set_real_di("w",w);
robot->set_real_di("p",p);
robot->set_real_di("r",r);
robot->go_position();
}
function robot_heavy::gripper(s) {
//Специфичный, для robot_heavy, код управления захватом
if (s) {
robot->set_gripper_pos(124,25);
} else {
robot->set_gripper_pos(350,50);
}
}
function robot_light::move_to(x, y, z, w, p, r) {
//Специфичный, для robot_light, код перемещения захвата
robot->move_to(x,y,z);
robot->set_angle(w,p,r);
}
function robot_light::gripper(s) {
//Специфичный, для robot_light, код управления захватом
if (s) {
robot->pump_on();
} else {
robot->pump_off();
}
}
function main() {
//Универсальный код для перемещения детали роботом любого класса
robot->move_to(46,76,73,235,-34,23); //Переместиться к заготовке
robot->gripper(1); //Захватить деталь
robot->move_to(235,34,47,262,673,74); //Переместить деталь к позиции 1
system.sleep(15000); //Ожидать время измерения детали на позиции 1
if (some_check()) {
//Переместить захват робота к контейнеру с качественными деталями
robot->move_to(35,63,23,25,-48,245);
robot->gripper(0); //Освободить деталь
} else {
//Переместить захват робота к контейнеру с браком
robot->move_to(568,778,346,-54,2,34);
robot->gripper(0); //Освободить деталь
}
}
В данном случае алгоритм перемещения и проверки сможет выполнять как класс роботов См. такжеПримечания
Литература
Ссылки
|