Использование Remote API в робосимуляторе V-REP

из песочницы
ar1 6 октября 2015 в 11:16 12,6k


V-REP представляет собой среду для симулирования (sandbox) различных видов роботов, при этом пользователю нет необходимости иметь физический доступ к реальной машине, что экономит деньги и время. Среда V-REP предоставляет удобный интерфейс для визуализации действий робота в трёхмерном виртуальном пространстве намного раньше, чем реальный прототип робота будет создан. При помощи данного руководства вы убедитесь, что для того, чтобы работать в данной среде, программисту не нужно иметь большого технического опыта в области роботостроения.

Причиной создания данного руководства стало отсутствие (на то время) знаний языка Lua, на котором по умолчанию написаны все скрипты управления роботом, и его меньшая популярность. Цель данного руководства показать как пользоваться удалённым (Remote) API данной среды на примере языка Python.

Для начала скачайте версию для Академических целей (Non-limited EDUCATIONAL) для своей ОС с официального сайта.

После установки и запуска программы откроется основное окно программы.



Когда вы открываете среду V-REP, она инициализирует сцену по умолчанию. Пользователь может открывать несколько сцен параллельно, но отображается только текущая.

Панель инструментов содержит набор кнопок, основными из которых являются кнопки для запуска и остановки сцены.



Также инструменты для работы с камерой. Для перемещения и изменения угла просмотра, приближение.



Для работы с элементами помещенными на сцену существуют следующие инструменты: “выделяемость” объекта по нажатию, перемещение и изменение угла расположения объекта. При этом у выделенного объекта появляются дополнительные оси, за которые удобно перемещать и поворачивать.



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



Как вы заметили, справа от имени некоторых объектов есть различные иконки. Таким образом отображаются зависимые Lua-скрипты, которые можно просмотреть по двойному нажатию. У самой сцены есть главный скрипт, редактировать который не рекомендуется. А у других объектов собственные, которые можно добавлять, редактировать и изменять в соответсвии с вашими потребностями.

Давайте добавим что-нибудь на нашу сцену. V-REP содержит целую коллекцию разнообразных роботов, которых можно предварительно посмотреть в обзорщике моделей (Tools | Model browser). Для добавления нужной модели необходимо лишь перетащить её на сцену. При этом важно, чтобы сцена при перетаскивании была остановлена, иначе ваши изменения не будут сохранены.



Также в среде доступны все основные примитивы, добавить которые можно, нажав правую кнопку мыши на сцене и выбрав соответсвующие пункты меню.

Например, добавим на нашу сцену куб, выбрав Add | Primitive shape | Cuboid.



И выставим в появившемся меню размеры 0.400 x 0.400 x 0.400. (Соответсвующие метрической системе).





Давайте посмотрим как взаимодействовать с V-REP посредством предоставляемым им Remote API, который позволяет писать сценарии для среды на различных языках, среди которых C/C++, Python, Java, Matlab/Octave и Urbi.

  • Для начала создайте папку для нашего нового проекта.
  • Затем создайте новую сцену или удалите/отмените изменения на сцене по умолчанию.
  • Сохраните сцену, например как myFirstScene. В результате создастся файл myFirstScene.ttt
  • Далее вам необходимо скопировать несколько файлов из директории с установленной программой. Зайдите в неё. В ней содержится папка programming, затем в remoteApiBindings, из которой вам нужно скопировать несколько файлов в созданную ранее папку для проекта. А именно файлы из папки python (vrep.py, vrepConst.py, simpleTest.py). И файлы из папки lib в соответсвии с разрядностью вашей ОС (это может быть remoteApi.so или remoteApi.dll).

Добавим на сцену модель робота pioneer p3dx. Для этого в обзорщике моделей в дереве robots выберите mobile и перетащите робота на сцену.



Если сейчас нажать на кнопку Play (Старт сцены), то робот поедет в прямом направлении, логика его работы содержится в прикреплённом скрипте, который мы скоро заменим на наш Python-скрипт.

Если внимательно изучить из чего состоит данная модель в Иерархии сцены (Scene hierachy), то можно заметить, что данный робот состоит из пары колёс (Pioneer_p3dx_leftWheel и Pioneer_p3dx_rightWheel), 16 сенсоров по бокам (Pioneer_p3dx_ultrasonicSensor1-16) и 11 коннекторов (Pioneer_p3dx_connection1-11).



