0. 简介

对于ROS而言,其最常用的就是Topic话题以及Service两个了。之前我们在了解Unity Robotics Hub时候就了解到基本的Unity和ROS的通讯,下面我们来详细介绍一下Unity与ROS的话题与服务。

ROS和Unity之间的通信是通过Unity的“ROS-TCP-Connector”软件包和ROS的“ROS-TCP-Endpoint”软件包进行通信的。

1. Unity与ROS链接

ROS方面的准备步骤如下,首先添加端口号“10000”“5005”,启动Docker镜像。

Unity和ROS之间的通信需要端口号“10000”“5005”。为了在Unity中导入消息文件,也进行文件夹的安装。

docker run -p 6080:80 -p 10000:10000 -p 5005:5005 --shm-size=1024m tiryoh/ros-desktop-vnc:melodic

安装“ROS-TCP-Endpoint”软件包,用于ROS程序与Unity通信

cd ~/catkin_ws/src
git clone https://github.com/Unity-Technologies/ROS-TCP-Endpoint
cd ..
catkin build
source ~/catkin_ws/devel/setup.bash

然后就是Unity端准备步骤如下,首先就是安装ROS-TCP-Connector。这需要确保Unity的版本在2020.2以上。然后在在Unity菜单“Window→Package Manager”中打开“Package Manager”,“+→Add Package from git URL….”中输入以下URL,按下“Add”按钮,然后我们就会看到ROS-TCP-Connector插件安装成功

https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector

在这里插入图片描述
然后在Unity中完成对ROS的设置,首先选择Unity菜单“Robotics→ROS Settings”
在这里插入图片描述
确认以下的设定是否正确

・Connect on Startup : True
・Protocol : ROS1
・ROS IP Address : 127.0.0.1
・ROS Port : 10000
・Show HUD : True
・KeepAlive time (secs):在指定秒数以上没有发送其他消息的情况下,频繁测试连接。这个时间越长,ROSConnection认识到Topic停止响应所花费的时间就越长。
・Network timeout (secs):消息发送超过指定秒数时,视为连接失败。这个时间越长,ROSConnection认识到Topic停止了响应所花费的时间就越长。
・Sleep time (secs):在确认新消息之前,睡眠的秒数。如果减少这个时间,响应会变快,但是会消耗更多的CPU。

2. 自定义msg

将消息导入Unity的步骤如下所示

  1. Unity的菜单“Robotics→Generate ROS Messages…”选择。

  2. 在“ROS message path”中选择“catkin_ws/src”。

然后就可以看到path下的msg都会显示在Unity下面
在这里插入图片描述

  1. 然后点击“MyString.msg”中的“Build msg”。这样“MyString.msg”将被转换成c#脚本“MyStringMsg”,并在Project窗口中输出“RosMessages”。
    在这里插入图片描述

3. Topic话题

这一小节我们主要来说Topic的发布和订阅,首先我们来看一下发布者的Unity编程。

  1. 在Hierarchy窗口的“+→Create Empty”中创建空GameObject,命名为“Publisher”。

  2. 在“Publisher”中追加新脚本“ChatterPublisher”,编辑如下

using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using MyStringMsg = RosMessageTypes.Hello.MyStringMsg;

public class ChatterPublisher : MonoBehaviour
{
    private ROSConnection ros;

    // 初始化时被调用
    void Start()
    {
        // 向ROS连接注册Topic话题
        ros = ROSConnection.instance;
        ros.RegisterPublisher<MyStringMsg>("chatter");
    }

    // 每帧更新
    void FixedUpdate()
    {
        // 发送msg信息
        MyStringMsg msg = new MyStringMsg("Hello Unity!");
        ros.Send("chatter", msg);
    }
}
  1. 而接收者和发布者类似,都在Hierarchy窗口的“+→Create Empty”中创建空GameObject,命名为“Subscriber”。

  2. 在“Subscriber”中添加新的脚本“ChatterSubscriber”,编辑如下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using MyStringMsg = RosMessageTypes.Hello.MyStringMsg;

public class ChatterSubscriber : MonoBehaviour{

    void Start(){
        // 向ROS连接注册Subscribe
        ROSConnection.instance.Subscribe<MyStringMsg>("chatter", Callback);
    }

    void Callback(MyStringMsg msg){
        Debug.Log(msg.data);
    }
}

同时我们可以在ROS当中订阅这些信息,运行

roscore
rosparam set ROS_IP 127.0.0.1
rosparam set ROS_TCP_PORT 10000
rosrun ros_tcp_endpoint default_server_endpoint.py
# roslauch ros_tcp_endpoint endpoint.launch tcp_ip:=127.0.0.1 tcp_port:=10000 # 将127.0.0.1

然后写一个listener.py的订阅器
在这里插入图片描述

4. Service话题

首先和上面第二章类似,使用同样的方法可以完成srv文件的导入
在这里插入图片描述

  1. 服务端的实现。Hierarchy窗口的“+→Create”Empty”创建空GameObject,命名为“AddTwoIntsServer”,添加新的脚本“AddTwoIntsServer”
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using Unity.Robotics.ROSTCPConnector.ROSGeometry;
using AddTwoIntsRequest = RosMessageTypes.Hello.AddTwoIntsRequest;
using AddTwoIntsResponse = RosMessageTypes.Hello.AddTwoIntsResponse;

public class AddTwoIntsServer : MonoBehaviour
{
    void Start()
    {
        // 向ROS连接注册Service服务
        ROSConnection.GetOrCreateInstance().ImplementService<
            AddTwoIntsRequest, AddTwoIntsResponse>("add_two_ints", AddTwoIntsCallback);
    }

    private AddTwoIntsResponse AddTwoIntsCallback(AddTwoIntsRequest request)
    {
        AddTwoIntsResponse response = new AddTwoIntsResponse();
        response.sum = request.a + request.b;
        return response;
    }
}
  1. 客户端的实现。Hierarchy窗口的“+→Create”Empty”创建空GameObject,命名为“AddTwoIntsClient”,添加新的脚本“AddTwoIntsClient”,编辑如下。
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using AddTwoIntsRequest = RosMessageTypes.Hello.AddTwoIntsRequest;
using AddTwoIntsResponse = RosMessageTypes.Hello.AddTwoIntsResponse;

public class AddTwoIntsClient : MonoBehaviour
{
    ROSConnection ros;

    void Start()
    {
        // 向ROS连接注册Service服务
        ros = ROSConnection.GetOrCreateInstance();
        ros.RegisterRosService<AddTwoIntsRequest, AddTwoIntsResponse>("add_two_ints");

        // 请求生成
        AddTwoIntsRequest request = new AddTwoIntsRequest(1, 2);

        // 请求发送
        ros.SendServiceMessage<AddTwoIntsResponse>("add_two_ints", request, AddTwoIntsCallback);
    }

    void AddTwoIntsCallback(AddTwoIntsResponse response)
    {
        print("1 + 2 = " + response.sum);
    }
}