URBI — введение в urbiScript — часть 4


1. введение в urbiScript — часть 1
2. введение в urbiScript — часть 2
3. введение в urbiScript — часть 3
4. введение в urbiScript — часть 4

Продолжаем рассмотрение возможностей скриптового языка urbiScript от компании Gostai, предназначенного для управления роботами.

urbiScript выполняется на Urbi-сервере, который запускается либо на роботе, либо на компьютере и к которому можно подключиться через сеть обычным telnet-ом.

Основной особенностью и краеугольным камнем urbiScript является параллельная работа

23. Операторы параллельной работы

Пока мы рассматривали завершение операторов и команд символом точки с запятой (;).
Однако существует и другие операторы разделения команд:

«;» — последовательно. Перед продолжением — ждать пока левый оператор завершит работу.
«&» — параллельно. Все операторы начинают работу одновременно и выполняются параллельно. Блок & завершает работу, когда все операторы завершили работу. & имеет более высокий приоритет чем другие операторы разделения.
«,» — в фоновом режиме. Левый оператор запускается и начинается выполнение правого оператора.
Этот оператор связывается с областью применения: при использовании внутри области,
область завершает работу только тогда, когда все операторы, работающие в фоновом режиме с помощью ‘,’ ,завершат работу.
«|» — один за другим. Правый оператор запускается немедленно после левого (создаётся атомарность для параллельных задач)

Пример демонстрирует использование разделителя & для запуска двух функций одновременно(параллельно).

function test(name)
{
	echo(name + ": 1");
	echo(name + ": 2");
	echo(name + ": 3");
} |;
// последовательное выполнение
test("left") ; test ("middle"); test ("right");
[00000000] *** left: 1
[00000000] *** left: 2
[00000000] *** left: 3
[00000000] *** middle: 1
[00000000] *** middle: 2
[00000000] *** middle: 3
[00000000] *** right: 1
[00000000] *** right: 2
[00000000] *** right: 3
// параллельное выполнение
test("left") & test("middle") & test ("right");
[00000000] *** left: 1
[00000000] *** middle: 1
[00000000] *** right: 1
[00000000] *** left: 2
[00000000] *** middle: 2
[00000000] *** right: 2
[00000000] *** left: 3
[00000000] *** middle: 3
[00000000] *** right: 3

Разница между «&» и «,» довольно тонкая:
* операторы связанные «&» не запустятся пока все операторы не будут известны. Т.е. написав строчку заканчивающуюся оператором «&» система будет ждать правого оператора (например «,» или «;«) и затем запустит операторы на выполнение. Оператор же заканчивающийся «,» запустится на выполнение сразу.
* выполнение блокируется после того как все операторы группа «&» завершили работу.

function test(name)
{
	echo(name + ": 1");
	echo(name + ": 2");
	echo(name + ": 3");
} | {};
// запуск test() и функции echo("right") параллельно,
// и ожидание пока оба завершатся перед тем как продолжить выполнение
test("left") & echo("right"); echo("done");
[00000000] *** left: 1
[00000000] *** right
[00000000] *** left: 2
[00000000] *** left: 3
[00000000] *** done
// запуск test() в фоновом режиме, затем обе функции echo() без ожидания
test("left") , echo("right"); echo("done");
[00000000] *** left: 1
[00000000] *** right
[00000000] *** left: 2
[00000000] *** done
[00000000] *** left: 3

// Пример "|"
// параллельные задачи выполняются в перемешку
{
	{ echo("11") ; sleep(100ms) ; echo("12") },
	{ echo("21") ; sleep(400ms) ; echo("22") },
};
[00000316] *** 11
[00000316] *** 21
[00000316] *** 12
[00000316] *** 22
// между задачами объединёнными при помощи | другие задачи вклиниться не могут
{
	{ echo("11") | echo("12") },
	{ echo("21") | echo("22") },
};
[00000316] *** 11
[00000316] *** 12
[00000316] *** 21
[00000316] *** 22

23.1 Отделение — detach

Функция Control.detach запускает выполнение в фоновом режиме, как и оператор «,» ,но выполнение полностью отделено и не ожидает завершения работы области.

function test()
{
	// ждём одну секунду, и выводим "foo".
	detach({sleep(1s); echo("foo")});
}|;
test();
echo("Not blocked");
[00000000] Job
[00000000] *** Not blocked
sleep(2s);
echo("End of sleep");
[00001000] *** foo
[00002000] *** End of sleep