Для начала давайте отключим скрипт, двигающий робота вперёд. Для этого нажмём на боковой панели кнопку Скрипты (Scripts).



Появится новое окно, в котором перечислены все имеющиеся на сцене скрипты.



Теперь выделите скрипт робота Non-threaded child script (Pioneer_p3dx) и поставьте галочку на пункте Disabled.



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



Теперь давайте немного разберёмся в том, как наш скрипт будет взаимодействовать со сценой при помощи Remote API.

V-REP предоставляет средства контроля симуляцией из внешнего приложения или внешнего устройства (например с настоящего робота, удалённого компьютера). API содержит сотни функций, которые могут быть вызваны через коммуникационные сокеты, с минимальной задержкой и нагрузкой на сеть. Всё это происходит в скрытом от пользователя виде. По средствам удалённого API можно взаимодействовать с V-REP в синхронном и асинхронных режимах (по умолчанию действует асинхронный режим), и даже удалённо управлять симулятором (удалённо загружать сцену, начинать и останавливать работу симуляции).

Примечание: Синхронный режим подразумевает, что симулятор будет ждать подтверждающего сигнала от клиента для выполнения следующего шага на время t + dt.

Для начала работы с Remote API нужно активировать его на стороне сервера, тоесть в самой среде V-REP. Для этого нужно активировать прослушку порта в любом активном потоково зависимом скрипте (например дописав команду в имеющийся Lua-скрипт или добавив какой-нибудь примитив, тот же куб и прикрепив скрипт к нему).

Давайте добавим куб на сцену как описано выше, оставим размеры по умолчанию (0.100 x 0.100 x 0.100). Выделите его на сцене, нажмите правую кнопку мыши и в контекстном меню выберите Add | Associated child script | Threaded.



После чего рядом с именем нашего куба появится иконка зависимого скрипта и его настроек в иерархии сцены. В панеле Скрипты (Scripts) также появится соответствующий пункт.





По нажатию на иконку скрипта в текстовом редакторе выведется стандартный каркас потоковых скриптов, в него же вам следует добавить строку открытия и активации порта на языке Lua.

simExtRemoteApiStart(19999)


Добавьте ее сразу после команды simSetThreadSwitchTiming(2), в результате получится следующее.



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

Для этого вернитесь в папку нашего проекта и обратите внимание на скрипт simpleTest.py. Давайте изучим его содержимое:

import vrep

print ('Program started')
vrep.simxFinish(-1) # just in case, close all opened connections
clientID = vrep.simxStart('127.0.0.1',19999,True,True,5000,5)
if clientID != -1:
    print ('Connected to remote API server')
    res,objs=vrep.simxGetObjects(clientID,vrep.sim_handle_all,vrep.simx_opmode_oneshot_wait)
    if res == vrep.simx_return_ok:
            print ('Number of objects in the scene: ', len(objs))
    else:
            print ('Remote API function call returned with error code: ', res)
    vrep.simxFinish(clientID)
else:
    print ('Failed connecting to remote API server')
print ('Program ended')

Попробуйте запустить его. Если сцена будет не запущенна, то вы получите соответсвующее уведомление в консоли, иначе скрипт подсчитает количество объектов на сцене.



Разберемся в содержимом данного скрипта. Если вы владеете инструментом IPython, то можете последовательно строка за строкой вводить команды и изучать, что возвращают функции V-REP.

Для начала импортируем модуль V-REP. Не забывайте, что он должен быть в текущей дириктории скрипта(для этого мы и копировали те файлы из папки programming), иначе Python не обнаружит его.

import vrep

Далее остановим другие соединения со сценой чтобы они не мешали логике нашего скрипта, если они конечно существуют. Для это есть функция simxFinish c аргументом -1.

vrep.simxFinish(-1)

Далее необходимо соединиться с удалённым сервером на том порту, что мы открыли в скрипте куба. Так как V-REP запущен у нас локально, то адрес 127.0.0.1. Согласно документации по Remote Api для Python (ссылка), аргументы данной функции обозначают следующее:

clientID = vrep.simxStart('127.0.0.1', 19999, True, True, 5000, 5)

  • connectionAddress: IP адрес, где сервер находится (тоесть адрес сервера с V-REP).
  • connectionPort: Порт, с которым происходит соединение.
  • waitUntilConnected: Если True, тогда функция блокируется на время соединения или пока не закончится время тайм-аута.
  • doNotReconnectOnceDisconnected: Если True, тогда коммуникационный поток не будет пытаться переподсоединиться в случае потери соединения.
  • timeOutInMs: Тайм-аут соединения в милисекундах (для первого соединения).
  • commThreadCycleInMs: Указывает на то, как часто должен происходить обмен пакетами данных. Уменьшение этого числа повышает чувствительность, а в роли значения по умолчанию рекомендуется 5.


В качестве возвращаемого значения clientID: идентификатор клиентского ID, или -1, если соедиение с сервером не возможно (в том числе по окончанию времени тайм-аута).

Вызов simxStart всегда должен быть в паре с вызовом simxFinish, за исключением случая, когда соедиение не было выполнено (тоесть clientID = -1). Чему соответсвует следующая строка кода:

vrep.simxFinish(clientID)

После попытки установления соединения выполняется проверка на успешность, о чем сообщит соответсвующее сообщение.

if clientID != -1:
    print ('Connected to remote API server')

    ...

else:
    print ('Failed connecting to remote API server')

Дальше скрипт запрашивает все объекты на сцене через функцию vrep.simxGetObjects.

Согласно документации, которую вы можете изучить на официальном сайте (ссылка), функция получает хэндлы объектов определенного типа или, как в нашем случае, всех типов (vrep.sim_handle_all); последний аргумент означает, что после отправки команды функция будет ждать ответа от сервера и вернёт его, если не произойдет ошибки или будет превышенно время тайм-аута (vrep.simx_opmode_oneshot_wait). Остальные режимы можно посмотреть здесь.

res, objs = vrep.simxGetObjects(clientID, vrep.sim_handle_all, vrep.simx_opmode_oneshot_wait)

Функция возвращает 2 значения errorCode: код ошибки и objectHandles: массив хэндлов объектов.

Далее следует проверка кода ошибки и в случае успеха — подсчет количества объектов на сцене:

    if res == vrep.simx_return_ok:
            print ('Number of objects in the scene: ', len(objs))
    else:
            print ('Remote API function call returned with error code: ', res)

При этом стоит заметить, что константа simx_return_ok соответсвует нулю (0).

Отлично! После того как мы разобрались со значением функций, давайте, наконец, оживим нашу сцену. Для этого нам потребуется выполнить следующие действия в нашем собственном скрипте:

  • Получаем clientID и закрываем остальные соединения, если таковые имеются.
  • Проверяем получилось ли соединиться, если нет, то выводим сообщение и прекращаем работу.
  • Поискав в документации, обнаруживаем функцию vrep.simxGetObjectHandle, с помощью которой можно получить хэндл нужного нам объекта (в нашем случае левого и правого колеса).

Задаем ускорение (vrep.simxSetJointTargetVelocity) в случае успеха, что заставит нашего робота двигаться с нужным нам ускорением.

В результате у вас выйдет подобный скрипт script1.py:

import vrep
import sys

vrep.simxFinish(-1)

clientID = vrep.simxStart('127.0.0.1', 19999, True, True, 5000, 5)

if clientID!= -1:
    print("Connected to remote server")
else:
    print('Connection not successful')
    sys.exit('Could not connect')

errorCode,left_motor_handle=vrep.simxGetObjectHandle(clientID,'Pioneer_p3dx_leftMotor',vrep.simx_opmode_oneshot_wait)

errorCode,right_motor_handle=vrep.simxGetObjectHandle(clientID,'Pioneer_p3dx_rightMotor',vrep.simx_opmode_oneshot_wait)

if errorCode == -1:
    print('Can not find left or right motor')
    sys.exit()

errorCode=vrep.simxSetJointTargetVelocity(clientID,left_motor_handle,0.2, vrep.simx_opmode_oneshot_wait)
errorCode=vrep.simxSetJointTargetVelocity(clientID,right_motor_handle,0.2, vrep.simx_opmode_oneshot_wait)

Для функции simxGetObjectHandle помимо clientID указывается имя объекта, которое можно посмотреть в Иерархии сцены.



errorCode, left_motor_handle = vrep.simxGetObjectHandle(clientID, 'Pioneer_p3dx_leftMotor', vrep.simx_opmode_oneshot_wait)

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

Как видите, взаимодействовать со средой V-REP при помощи Python совсем не сложно, а благодаря большому функционалу можно создавать действительно сложные сценарии взаимодействия целых групп роботов и многое многое другое. Для вдохновления можете начать с изучения их демо-примеров.
Проголосовать:
+7
Сохранить: