CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

Turtle - killer turtles - игра в ROS

Начало весны, пора приниматься за недоделанные проекты.
Пока жду детали и вспоминаю ROS.
В качестве разминки (надеюсь после разминки будут более интересные проекты) — небольшая игра в ROS с использованием пакета turtlesim.



ROS — (Robot Operating System) Операционная система для роботов — это фреймворк для программирования роботов, предоставляющий функционал для распределённой работы. Хорошие мануалы (с которых я начинал изучение ROS) на русском языке на этом сайте — здесь
Последняя (восьмая) версия ROS — indigo.
Сначала установил ее на компьютер с операционной системой Ubuntu 14.04. (Инструкция по установке и настройке)
Пакет Turtlesim используют в примерах по изучению ROS. Запуск пакета
rosrun turtlesim turtlesim_node

Появляется окно, в котором расположена черепашка turtle, управлять которой можно отправкой сообщений в темы или сервисы. Есть также возможность управления движением черепашки с помощью клавиатуры.
На самом деле возможности пакета шире, можно создавать любое количество экземпляров черепашки, управлять их перемещением, устанавливать цвет и размер следа черепашки, цвет поля, отслеживать текущие значения координат и текущих скоростей черепашки.
Посмотреть описание пакета turtlesim можно здесь
Итак, игра на ROS c использованием пакета Turtlesim. Движением черепашки будем управлять с помощью геймпада Defender Game Racer X7.

Defender Game Racer X7 имеет 12 кнопок (включая D-Pad и 2 аналоговых джойстика), а также кнопки Turbo, Clear и Home. Устройство поддерживает вибрационную обратную связь, работающую при помощи 2-х вибромоторов. Подключение к компьютеру производится через интерфейс USB. Джойстик может работать в двух режимах, один из которых HID-устройство, другой – контроллер XBOX360. Переключение производится с помощью кнопки Mode.
Проверяем, опознается ли данный геймпад системой. Набираем в терминале команду
ls /dev/input

и смотрим результат выполнения команды

Джойстик устройства называются по jsX, у меня было js0. Удостоверимся, что джойстик работает. Выполним в терминале команду
sudo jstest /dev/input/js0

И смотрим изменение показаний кнопок и джойстиков

4.1. ROS пакет joy.
ROS пакет joy – драйвер джойстика уже установлен в системе. По умолчанию пакет joy использует устройство /dev/input/js0. Если ваш джойстик имеет другое название (например /dev/input/js1), необходимо перед запуском пакета установить параметр joy_node/dev на сервере параметров:
rosparam set joy_node/dev "/dev/input/js1"

Для запуска
rosrun joy joy_node

При запуске пакет выдает сообщение о подключении джойстика

Пакет создает узел ros node_joy, который публикует в тему joy сообщения типа sensor_msgs/Joy

Посмотреть выдачу сообщений узлом joy_node в тему joy можно по команде
rostopic echo joy
И смотрим сообщения в тему joy при нажатии кнопок и передвижении джойстиков нашего геймпада

Наша задача создать узел, который будет слушателем (subscriber) сообщений из темы joy. Этот узел будет обрабатывать эти сообщения и посылать сообщения в темы и сервисы пакета turtlesim для управления черепахами.

СОЗДАНИЕ ИГРЫ

Суть игры следующая – на поле через некоторое время в случайных позициях появляются черепахи. Задача игрока – управляя с помощью джойстика своей черепахой turtle1 наезжать на этих черепах (при наезде черепаха исчезает).

Создаем в рабочем пространстве catkin новый пакет game_turtlesim.
cd ~/catkin_ws/src
catkin_create_pkg game_turtlesim std_msgs rospy joy turtlesim

При этом сразу указываем зависимости пакета. После создания пакета В директории ~/catkin_ws/src появится новая директория с файлами нового, только что созданного пакета game_turtlesim.
Теперь необходимо отредактировать файлы package.xml и CmakeLists.txt.
В файле package.xml мы заполняем номер версии, данные об авторе, сведения о лицензии. Зависимости пакета указаны в блоках <buildtool_depend> и <run_depend>. В блоке <buildtool_depend> указаны зависимости при сборке пакета, а в блоках <run_depend> – зависимости при выполнении пакета.
В данном проекте мы не собираемся использовать сообщения пользовательского типа, поэтому других изменений в файле package.xml и CmakeLists.txt мы делать не будем.
Необходимо реализовать
— управление с помощью джойстика движением черепахи turtle1;
— определение текущего местонахождения нашей движущейся черепахи;
— создание на поле черепах через определенное время;
— проверку столкновения нашей движущейся черепахи с черепахами на поле (в случае наезда – удаление черепахи).

Управление с помощью джойстика движением черепахи turtle1

Скрипт на языке python, управляющий движением черепахи turtle1 с помощью джойстиков геймпада Defender Game Racer X7. Узел должен являться слушателем (subscriber) темы joy и преобразовывать получаемые данные и формировать запросы в сервис /turtle1/teleport_relative для управления движением черепахи turtle1. Т.к. узел joy_node при перемещениях джойстиков публикует сообщения в тему joy очень часто, сервис /turtle1/teleport_relative не будет успевать обрабатывать эти сообщения и они будут ставиться в очередь, что приведет к сильному замедлению реакции черепахи turtle1 на перемещения джойстиков геймпада. Поэтому я поступил следующим образом. Subscriber будет только обновлять последние значения показаний джойстиков и сохранять их в параметре example_1/joy_tek на сервере параметров, а другой скрипт будет раз в 0.1 сек получать значения параметра example_1/joy_tek и отправлять запросы в сервис /turtle1/teleport_relative. Это приведет к потере реакции на сообщения, публикуемые в тему joy, но задержки не будет.
Скрипт turtlesim_joy.py
Создаем файл
roscd game_turtlesim 
mkdir nodes
cd nodes
touch turtlesim_joy.py
chmod +x turtlesim_joy.py

И сам скрипт
#!/usr/bin/env python
#-*-coding:utf-8 -*-
 
import roslib; roslib.load_manifest('game_turtlesim')
import rospy
import time
 
from sensor_msgs.msg import Joy
import std_srvs.srv 
from turtlesim.srv import SetPen
from turtlesim.srv import TeleportAbsolute
 
 
def controller(data):
    # запись данных с джойстиков
    rospy.loginfo(str(data.axes[0])+" "+str(data.axes[3]))
    joy_tek=rospy.get_param("game_turtlesim/joy_tek")
    joy_tek[0]=data.axes[0]
    joy_tek[1]=data.axes[3]
    rospy.set_param("game_turtlesim/joy_tek",joy_tek)
def listener():
     rospy.init_node('sub_turtle1_joy')
     # установка параметров
     rospy.set_param("game_turtlesim/start",1)
     rospy.set_param("game_turtlesim/joy_tek",[0.0, 0.0]) 
     # установить цвет фона
     rospy.set_param("background_r",255)
     rospy.set_param("background_g",255)
     rospy.set_param("background_b",0)
     serv1=rospy.ServiceProxy('/clear',std_srvs.srv.Empty)
     res1=serv1();
     # установить цвет карандаша для turtle1
     serv1=rospy.ServiceProxy('/turtle1/set_pen',SetPen)
     res1=serv1(255,255,0,10,0);
     # черепаху в начальную позицию
     serv1=rospy.ServiceProxy('turtle1/teleport_absolute',TeleportAbsolute)
     res1=serv1(0.0,0.0,0.89);
     # пауза - отдышаться перед игрой
     rospy.sleep(1.0)
    
     sub = rospy.Subscriber("joy",Joy,controller)
     rospy.spin()
  
if __name__ == '__main__':
   listener()


Отклонения влево/вправо левого джойстика (поворот влево/вправо черепахи) и отклонения вперед/назад правого джойстика (движение черепахи вперед/назад). Одним джойстиком осуществлять управление неудобно.

Движение черепахи реализуется в основном скрипте turtle1_go.py
Вот код, реализующий движение turtle1
if rospy.get_param("game_turtlesim/start")==1:
          joy_tek=rospy.get_param("game_turtlesim/joy_tek")
          speed=joy_tek[1]/K_SPEED
          k=1
          if joy_tek[1]<0:
            k=-1
          angle=math.asin(joy_tek[0]*k)/K_ANGLE
          res1=serv1(speed,angle);
       rospy.sleep(0.1)


Определение текущего местонахождения нашей движущейся черепахи

Узел turtlesim_node публикует в тему turtleX/pose сообщения типа turtlesim/Pose о текущей позиции и скоростях передвижения черепахи. Дополнительный скрипт turtle1_pose.py, создающий узел sub_turtle1_pose, который будет являться слушателем (subscriber) сообщений из темы turtle1/pose. Значения x и y мы будем сохранять в параметре game_turtlesim/turtle1_pose на сервере параметров. Значения этого параметра мы будет использовать в основном скрипте turtle1_go.py. Содержимое скрипта turtle1_pose.py
#!/usr/bin/env python
#-*-coding:utf-8 -*-
 
import roslib; roslib.load_manifest('game_turtlesim')
import rospy
import time
from turtlesim.msg import Pose
 
def controller(data):    
    # запись данных положения turtle1
    rospy.set_param("game_turtlesim/turtle1_pose",[data.x,data.y])
    rospy.loginfo("x="+str(data.x)+" y="+str(data.y))

def listener():
     rospy.init_node('sub_turtle1_pose')
     # начальная установка параметров
     rospy.set_param("game_turtlesim/turtle1_pose",[0.0, 0.0]) 
     # объявление subcriber
     sub = rospy.Subscriber("turtle1/pose",Pose,controller)
     rospy.spin()
  
if __name__ == '__main__':
   listener()


Cоздание на поле черепах через определенное время

Код создания на поле черепах через определенное время. Добавление черепах на поле в происходит при отправке запроса к сервису spawn. Формат сообщения сервису spawn – turtlesim/Spawn:
float32 x
float32 y
float32 theta
string name # Optional. A unique name will be created and returned if this is empty
— string name
Т.е. нам необходимо отправить значения координат на поле, угол поворота (в радианах) и имя. Список черепах (1 – есть, 0 – нет) и их координаты на поле, а также текущее значение количества черепах будем сохранять в параметрах game_turtlesim/list_turtles, game_turtlesim/coord_turtles, game_turtlesim/count_turtles на сервере параметров rosparam. Параметр game_turtlesim/time считает время выполнения скрипта, чтобы мы могли отслеживать задержку перед появлением следующей черепахи. Код данного фрагмента
# создание черепах turtle00-turtle010
count_turtles=rospy.get_param("game_turtlesim/count_turtles")
count=rospy.get_param("game_turtlesim/count")
if rospy.get_param("game_turtlesim/start")==1 and count_turtles<10 and
           time.time()-rospy.get_param("game_turtlesim/time")>(T_SPEED-max(2,count*0.03)):
   count_turtles=count_turtles+1
   list_turtles=rospy.get_param("game_turtlesim/list_turtles")
   coord_turtles=rospy.get_param("game_turtlesim/coord_turtles")
   ind=list_turtles.index(0,0,10)
   prv1=False
   while prv1==False:
     x=random.randrange(5,110,5)
     y=random.randrange(5,110,5)
     theta=0.1*random.randint(1,10)
     tek_turtle="turtle0"+str(ind)
     res2=serv2(0.1*x,0.1*y,theta,tek_turtle);
     rospy.loginfo("create turtle="+tek_turtle)
     list_turtles[ind]=1
     coord_turtles[ind]=[x,y]
     rospy.loginfo(list_turtles)
     rospy.set_param("game_turtlesim/list_turtles",list_turtles) 
     rospy.set_param("game_turtlesim/coord_turtles",coord_turtles) 
     rospy.set_param("game_turtlesim/time",time.time())
     rospy.set_param("game_turtlesim/count_turtles",count_turtles)
     prv1=True


Проверка столкновения нашей движущейся черепахи с черепахами на поле

Проверку столкновения нашей движущейся черепахи с черепахами на поле с помощью перебора координат всех черепах на поле (параметр game_turtlesim/coord_turtles) с текущим положением нашей движущейся черепахи turtle1 (параметр game_turtlesim/turtle1_pose) с погрешностью 3 пиксела. В случае наезда удаление черепахи (запрос сервису kill) и внесение значения нулевых координат [0.0, 0.0] для удаленной черепахи в массиве game_turtlesim/coord_turtles и 0 в массиве game_turtlesim/list_turtles. При уничтожении черепахи инкрементируем счетчик игры (параметр game_turtlesim/count на сервере параметров rosparam). Код данного фрагмента

# проверка столкновения turtle1 с turtle00-turtle010
count=rospy.get_param("game_turtlesim/count")
list_turtles=rospy.get_param("game_turtlesim/list_turtles")
coord_turtles=rospy.get_param("game_turtlesim/coord_turtles")
xy=rospy.get_param("game_turtlesim/turtle1_pose")
count_turtles=rospy.get_param("game_turtlesim/count_turtles")
x1=int(xy[0]*10)
y1=int(xy[1]*10)
i=0
for xy in coord_turtles:
   if abs(xy[0]-x1)<4 and abs(xy[1]-(110-y1))<4 and list_turtles[i]==1:
      turtle_del="turtle0"+str(i)
      rospy.loginfo(str(xy[0])+" "+str(xy[1])+" "+str(x1)+" "+str(y1)+" "+turtle_del)
      res3=serv3(turtle_del);
      list_turtles[i]=0
      coord_turtles[i]=[0,0]
      count_turtles=count_turtles-1
      rospy.set_param("game_turtlesim/count",count+1) 
      rospy.set_param("game_turtlesim/count_turtles",count_turtles) 
      rospy.set_param("game_turtlesim/list_turtles",list_turtles) 
      rospy.set_param("game_turtlesim/coord_turtles",coord_turtles) 
   i=i+1       


И запуск

Командный файл game_turtlesim.launch
<launch>
  <!-- для джойстика  -->
  <param name="joy_node" value="/dev/input/js0"></param>
  <node name="joy_node" pkg="joy" type="joy_node" />
  <!-- запуск turtlesim  -->
  <node name="turtlesim_node" pkg="turtlesim" type="turtlesim_node" />
  <!-- запуск turtle1_pose  -->
  <node name="sub_turtle1_pose" pkg="game_turtlesim" type="turtle1_pose.py" />
  <!-- запуск turtlesim_joy  -->
  <node name="sub_turtle1_joy" pkg="game_turtlesim" type="turtlesim_joy.py" />
  <!-- запуск turtle1_go  -->
  <node name="turtle1_go" pkg="game_turtlesim" type="turtle1_go.py" />
</launch>


В первом терминале
roscore

Во втором терминале
roslaunch game_turtlesim game_turtlesim.launch



Проект данного примера можно скачать с github (https://github.com/victoruni/game_turtlesim.git)

Комментарии (0)

RSS свернуть / развернуть

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