24. Теги

Тег — это объект, помещающий блок кода для внешнего контроля его выполнения. Выполнение кода может быть заморожено, возобновлено, остановлено.

Любой кусок кода можно обозначить тегом. Для этого достаточно написать имя тега и поставить двоеточие (:). Тег так же можно создать через Tag.new(«name»). Название тега опционально.

// создание нового тега
var mytag = Tag.new("name");
[00000000] Tag
// тег связывается с выполнением 42
mytag: 42;
[00000000] 42
// тег связывается с выполнением блока
mytag: { "foo"; 51 };
[00000000] 51
// тег связывается с вызовом функции
mytag: echo("tagged");
[00000000] *** tagged

Можно использовать тег, который не был объявлен ранее; при этом он будет создан автоматически.
Однако это не рекомендуется, т.к. тег будет создан в глобальной области.

// Если mytag не объявлен, то это приведёт к выполнению:
// var Tag.mytag = Tag.new("mytag");
mytag : 42;
[00000000] 42

Теперь можно рассмотреть какие методы контроля предоставляет тег:

freeze — приостанавливает выполнение кода
unfreeze — возобнавляет выполнение приостановленного кода
stop — останавливает выполнение кода. Поток выполнения, который останавливается командой stop мгновенно перепрыгивает на конец блока кода связанного с тегом.
block — блокирует выполнение кода:
* останавливает код
* если поток выполнения встречает заблокированный код — он просто пропускается.
unblock — разблокирует код.

Примеры работы данных методов:

// в фоновом режиме запускаем код, который печатает "ping"
// каждую секунду. Тег mytag используется для контроля
mytag:
	every (1s)
		echo("ping"),
sleep(2.5s);
[00000000] *** ping
[00001000] *** ping
[00002000] *** ping
// приостановим выполнение
mytag.freeze;
// больше не печатает :)
sleep(1s);
// возобновим работу
mytag.unfreeze;
sleep(1s);
[00007000] *** ping
// Теперь, в случае завершения тега - распечатываем сообщение.
{
mytag:
	every (1s)
		echo("ping");
	// этот код выполнится при остановке кода тега
	echo("Background job stopped")|
},
sleep(2.5s);
[00000000] *** ping
[00001000] *** ping
[00002000] *** ping
// остановим выполнение
mytag.stop;
[00002500] *** Background job stopped
// код остановлен, поэтому метод
// unfreez не работает.
mytag.unfreeze;
// Теперь, печатаем сообщение когда выполняем код тега
loop
{
	echo("ping"); sleep(1s);
	mytag: { echo("pong"); sleep(1s); };
},
sleep(3.5s);
[00000000] *** ping
[00001000] *** pong
[00002000] *** ping
[00003000] *** pong
// блокируем вывод pong
mytag.block;
sleep(3s);
// половина кода цикла больше не выполняется
[00004000] *** ping
[00005000] *** ping
[00006000] *** ping
// разблокируем pong
mytag.unblock;
sleep(3.5s);
[00008000] *** pong
[00009000] *** ping
[00010000] *** pong
[00011000] *** ping

24.1 Продвинутый пример использования параллельного выполнения и тегов.

В примере показано применение функции timeOut, которая принимает в качестве аргументов код для выполнения и время выполнения кода.
Функция выполняет код выполняется и возвращает его значение.
Однако, в случае если время выполнения кода превышает заданный предел — код останавливается, выводится надпись «Timeout!» и возвращается void.

В данном примере используются:
* ленивые аргументы
* операторы параллельного выполнения кода для запуска кода контроля времени в фоновом режиме

// timeout (код, продолжительность).
function timeOut
{
// в фоновом режиме запускаем код контроля времени, 
// который просто ожидает заданное время перед тем как остановить функцию
// call.evalArgAt(1) - второй аргумент функции - продолжительность.
{
	sleep(call.evalArgAt(1));
	echo("Timeout!");
	return;
},
// выполняем код и возвращаем его значение
return call.evalArgAt(0);
} |;
timeOut({sleep(1s); echo("On time"); 42}, 2s);
[00000000] *** On time
[00000000] 42
timeOut({sleep(2s); echo("On time"); 42}, 1s);
[00000000] *** Timeout!

Читать далее: введение в urbiScript — часть 5


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение