浏览代码

Updating tutorials for ROS2 (#247)

/merge-resolve-conflicts
peifeng-unity 3 年前
当前提交
1347d063
共有 72 个文件被更改,包括 2120 次插入473 次删除
  1. 3
      tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.cs
  2. 6
      tutorials/pick_and_place/Scripts/SourceDestinationPublisher.cs
  3. 16
      tutorials/pick_and_place/Scripts/TrajectoryPlanner.cs
  4. 4
      tutorials/pick_and_place/docker/set-up-workspace
  5. 17
      tutorials/ros_unity_integration/README.md
  6. 13
      tutorials/ros_unity_integration/network.md
  7. 85
      tutorials/ros_unity_integration/publisher.md
  8. 152
      tutorials/ros_unity_integration/setup.md
  9. 41
      tutorials/ros_unity_integration/subscriber.md
  10. 5
      tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs
  11. 2
      tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs
  12. 8
      tutorials/ros_unity_integration/unity_scripts/RosUnityServiceExample.cs
  13. 11
      tutorials/ros_unity_integration/unity_scripts/RosServiceCallExample.cs
  14. 83
      tutorials/ros_unity_integration/unity_service.md
  15. 2
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/position_service.py
  16. 158
      tutorials/ros_unity_integration/images/create_cube.png
  17. 40
      tutorials/ros_unity_integration/images/docker_cli.png
  18. 399
      tutorials/ros_unity_integration/images/generate_messages_3.png
  19. 36
      tutorials/ros_unity_integration/images/move_tool.png
  20. 121
      tutorials/ros_unity_integration/images/ros1_icon.png
  21. 129
      tutorials/ros_unity_integration/images/ros2_icon.png
  22. 126
      tutorials/ros_unity_integration/images/ros2_protocol.png
  23. 86
      tutorials/ros_unity_integration/images/settings_ros_ip.png
  24. 151
      tutorials/ros_unity_integration/images/unity-tab-square-white.png
  25. 103
      tutorials/ros_unity_integration/service_call.md
  26. 22
      tutorials/ros_unity_integration/ros2_docker/Dockerfile
  27. 5
      tutorials/ros_unity_integration/ros2_docker/source_ros.sh
  28. 25
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/package.xml
  29. 0
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/resource/unity_robotics_demo
  30. 4
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.cfg
  31. 29
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.py
  32. 23
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_copyright.py
  33. 25
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_flake8.py
  34. 23
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_pep257.py
  35. 0
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/__init__.py
  36. 50
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/color_publisher.py
  37. 34
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/position_service.py
  38. 34
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/CMakeLists.txt
  39. 25
      tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/package.xml
  40. 24
      tutorials/ros_unity_integration/ros_docker/Dockerfile
  41. 6
      tutorials/ros_unity_integration/ros_docker/set-up-workspace
  42. 34
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/CMakeLists.txt
  43. 34
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/package.xml
  44. 48
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/color_publisher.py
  45. 40
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/CMakeLists.txt
  46. 7
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/PosRot.msg
  47. 4
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/UnityColor.msg
  48. 28
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/package.xml
  49. 3
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/ObjectPoseService.srv
  50. 3
      tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/PositionService.srv
  51. 154
      tutorials/ros_unity_integration/server_endpoint.md
  52. 112
      tutorials/ros_unity_integration/service.md
  53. 0
      /tutorials/ros_unity_integration/unity_scripts/RosServiceCallExample.cs
  54. 0
      /tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/launch
  55. 0
      /tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/msg
  56. 0
      /tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/position_service.py
  57. 0
      /tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/srv

3
tutorials/pick_and_place/PickAndPlaceProject/Assets/DemoScripts/Demo.cs


string rosConnectName = "ROSConnect";
string publisherName = "Publisher";
int hostPort = 10000;
int unityPort = 5005;
int awaitDataMaxRetries = 10;
int awaitDataSleepSeconds = 1;
string trajectoryPlannerType = "TrajectoryPlanner";
string rosServiceName = "niryo_moveit";

6
tutorials/pick_and_place/Scripts/SourceDestinationPublisher.cs


public void Publish()
{
MNiryoMoveitJoints sourceDestinationMessage = new MNiryoMoveitJoints();
NiryoMoveitJointsMsg sourceDestinationMessage = new NiryoMoveitJointsMsg();
sourceDestinationMessage.joint_00 = jointArticulationBodies[0].xDrive.target;
sourceDestinationMessage.joint_01 = jointArticulationBodies[1].xDrive.target;

sourceDestinationMessage.joint_05 = jointArticulationBodies[5].xDrive.target;
// Pick Pose
sourceDestinationMessage.pick_pose = new MPose
sourceDestinationMessage.pick_pose = new PoseMsg
{
position = target.transform.position.To<FLU>(),
orientation = Quaternion.Euler(90, target.transform.eulerAngles.y, 0).To<FLU>()

sourceDestinationMessage.place_pose = new MPose
sourceDestinationMessage.place_pose = new PoseMsg
{
position = targetPlacement.transform.position.To<FLU>(),
orientation = pickOrientation.To<FLU>()

16
tutorials/pick_and_place/Scripts/TrajectoryPlanner.cs


/// Get the current values of the robot's joint angles.
/// </summary>
/// <returns>NiryoMoveitJoints</returns>
MNiryoMoveitJoints CurrentJointConfig()
NiryoMoveitJointsMsg CurrentJointConfig()
MNiryoMoveitJoints joints = new MNiryoMoveitJoints();
NiryoMoveitJointsMsg joints = new NiryoMoveitJointsMsg();
joints.joint_00 = jointArticulationBodies[0].xDrive.target;
joints.joint_01 = jointArticulationBodies[1].xDrive.target;

/// </summary>
public void PublishJoints()
{
MMoverServiceRequest request = new MMoverServiceRequest();
MoverServiceRequest request = new MoverServiceRequest();
request.pick_pose = new MPose
request.pick_pose = new PoseMsg
{
position = (target.transform.position + pickPoseOffset).To<FLU>(),
// The hardcoded x/z angles assure that the gripper is always positioned above the target cube before grasping.

// Place Pose
request.place_pose = new MPose
request.place_pose = new PoseMsg
ros.SendServiceMessage<MMoverServiceResponse>(rosServiceName, request, TrajectoryResponse);
ros.SendServiceMessage<MoverServiceResponse>(rosServiceName, request, TrajectoryResponse);
void TrajectoryResponse(MMoverServiceResponse response)
void TrajectoryResponse(MoverServiceResponse response)
{
if (response.trajectories.Length > 0)
{

/// </summary>
/// <param name="response"> MoverServiceResponse received from niryo_moveit mover service running in ROS</param>
/// <returns></returns>
private IEnumerator ExecuteTrajectories(MMoverServiceResponse response)
private IEnumerator ExecuteTrajectories(MoverServiceResponse response)
{
if (response.trajectories != null)
{

4
tutorials/pick_and_place/docker/set-up-workspace


#!/bin/bash
source /opt/ros/melodic/setup.bash
echo "ROS_IP: $(hostname -i)" > $ROS_WORKSPACE/src/niryo_moveit/config/params.yaml
echo "ROS_IP: $(hostname -i)" > $ROS_WORKSPACE/src/ros-tcp-endpoint/config/params.yaml
catkin_make
catkin_make

17
tutorials/ros_unity_integration/README.md


## Tutorials
- [ROS–Unity Integration: Initial Setup](setup.md) - ROS-Unity Initial Setup
- [ROS–Unity Integration: Initial Setup](setup.md) - ROS–Unity Initial Setup
- [ROS–Unity Integration: Publisher](publisher.md) - Adding a Publisher to a Unity Scene
- [ROS–Unity Integration: Subscriber](subscriber.md) - Adding a Subscriber to a Unity Scene
- [ROS–Unity Integration: Service](service.md) - Adding a Service call to a Unity Scene
- [ROS–Unity Integration: UnityService](unity_service.md) - Adding a Service that runs in a Unity Scene
- [ROS–Unity Integration: Server Endpoint](server_endpoint.md) - How to write a Server Endpoint
- [ROS–Unity Integration: Publisher](publisher.md) - Publish messages from a Unity Scene
- [ROS–Unity Integration: Subscriber](subscriber.md) - Subscribe to receive messages in a Unity Scene
- [ROS–Unity Integration: Unity Service](unity_service.md) - Implement a service inside a Unity Scene
- [ROS–Unity Integration: Service Call](service_call.md) - Call an external service from a Unity Scene
## Example Unity Scripts

- `unity_scripts/RosSubscriberExample.cs`
- Subscribes to a topic that accepts color messages and uses them to change the color of a GameObject in the Unity scene.
- `unity_scripts/RosServiceExample.cs`
- Returns a destination position for a GameObject to move towards each time the service is called.
- `unity_scripts/RosServiceExample.cs`
- Returns a destination position for a GameObject to move towards each time the service is called.

13
tutorials/ros_unity_integration/network.md


`ROS_IP` : The IP address of the machine, VM, or container running ROS.
`UNITY_IP` : The IP address of the machine running Unity.
> It is possible to set both of these variables on the machines running Unity and ROS. The specifics of where and why each of these settings will be described below.
On the ROS machine these settings are set as a rosparam and will typically be set in a launch file like [this](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/main/tutorials/ros_packages/robotics_demo/launch/robo_demo.launch) or in a [param file](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/main/tutorials/pick_and_place/ROS/src/niryo_moveit/config/params.yaml) loaded by a launch file like [this](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/main/tutorials/pick_and_place/ROS/src/niryo_moveit/launch/part_3.launch#L2). The param file can also be loaded manually by running the `rosparam load params.yaml` command.

- On the ROS side, set `ROS_IP` to `0.0.0.0`.
- On the Unity side, set `ROS_IP` to `127.0.0.1` and the `Override Unity IP Address` to your local machine's IP address.
- On the Unity side, set `ROS_IP` to `127.0.0.1`.
## Explicitly setting `UNITY_IP`
The `UNITY_IP` can be set in two different places.
1. If set on the ROS side as a rosparam, the `server_endpoint` will only use this IP to send messages to Unity.
1. If set on the Unity side as the `Override Unity IP Address`, the `UNITY_IP` on the ROS side will be set to this value during the initial handshake between ROS and Unity once play is pressed in the Editor.
> If the `UNITY_IP` is not set in either of these places, then the IP that makes the first connection to ROS during the initial handshake will be used.
# Troubleshooting

85
tutorials/ros_unity_integration/publisher.md


Create a simple Unity scene which publishes a GameObject's position and rotation to a [ROS topic](http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics#ROS_Topics).
## Setting Up ROS
- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
These instructions cover the setup for both ROS1 and ROS2. Instructions for ROS2 users are marked with this icon: <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/>.
- Follow the [ROS–Unity Initial Setup](setup.md) guide.
## Setting Up
- Open a new terminal window and run the following commands:
```bash
source devel/setup.bash
rosrun robotics_demo server_endpoint.py
```
- Follow the [ROS–Unity Demo Setup](setup.md#ros2-environment) guide.
Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
- Open another new terminal window, navigate to your ROS workspace, and run the following commands:
```bash
source devel/setup.bash
rostopic echo pos_rot
```
## Setting Up Unity Scene
- In the menu bar, find and select `Robotics` -> `Generate ROS Messages...`
- Set the ROS message path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo`.
- Expand the robotics_demo subfolder and click "Build 2 msgs" to generate new C# scripts from the ROS .msg files.
![](images/generate_messages_1.png)
- The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/msg`.
- Create a new directory in `Assets` and name it `Scripts`
- Create a new script in the `Scripts` directory and name it `RosPublisherExample.cs`
- Open `RosPublisherExample.cs` and paste the following code:
- **Note** Script can be found at `tutorials/ros_unity_integration/unity_scripts`
## Create Unity Publisher
- In your Project tab in Unity, create a new C# script and name it `RosPublisherExample`. Paste the following code into the new script file.
- (Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs` in this repo.)
using RosMessageTypes.RoboticsDemo;
using RosMessageTypes.UnityRoboticsDemo;
/// <summary>
///

{
// start the ROS connection
ros = ROSConnection.instance;
ros.RegisterPublisher<PosRotMsg>(topicName);
}
private void Update()

{
cube.transform.rotation = Random.rotation;
MPosRot cubePos = new MPosRot(
PosRotMsg cubePos = new PosRotMsg(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,

}
```
- Add a plane and a cube to the empty Unity scene
- Move the cube a little ways up so it is hovering above the plane
- In the main menu bar, open `Robotics/ROS Settings`.
- Set the ROS IP address and port to match the ROS IP and port variables defined when you set up ROS.
- Add a plane and a cube to your Unity scene. You can create simple geometric shapes in Unity by going to the Hierarchy window, clicking the + button, and navigating to the shape you want to create.
![](images/create_cube.png)
- Move the cube a little ways up so it is hovering above the plane. To do this, select the cube in the hierarchy window, and click on the move tool in the toolbar at the top left of the Unity window.
![](images/move_tool.png)
- Draggable arrows will appear around the cube in the Scene view; to move the cube up, drag the vertical (green) arrow upwards.
- Pressing play in the Editor should publish a message to the terminal running the `rostopic echo pos_rot` command every 0.5 seconds
- Press play in the Editor. You should see the connection lights at the top left corner of the Game window turn blue, and something like `[INFO] [1622242057.562860400] [TCPServer]: Connection from 172.17.0.1` appear in the terminal running your server_endpoint.
## Common Errors
If you see the error `Failed to resolve message name: No module named unity_robotics_demo_msgs.msg` followed by `Topic 'pos_rot' is not registered` in the ROS-TCP-Endpoint log, you may have missed the step about installing the unity_robotics_demo_msgs package, or perhaps you forgot to build and/or source it afterwards. Try following the "Install Unity Robotics Demo" instructions [here](setup.md#install-unity-robotics-demo).
## Start the Echo monitor
- To prove that messages are actually being received by ROS, let's run the rostopic echo command.
a) <img src="images/ros1_icon.png" alt="ros1" width="14" height="14"/> In ROS1, open a new terminal window, navigate to your ROS workspace, and run the following commands:
```bash
source devel/setup.bash
rostopic echo pos_rot
```
b) <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> In ROS2, the commands to run are
```bash
source install/setup.bash
ros2 topic echo pos_rot
```
- If you're using Docker, you can use the command `docker ps` to get a list of all running containers; `docker exec -ti bash <container name> bash` starts a new terminal for the specified container. Alternatively, click the "CLI" button in the Docker UI to open a new terminal ("command line interface").
![](images/docker_cli.png)
- If it's working correctly, you should see the contents of the message Unity is sending appearing every 0.5 seconds.
> Please reference [networking troubleshooting](network.md) doc if any errors are thrown.

152
tutorials/ros_unity_integration/setup.md


# ROS–Unity Initial Setup
# ROS–Unity Demo Setup
The minimum requirements for a ROS–Unity integration.
This document is in two parts - part 1 covers the minimum requirements for a ROS–Unity integration. Part 2 sets up the Unity Robotics Demo package, which you will need if you're following the ROS–Unity Integration tutorials.
## ROS Environment
These instructions cover both ROS1 and ROS2. The symbols <img src="images/ros1_icon.png" alt="ros1" width="14" height="14"/> and <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> indicate instructions for ROS1 and ROS2 users, respectively. If using ROS2, start with [ROS2 Environment](setup.md#-ros2-environment).
1. Download and copy the [TCP Endpoint](https://github.com/Unity-Technologies/ROS-TCP-Endpoint) package to the `src` folder in your Catkin workspace.
## <img src="images/ros1_icon.png" alt="ros1" width="28" height="28"/> ROS Environment
1. Navigate to your Catkin workspace and run `catkin_make && source devel/setup.bash`. Ensure there are no errors.
Follow these steps to use ROS (melodic or noetic):
1. Open a new terminal, navigate to your Catkin workspace, and run:
1.
a) If you don't already have a ROS environment set up, we recommend using Docker. Navigate to `tutorials/ros_unity_integration` in your copy of this repo and run the following commands:
source devel/setup.bash
roscore &
docker build -t melodic -f ros_docker/Dockerfile .
docker run -it --rm -p 10000:10000 melodic /bin/bash
Once ROS Core has started, it will print `started core service [/rosout]` to the terminal window.
This should build a docker image and start it.
1. Note that in the `server_endpoint`, the script fetches parameters for the TCP connection. You will need to know the IP address of your ROS machine as well as the IP address of the machine running Unity.
- The ROS machine IP, i.e. `ROS_IP` should be the same value as the one set as `Host Name` on the RosConnect component in Unity.
1. The ROS parameter values can be set using a YAML file. Create a `params.yaml` file in your package, e.g. `./config/params.yaml`. Open the file for editing.
b) (Alternative) If you're using your own ROS environment, download and copy the [ROS-TCP-Endpoint](https://github.com/Unity-Technologies/ROS-TCP-Endpoint) package into the `src` folder in your Catkin workspace. Then navigate to your Catkin workspace and run `catkin_make`, then `source devel/setup.bash`. Ensure there are no errors.
1. Update the `ROS_IP` below with the appropriate address and copy the contents into the `params.yaml` file.
2. Open a new terminal, navigate to your Catkin workspace, and run:
```yaml
ROS_IP: <your ROS IP>
ROS_TCP_PORT: 10000
```
```bash
source devel/setup.bash
roscore
```
e.g.
Once ROS Core has started, it will print `started core service [/rosout]` to the terminal window.
```yaml
ROS_IP: 127.0.0.1
ROS_TCP_PORT: 10000
3. In your previous terminal, run the following command, replacing the `<your IP address>` with your ROS machine's IP or hostname.
```bash
rosparam set ROS_IP <your IP address>
Ensure that the `ROS_TCP_PORT` is set to 10000.
- If you're running ROS in a Docker container, you can just use `rosparam set ROS_IP 0.0.0.0`
- On Linux you can find out your IP address with the command `hostname -I`
- On MacOS you can find out your IP address with `ipconfig getifaddr en0`
1. Set these newly defined parameters by running `rosparam load`, e.g.:
6. (Optional) By default, the server_endpoint will listen on port 10000, but this is also controlled by a parameter. If you need to change it, you can run the command `rosparam set ROS_TCP_PORT 10000`, replacing 10000 with the desired port number.
```bash
rosparam load PATH/TO/config/params.yaml
```
Alternatively, this YAML can be loaded from a launch file, e.g.:
7. Start the server endpoint with the following command:
```xml
<launch>
<rosparam file="$(find <PACKAGE_NAME>)/config/params.yaml" command="load"/>
</launch>
```
```bash
rosrun ros_tcp_endpoint default_server_endpoint.py
```
Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
> Note, for this tutorial we have illustrated how to do everything manually, but for day-to-day use, we recommend starting the endpoint with a launch file. Replace all the above (including the roscore step) with the following command: `roslaunch ros_tcp_endpoint endpoint.launch`.
> While using this launch file, your ROS_IP and ROS_TCP_PORT parameters are read from the file src/ros_tcp_endpoint/config/params.yaml. You can edit this file to adjust your settings - for example, this command will set the appropriate IP address for your machine:
> `echo "ROS_IP: $(hostname -i)" > src/ros-tcp-endpoint/config/params.yaml`
## Unity Scene
1. Launch Unity and create a new scene.
2. Open Package Manager and click the + button at the top left corner. Select "add package from git URL" and enter "https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector" to install the [ROS TCP Connector](https://github.com/Unity-Technologies/ROS-TCP-Connector) package.
## <img src="images/ros2_icon.png" alt="ros2" width="46" height="28"/> ROS2 Environment
![](images/add_package.png)
Follow these steps if using ROS2:
![](images/add_package_2.png)
1.
a) If you don't already have a ROS2 environment set up, we recommend using Docker. Navigate to `tutorials/ros_unity_integration` in your copy of this repo and run the following commands:
Messages being passed between Unity and ROS need to be serialized exactly as ROS serializes them internally. This is achieved with the RosMessageGeneration utility, which generates C# classes, including serialization and deserialization functions, based on ROS message files. Adding the ROS TCP Connector package should have created a new Unity menu option, “Robotics/Generate ROS Messages”, which we will use to generate these messages later.
```bash
docker build -t foxy -f ros2_docker/Dockerfile .
docker run -it --rm -p 10000:10000 foxy /bin/bash
```
This should build a docker image and start it.
b) Alternatively, if you're not going to use the Docker image, download the [ROS2 branch of the ROS-TCP-Endpoint](https://github.com/Unity-Technologies/ROS-TCP-Endpoint/tree/ROS2) repository and copy it into the `src` folder in your Colcon workspace. Then navigate to your Colcon workspace and run the following commands:
```bash
source install/setup.bash
colcon build
source install/setup.bash
```
Note: yes, you need to run the source command twice. The first sets up the environment for the build to use, the second time adds the newly built packages to the environent.
2. In your Colcon workspace, run the following command, replacing `<your IP address>` with your ROS machine's IP or hostname.
```bash
ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=<your IP address>
```
- If you're running ROS in a Docker container, 0.0.0.0 is a valid incoming address, so you can write `ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=0.0.0.0`
- On Linux you can find out your IP address with the command `hostname -I`
- On MacOS you can find out your IP address with `ipconfig getifaddr en0`
Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
3. (Alternative) If you need the server to listen on a port that's different from the default 10000, here's the command line to also set the ROS_TCP_PORT parameter:
```bash
ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=127.0.0.1 -p ROS_TCP_PORT:=10000
```
## <img src="images/unity-tab-square-white.png" alt="ros2" width="24" height="24"/> Unity Setup
1. Launch Unity and create a new project. The Robotics package works best with a version of Unity no older than 2020.
2. Open Package Manager and click the + button at the top left corner. Select "add package from git URL" and enter "https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector#dev" to install the [ROS-TCP-Connector](https://github.com/Unity-Technologies/ROS-TCP-Connector) package.
![](images/add_package.png)
![](images/add_package_2.png)
3. If you're not using a Docker container, open `Robotics/ROS Settings` from the Unity menu bar, and set the `ROS IP Address` variable to the IP you set earlier. (If you're using Docker, leave it as the default 127.0.0.1.)
![](images/settings_ros_ip.png)
4. <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> Also in the ROS Settings window, ROS2 users should switch the protocol to ROS2 now.
![](images/ros2_protocol.png)
## Install Unity Robotics Demo
The instructions so far have set up the ROS-TCP-Connector package for general use. If you are specifically following one of the [ROS–Unity Integration tutorials](README.md), you'll need to do the following additional steps:
1. Copy the `unity_robotics_demo` and `unity_robotics_demo_msgs` packages into the `src` folder in your Catkin workspace. (Skip this step if you're using one of the Dockerfiles from this repo: they have the demo packages pre-installed.)
- <img src="images/ros1_icon.png" alt="ros1" width="14" height="14"/> If using ROS1, copy them from from `tutorials/ros_unity_integration/ros_packages` in this repo.
- <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> If using ROS2, copy them from `tutorials/ros_unity_integration/ros2_packages` in this repo.
1. Build the new packages.
- <img src="images/ros1_icon.png" alt="ros1" width="14" height="14"/> In ROS1: Run `catkin_make`, and then `source devel/setup.bash` (again) so that ROS can find the newly built messages.
- <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> In ROS2: run `colcon build`, then `source install/setup.bash` (again) so that ROS can find the newly built messages.
2. In the Unity menu bar, go to `Robotics` -> `Generate ROS Messages...`. In the Message Browser window, click the Browse button at the top right to set the ROS message path to `tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs` in this repo.
(Note: The version in the ros2_packages folder is equivalent; ROS2 users can feel free to use it, or not.)
3. In the message browser, expand the unity_robotics_demo_msgs subfolder and click "Build 2 msgs" and "Build 2 srvs" to generate C# scripts from the ROS .msg and .srv files.
![](images/generate_messages_3.png)
The generated files will be saved in the default directories `Assets/RosMessages/UnityRoboticsDemo/msg` and `Assets/RosMessages/UnityRoboticsDemo/srv`. Note, there is no difference between the message scripts generated in ROS1 and ROS2 mode. You don't need to regenerate messages when you switch between them.

41
tutorials/ros_unity_integration/subscriber.md


Create a simple Unity scene which subscribes to a [ROS topic](http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics#ROS_Topics) to change the colour of a GameObject.
## Setting Up ROS
## Setting Up
(Skip to [Setting Up Unity Scene](subscriber.md#setting-up-unity-scene) if you already did the [Publisher](publisher.md) tutorial.)
- Follow the [ROS–Unity Demo Setup](setup.md) guide if you haven't already done so.
- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
## Create Unity Subscriber
- Follow the [ROS–Unity Initial Setup](setup.md) guide.
- Open a new terminal window, navigate to your Catkin workspace, and run the following commands:
```bash
source devel/setup.bash
rosrun robotics_demo server_endpoint.py
```
Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
- In Unity, we need to generate the C# code for the `UnityColor` message. Open `Robotics` -> `Generate ROS Messages...`.
- Set the ROS message path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo/`, expand the robotics_demo subfolder and click `Build 2 msgs`.
![](images/generate_messages_1.png)
- The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/msg`.
## Setting Up Unity Scene
- Create a script and name it `RosSubscriberExample.cs`
- Paste the following code into `RosSubscriberExample.cs`
- **Note** Script can be found at `tutorials/ros_unity_integration/unity_scripts`
- In Unity, create a new C# script and name it `RosSubscriberExample`. Paste the following code into the new script file.
(Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs`.)
using RosColor = RosMessageTypes.RoboticsDemo.MUnityColor;
using RosColor = RosMessageTypes.UnityRoboticsDemo.UnityColorMsg;
public class RosSubscriberExample : MonoBehaviour
{

- Create an empty GameObject and name it `RosSubscriber`
- Attach the `RosSubscriberExample` script to the `RosSubscriber` GameObject and drag the cube GameObject onto the `cube` parameter in the Inspector window.
- From the Unity menu bar, open `Robotics/ROS Settings`, and set the `ROS IP Address` variable to your ROS IP.
- After the scene has entered Play mode, run the following command: `rosrun robotics_demo color_publisher.py` to change the color of the cube GameObject in Unity to a random color
Let's send a color message to change the color of the cube GameObject in Unity to a random color.
a) <img src="images/ros1_icon.png" alt="ros1" width="14" height="14"/> In ROS1, run: `rosrun unity_robotics_demo color_publisher.py`
b) <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> In ROS2, instead run: `ros2 run unity_robotics_demo color_publisher`
Continue to the [ROS–Unity Integration Service](service.md).
Continue to the [ROS–Unity Integration Unity Service](unity_service.md).

5
tutorials/ros_unity_integration/unity_scripts/RosPublisherExample.cs


using RosMessageTypes.RoboticsDemo;
using RosMessageTypes.UnityRoboticsDemo;
/// <summary>
///

{
// start the ROS connection
ros = ROSConnection.instance;
ros.RegisterPublisher<PosRotMsg>(topicName);
}
private void Update()

{
cube.transform.rotation = Random.rotation;
MPosRot cubePos = new MPosRot(
PosRotMsg cubePos = new PosRotMsg(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,

2
tutorials/ros_unity_integration/unity_scripts/RosSubscriberExample.cs


using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using RosColor = RosMessageTypes.RoboticsDemo.MUnityColor;
using RosColor = RosMessageTypes.UnityRoboticsDemo.UnityColorMsg;
public class RosSubscriberExample : MonoBehaviour
{

8
tutorials/ros_unity_integration/unity_scripts/RosUnityServiceExample.cs


using RosMessageTypes.RoboticsDemo;
using RosMessageTypes.UnityRoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using Unity.Robotics.ROSTCPConnector.ROSGeometry;

void Start()
{
// register the service with ROS
ROSConnection.instance.ImplementService<MObjectPoseServiceRequest>(m_ServiceName, GetObjectPose);
ROSConnection.instance.ImplementService<ObjectPoseServiceRequest>(m_ServiceName, GetObjectPose);
}
/// <summary>

/// <returns>service response containing the object pose (or 0 if object not found)</returns>
private MObjectPoseServiceResponse GetObjectPose(MObjectPoseServiceRequest request)
private ObjectPoseServiceResponse GetObjectPose(ObjectPoseServiceRequest request)
MObjectPoseServiceResponse objectPoseResponse = new MObjectPoseServiceResponse();
ObjectPoseServiceResponse objectPoseResponse = new ObjectPoseServiceResponse();
// Find a game object with the requested name
GameObject gameObject = GameObject.Find(request.object_name);
if (gameObject)

11
tutorials/ros_unity_integration/unity_scripts/RosServiceCallExample.cs


using RosMessageTypes.RoboticsDemo;
using RosMessageTypes.UnityRoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;

void Start()
{
ros = ROSConnection.instance;
ros.RegisterRosService<PositionServiceRequest>(serviceName);
destination = cube.transform.position;
}

{
Debug.Log("Destination reached.");
MPosRot cubePos = new MPosRot(
PosRotMsg cubePos = new PosRotMsg(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,

cube.transform.rotation.w
);
MPositionServiceRequest positionServiceRequest = new MPositionServiceRequest(cubePos);
PositionServiceRequest positionServiceRequest = new PositionServiceRequest(cubePos);
ros.SendServiceMessage<MPositionServiceResponse>(serviceName, positionServiceRequest, Callback_Destination);
ros.SendServiceMessage<PositionServiceResponse>(serviceName, positionServiceRequest, Callback_Destination);
void Callback_Destination(MPositionServiceResponse response)
void Callback_Destination(PositionServiceResponse response)
{
awaitingResponseUntilTimestamp = -1;
destination = new Vector3(response.output.pos_x, response.output.pos_y, response.output.pos_z);

83
tutorials/ros_unity_integration/unity_service.md


# ROS–Unity Integration: UnityService
Create a simple Unity scene which create a [Service](http://wiki.ros.org/Services) in Unity that takes a request with a GameObject's name and responds with the GameObject's pose (position and orientation) in the ROS coordinate system.
## Setting Up ROS
(Skip to [Setting Up the Unity Scene](unity_service.md#setting-up-the-unity-scene) if you already did the [ROS–Unity Integration Publisher](publisher.md) or [Subscriber](subscriber.md) tutorials.)
- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
- Follow the [ROS–Unity Initial Setup](setup.md) guide.
- Open a new terminal window, navigate to your ROS workspace, and run the following commands:
```bash
source devel/setup.bash
rosrun robotics_demo server_endpoint.py
```
Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
## Setting Up the Unity Scene
- Generate the C# code for `ObjectPoseService`'s messages by going to `Robotics` -> `Generate ROS Messages...`
- Set the input file path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo`, expand the robotics_demo folder and click `Build 2 srvs` (Note that you may skip this step if you have already done it in the previous tutorial).
Create a simple Unity scene which runs a [Service](http://wiki.ros.org/Services) in Unity that takes a request with a GameObject's name and responds with the GameObject's pose (position and orientation) in the ROS coordinate system.
![](images/generate_messages_2.png)
## Setting Up
- The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/srv`.
- Follow the [ROS–Unity Demo Setup](setup.md) guide if you haven't already done so.
## Create Unity Service
- **Note:** This script can be found at `tutorials/ros_unity_integration/unity_scripts`.
- (Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts`).
using RosMessageTypes.RoboticsDemo;
using RosMessageTypes.UnityRoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using Unity.Robotics.ROSTCPConnector.ROSGeometry;

void Start()
{
// register the service with ROS
ROSConnection.instance.ImplementService<MObjectPoseServiceRequest>(m_ServiceName, GetObjectPose);
ROSConnection.instance.ImplementService<ObjectPoseServiceRequest>(m_ServiceName, GetObjectPose);
}
/// <summary>

/// <returns>service response containing the object pose (or 0 if object not found)</returns>
private MObjectPoseServiceResponse GetObjectPose(MObjectPoseServiceRequest request)
private ObjectPoseServiceResponse GetObjectPose(ObjectPoseServiceRequest request)
MObjectPoseServiceResponse objectPoseResponse = new MObjectPoseServiceResponse();
ObjectPoseServiceResponse objectPoseResponse = new ObjectPoseServiceResponse();
// Find a game object with the requested name
GameObject gameObject = GameObject.Find(request.object_name);
if (gameObject)

}
```
- From the main menu bar, open `Robotics/ROS Settings`, and change the `ROS IP Address` variable to the ROS IP.
- Create an empty GameObject and name it `UnityService`.
- Attach the `RosUnityServiceExample` script to the `UnityService` GameObject.
- Pressing play in the Editor should start running as a ROS node, waiting to accept ObjectPose requests. Once a connection to ROS has been established, a message will be printed on the ROS terminal similar to `Connection from 172.17.0.1`.

- On your ROS system, open a new terminal window, navigate to your ROS workspace, and run the following commands:
- To test our new service is working, let's call it using the built-in ROS service command.
```bash
source devel/setup.bash
rosrun robotics_demo object_pose_client.py Cube
```
- This wil print an output similar to the following with the current pose information of the game object (note that the coordinates are converted to the ROS coordinate system in our Unity Service):
a) <img src="images/ros1_icon.png" alt="ros1" width="14" height="14"/> In ROS1, run the following command in your ROS terminal:
Requesting pose for Cube
Pose for Cube:
position:
x: 0.0
y: -1.0
z: 0.20000000298023224
orientation:
x: 0.0
y: -0.0
z: 0.0
w: -1.0
rosservice call /obj_pose_srv Cube
You may replace `Cube` with the name of any other GameObject currently present in the Unity hierarchy.
- Alternatively you may also call the ROS service using `rosservice call`:
In your Unity console you should see the log message `Received request for object: Cube`, and in your terminal it will report the object's position, like this:
rosservice call /obj_pose_srv Cube
```
```bash
object_pose:
position:
x: 0.0

y: -0.0
z: 0.0
w: -1.0
```
```
b) <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> If you're using ROS2, the command is:
```bash
ros2 service call obj_pose_srv unity_robotics_demo_msgs/ObjectPoseService "{object_name: Cube}"
```
And the output will look like this:
```bash
requester: making request: unity_robotics_demo_msgs.srv.ObjectPoseService_Request(object_name='Cube')
response:
unity_robotics_demo_msgs.srv.ObjectPoseService_Response(object_pose=geometry_msgs.msg.Pose(position=geometry_msgs.msg.Point(x=0.0, y=-0.0, z=0.0), orientation=geometry_msgs.msg.Quaternion(x=-0.558996319770813, y=-0.3232670724391937, z=-0.6114855408668518, w=-0.4572822153568268)))
```
Continue to the [ROS–Unity Integration Service Call](service_call.md).

2
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/position_service.py


import random
import rospy
from robotics_demo.srv import PositionService, PositionServiceResponse
from unity_robotics_demo_msgs.srv import PositionService, PositionServiceResponse
def new_position(req):

158
tutorials/ros_unity_integration/images/create_cube.png

之前 之后
宽度: 446  |  高度: 371  |  大小: 40 KiB

40
tutorials/ros_unity_integration/images/docker_cli.png

之前 之后
宽度: 413  |  高度: 176  |  大小: 11 KiB

399
tutorials/ros_unity_integration/images/generate_messages_3.png

之前 之后
宽度: 2019  |  高度: 627  |  大小: 116 KiB

36
tutorials/ros_unity_integration/images/move_tool.png

之前 之后
宽度: 175  |  高度: 90  |  大小: 9.8 KiB

121
tutorials/ros_unity_integration/images/ros1_icon.png

之前 之后
宽度: 79  |  高度: 80  |  大小: 15 KiB

129
tutorials/ros_unity_integration/images/ros2_icon.png

之前 之后
宽度: 128  |  高度: 80  |  大小: 16 KiB

126
tutorials/ros_unity_integration/images/ros2_protocol.png

之前 之后
宽度: 632  |  高度: 337  |  大小: 38 KiB

86
tutorials/ros_unity_integration/images/settings_ros_ip.png

之前 之后
宽度: 631  |  高度: 343  |  大小: 36 KiB

151
tutorials/ros_unity_integration/images/unity-tab-square-white.png

之前 之后
宽度: 512  |  高度: 512  |  大小: 25 KiB

103
tutorials/ros_unity_integration/service_call.md


# ROS–Unity Integration: Service Call
Create a simple Unity scene which calls an external [ROS service](http://wiki.ros.org/Services) with a GameObject's position and rotation to receive a new position to move the GameObject towards.
## Setting Up
- Follow the [ROS–Unity Demo Setup](setup.md) guide if you haven't already done so.
## Start the Position service
- For this tutorial we will need a ros service for Unity to call. In a new terminal window, navigate to your ROS workspace.
a) <img src="images/ros1_icon.png" alt="ros1" width="14" height="14"/> In ROS1, run the following commands:
```bash
source devel/setup.bash
rosrun unity_robotics_demo position_service.py
```
b) <img src="images/ros2_icon.png" alt="ros2" width="23" height="14"/> In ROS2, instead run:
```bash
source install/setup.bash
ros2 run unity_robotics_demo position_service
```
## Create Unity Service Caller
- Create a script and name it `RosServiceCallExample.cs`
- Paste the following code into `RosServiceCallExample.cs`
- (Alternatively, you can drag the script file into Unity from `tutorials/ros_unity_integration/unity_scripts`).
```csharp
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using RosMessageTypes.UnityRoboticsDemo;
public class RosServiceCallExample : MonoBehaviour
{
ROSConnection ros;
public string serviceName = "pos_srv";
public GameObject cube;
// Cube movement conditions
public float delta = 1.0f;
public float speed = 2.0f;
private Vector3 destination;
float awaitingResponseUntilTimestamp = -1;
void Start()
{
ros = ROSConnection.instance;
ros.RegisterRosService<PositionServiceRequest>(serviceName);
destination = cube.transform.position;
}
private void Update()
{
// Move our position a step closer to the target.
float step = speed * Time.deltaTime; // calculate distance to move
cube.transform.position = Vector3.MoveTowards(cube.transform.position, destination, step);
if (Vector3.Distance(cube.transform.position, destination) < delta && Time.time > awaitingResponseUntilTimestamp)
{
Debug.Log("Destination reached.");
PosRotMsg cubePos = new PosRotMsg(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,
cube.transform.rotation.x,
cube.transform.rotation.y,
cube.transform.rotation.z,
cube.transform.rotation.w
);
PositionServiceRequest positionServiceRequest = new PositionServiceRequest(cubePos);
// Send message to ROS and return the response
ros.SendServiceMessage<PositionServiceResponse>(serviceName, positionServiceRequest, Callback_Destination);
awaitingResponseUntilTimestamp = Time.time + 1.0f; // don't send again for 1 second, or until we receive a response
}
}
void Callback_Destination(PositionServiceResponse response)
{
awaitingResponseUntilTimestamp = -1;
destination = new Vector3(response.output.pos_x, response.output.pos_y, response.output.pos_z);
Debug.Log("New Destination: " + destination);
}
}
```
- Create an empty GameObject and name it `RosService`.
- Attach the `RosServiceExample` script to the `RosService` GameObject. Drag the cube GameObject onto its `cube` parameter.
- Pressing play in the Editor should start communication with the `position_service` script, running as a ROS node, causing the cube to move to random positions in the scene.
> Please reference [networking troubleshooting](network.md) doc if any errors are thrown.
![](images/tcp_3.gif)

22
tutorials/ros_unity_integration/ros2_docker/Dockerfile


FROM ros:foxy-ros-base
# Make ROS2 Workspace Dirss
RUN mkdir -p /home/dev_ws/src
# Copy ROS2 packages into workspace
COPY ./ros2_packages/ /home/dev_ws/src
#Check out ROS-TCP-Endpoint, ROS2 version
RUN git clone https://github.com/Unity-Technologies/ROS-TCP-Endpoint /home/dev_ws/src/ros_tcp_endpoint -b ROS2
# Reference script with commands to source workspace
COPY ./ros2_docker/source_ros.sh /home/dev_ws/source_ros.sh
# Change to workspace on sign in
RUN echo "cd home/dev_ws" >> ~/.bashrc
# Build the workspace
RUN cd home/dev_ws && . /opt/ros/foxy/setup.sh && colcon build
# Source the workspace on sign in
RUN echo ". install/local_setup.bash" >> ~/.bashrc

5
tutorials/ros_unity_integration/ros2_docker/source_ros.sh


#!/bin/bash
source /opt/ros/foxy/setup.bash
. install/local_setup.bash
ros2 launch ros2_test test_launcher.py

25
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/package.xml


<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>unity_robotics_demo</name>
<version>0.0.1</version>
<description>Package for use in ROS-Unity Integration tutorials (ROS2 version)</description>
<maintainer email="unity-robotics@unity.com">Unity Robotics</maintainer>
<license>TODO: License declaration</license>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
<export>
<build_type>ament_python</build_type>
</export>
</package>

0
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/resource/unity_robotics_demo

4
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.cfg


[develop]
script-dir=$base/lib/unity_robotics_demo
[install]
install-scripts=$base/lib/unity_robotics_demo

29
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/setup.py


import glob
import os
from setuptools import setup
package_name = 'unity_robotics_demo'
setup(
name=package_name,
version='0.0.1',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='Unity Robotics',
maintainer_email='unity-robotics@unity3d.com',
description='ROS2 Unity Integration Testing',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'color_publisher = unity_robotics_demo.color_publisher:main',
'position_service = unity_robotics_demo.position_service:main',
],
},
)

23
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_copyright.py


# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_copyright.main import main
import pytest
@pytest.mark.copyright
@pytest.mark.linter
def test_copyright():
rc = main(argv=['.', 'test'])
assert rc == 0, 'Found errors'

25
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_flake8.py


# Copyright 2017 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_flake8.main import main_with_errors
import pytest
@pytest.mark.flake8
@pytest.mark.linter
def test_flake8():
rc, errors = main_with_errors(argv=[])
assert rc == 0, \
'Found %d code style errors / warnings:\n' % len(errors) + \
'\n'.join(errors)

23
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/test/test_pep257.py


# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ament_pep257.main import main
import pytest
@pytest.mark.linter
@pytest.mark.pep257
def test_pep257():
rc = main(argv=['.', 'test'])
assert rc == 0, 'Found code style errors / warnings'

0
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/__init__.py

50
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/color_publisher.py


#!/usr/bin/env python
import random
import rclpy
from rclpy.node import Node
from unity_robotics_demo_msgs.msg import UnityColor
class ColorPublisher(Node):
def __init__(self):
super().__init__('color_publisher')
self.publisher_ = self.create_publisher(UnityColor, 'color', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
self.do_publish()
def do_publish(self):
if self.i == 0:
color = UnityColor()
color.r = random.randint(0, 255)
color.g = random.randint(0, 255)
color.b = random.randint(0, 255)
color.a = 1
self.get_logger().info(f'Publishing: {color}')
self.publisher_.publish(color)
self.i += 1
def timer_callback(self):
quit()
def main(args=None):
rclpy.init(args=args)
color_pub = ColorPublisher()
while rclpy.ok():
rclpy.spin_once(color_pub)
#color_pub.destroy_node()
#rclpy.shutdown()
if __name__ == '__main__':
main()

34
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo/unity_robotics_demo/position_service.py


#!/usr/bin/env python
import random
import rclpy
from unity_robotics_demo_msgs.srv import PositionService
from rclpy.node import Node
class PositionServiceNode(Node):
def __init__(self):
super().__init__('position_service_node')
self.srv = self.create_service(PositionService, 'pos_srv', self.new_position_callback)
def new_position_callback(self, request, response):
response.output.pos_x = random.uniform(-4.0, 4.0)
response.output.pos_z = random.uniform(-4.0, 4.0)
return response
def main(args=None):
rclpy.init(args=args)
pos_service = PositionServiceNode()
rclpy.spin(pos_service)
rclpy.shutdown()
if __name__ == '__main__':
main()

34
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/CMakeLists.txt


cmake_minimum_required(VERSION 3.5)
project(unity_robotics_demo_msgs)
# find dependencies
find_package(rosidl_default_generators REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(std_msgs REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/PosRot.msg"
"msg/UnityColor.msg"
"srv/PositionService.srv"
"srv/ObjectPoseService.srv"
DEPENDENCIES builtin_interfaces geometry_msgs std_msgs
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()

25
tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/package.xml


<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>unity_robotics_demo_msgs</name>
<version>0.0.1</version>
<description>Messages used by ROS-Unity Integration tutorial (ROS2 version)</description>
<maintainer email="unity-robotics@unity.com">Unity Robotics</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>

24
tutorials/ros_unity_integration/ros_docker/Dockerfile


FROM ros:melodic-ros-base
ENV ROS_WORKSPACE=/catkin_ws
# Copy packages
COPY ./ros_packages/ $ROS_WORKSPACE/src/
RUN git clone https://github.com/Unity-Technologies/ROS-TCP-Endpoint $ROS_WORKSPACE/src/ros_tcp_endpoint -b laurie/Ros2SinglePackage
COPY ./ros_docker/set-up-workspace /setup.sh
#COPY docker/tutorial /
RUN chmod +x /setup.sh && /setup.sh && rm /setup.sh
WORKDIR $ROS_WORKSPACE
# Source the workspace on sign in
RUN echo ". devel/setup.bash" >> ~/.bashrc
# making sure the file modes are executable
RUN chmod +x src/ros_tcp_endpoint/src/ros_tcp_endpoint/*.py
#ENTRYPOINT ["/tutorial"]

6
tutorials/ros_unity_integration/ros_docker/set-up-workspace


#!/bin/bash
source /opt/ros/melodic/setup.bash
echo "ROS_IP: 0.0.0.0" > $ROS_WORKSPACE/src/ros_tcp_endpoint/config/params.yaml
cd $ROS_WORKSPACE
catkin_make

34
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/CMakeLists.txt


cmake_minimum_required(VERSION 2.8.3)
project(unity_robotics_demo)
find_package(catkin REQUIRED COMPONENTS
rospy
std_msgs
geometry_msgs
ros_tcp_endpoint
message_generation
)
catkin_package(CATKIN_DEPENDS
ros_tcp_endpoint
message_runtime)
catkin_install_python(PROGRAMS
scripts/position_service.py
scripts/color_publisher.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_robotics_demo.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)

34
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/package.xml


<?xml version="1.0"?>
<package format="2">
<name>unity_robotics_demo</name>
<version>0.0.0</version>
<description>The unity_robotics_demo package (ROS1 version)</description>
<maintainer email="unity-robotics@unity3d.com">Unity Robotics</maintainer>
<license>Apache 2.0</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>rospy</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>ros_tcp_endpoint</build_depend>
<build_depend>unity_robotics_demo_msgs</build_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<build_export_depend>ros_tcp_endpoint</build_export_depend>
<build_export_depend>unity_robotics_demo_msgs</build_export_depend>
<exec_depend>message_runtime</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>ros_tcp_endpoint</exec_depend>
<exec_depend>unity_robotics_demo_msgs</exec_depend>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- Other tools can request additional information be placed here -->
</export>
</package>

48
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/color_publisher.py


#!/usr/bin/env python
import random
import rospy
import rosgraph
import time
from unity_robotics_demo_msgs.msg import UnityColor
TOPIC_NAME = 'color'
NODE_NAME = 'color_publisher'
def post_color():
pub = rospy.Publisher(TOPIC_NAME, UnityColor, queue_size=10)
rospy.init_node(NODE_NAME, anonymous=True)
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
color = UnityColor(r, g, b, 1)
wait_for_connections(pub, TOPIC_NAME)
pub.publish(color)
time.sleep(0.1)
def wait_for_connections(pub, topic):
ros_master = rosgraph.Master('/rostopic')
topic = rosgraph.names.script_resolve_name('rostopic', topic)
num_subs = 0
for sub in ros_master.getSystemState()[1]:
if sub[0] == topic:
num_subs+=1
for i in range(10):
if pub.get_num_connections() == num_subs:
return
time.sleep(0.1)
raise RuntimeError("failed to get publisher")
if __name__ == '__main__':
try:
post_color()
except rospy.ROSInterruptException:
pass

40
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/CMakeLists.txt


cmake_minimum_required(VERSION 2.8.3)
project(unity_robotics_demo_msgs)
find_package(catkin REQUIRED COMPONENTS
rospy
std_msgs
geometry_msgs
message_generation
)
add_message_files(FILES
PosRot.msg
UnityColor.msg
)
add_service_files(FILES
ObjectPoseService.srv
PositionService.srv
)
generate_messages(
DEPENDENCIES
geometry_msgs
std_msgs
)
catkin_package(CATKIN_DEPENDS
message_runtime)
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_robotics_demo.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)

7
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/PosRot.msg


float32 pos_x
float32 pos_y
float32 pos_z
float32 rot_x
float32 rot_y
float32 rot_z
float32 rot_w

4
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/msg/UnityColor.msg


int32 r
int32 g
int32 b
int32 a

28
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/package.xml


<?xml version="1.0"?>
<package format="2">
<name>unity_robotics_demo_msgs</name>
<version>0.0.1</version>
<description>Messages for the unity_robotics_demo package (ROS1 version)</description>
<maintainer email="unity-robotics@unity3d.com">Unity Robotics</maintainer>
<license>Apache 2.0</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>message_generation</build_depend>
<build_depend>std_msgs</build_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>message_runtime</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>ros_tcp_endpoint</exec_depend>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- Other tools can request additional information be placed here -->
</export>
</package>

3
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/ObjectPoseService.srv


string object_name
---
geometry_msgs/Pose object_pose

3
tutorials/ros_unity_integration/ros_packages/unity_robotics_demo_msgs/srv/PositionService.srv


PosRot input
---
PosRot output

154
tutorials/ros_unity_integration/server_endpoint.md


# ROS–Unity Integration: Server Endpoint
A walkthrough of the important components of a ROS TCP endpoint script using the `robotics_demo` package as a example.
The following is an example of a server endpoint Python script that:
- Gets parameters from `rosparam`
- Creates corresponding ROS Publisher, Subscriber, and Service objects to interact with topics and services running in ROS network
- Starts TCP Server process to handle incoming and outgoing connections
```python
#!/usr/bin/env python
import rospy
from ros_tcp_endpoint import TcpServer, RosPublisher, RosSubscriber, RosService, UnityService
from robotics_demo.msg import PosRot, UnityColor
from robotics_demo.srv import PositionService, ObjectPoseService
def main():
ros_node_name = rospy.get_param("/TCP_NODE_NAME", 'TCPServer')
buffer_size = rospy.get_param("/TCP_BUFFER_SIZE", 1024)
connections = rospy.get_param("/TCP_CONNECTIONS", 10)
tcp_server = TcpServer(ros_node_name, buffer_size, connections)
rospy.init_node(ros_node_name, anonymous=True)
tcp_server.start({
'pos_rot': RosPublisher('pos_rot', PosRot, queue_size=10),
'color': RosSubscriber('color', UnityColor, tcp_server),
'pos_srv': RosService('pos_srv', PositionService),
'obj_pose_srv': UnityService('obj_pose_srv', ObjectPoseService, tcp_server),
})
rospy.spin()
if __name__ == "__main__":
main()
```
## Import Statements for Services and Messages
```python
from ros_tcp_endpoint import TcpServer, RosPublisher, RosSubscriber, RosService, UnityService
from robotics_demo.msg import PosRot, UnityColor
from robotics_demo.srv import PositionService, ObjectPoseService
```
## Creating the Server
Requires:
- The ROS node name
```python
tcp_server = TcpServer(ros_node_name, buffer_size, connections)
```
The `ros_node_name` argument is required and the `buffer_size` and `connections` are optional. They are set to `1024` and `10` by default if not provided in the constructor arguments.
## Instantiate the ROS Node
```python
rospy.init_node(ros_node_name, anonymous=True)
```
## Starting the Server
```python
tcp_server.start({
'pos_rot': RosPublisher('pos_rot', PosRot, queue_size=10),
'color': RosSubscriber('color', UnityColor, tcp_server),
'pos_srv': RosService('pos_srv', PositionService),
'obj_pose_srv': UnityService('obj_pose_srv', ObjectPoseService, tcp_server),
})
rospy.spin()
```
## Source Destination Dictionary
The argument to start() is a dictionary keyed by topic or service with the corresponding ROS communication class as the value. The dictionary is used by the TCP server to direct messages to and from the ROS network.
## ROS Publisher
A ROS Publisher allows a Unity component to send messages on a given topic to other ROS nodes. It requires three components:
- Topic name
- ROS message class generated from running `catkin_make` command
- Queue size (optional)
`RosPublisher('pos_rot', PosRot, queue_size=10)`
## ROS Subscriber
A ROS Subscriber allows a Unity component to receive messages from other ROS nodes on a given topic. It requires three components:
- Topic name
- ROS message class generated from running `catkin_make` command
- The tcp server that will connect to Unity
`RosSubscriber('color', UnityColor, tcp_server)`
## ROS Service
A ROS Service is similar to a RosPublisher, in that a Unity component sends a Request message to another ROS node. Unlike a Publisher, the Unity component then waits for a Response back. It requires two components:
- Service name
- ROS Service class generated from running `catkin_make` command
`RosService('pos_srv', PositionService)`
## Unity Service
A Unity Service is similar to a RosSubscriber, in that a Unity component receives a Request message from another ROS node. It then sends a Response back. It requires three components:
- Service name
- ROS Service class generated from running `catkin_make` command
- The tcp server that will connect to Unity
`UnityService('obj_pose_srv', ObjectPoseService, tcp_server)`
## Parameters
The following parameters can be hardcoded, but for the sake of portability, we recommend setting the parameters using the `rosparam set` command, or a `rosparam` YAML file.
```python
ros_node_name = rospy.get_param("/TCP_NODE_NAME", 'TCPServer')
buffer_size = rospy.get_param("/TCP_BUFFER_SIZE", 1024)
connections = rospy.get_param("/TCP_CONNECTIONS", 10)
```
In addition, the TCPServer class uses the ROS parameters ROS_IP and ROS_TCP_PORT to determine what ip & port to listen on.
> Note: Read more about the ROS Parameter Server [here](http://wiki.ros.org/Parameter%20Server).
## Launch File
An example launch file that will set the appropriate ROSPARAM values required for a parameterized TCP Endpoint script.
```
<launch>
<env name="ROS_IP" value="127.0.0.1"/>
<env name="ROS_HOSTNAME" value="$(env ROS_IP)"/>
<param name="ROS_IP" type="str" value="$(env ROS_IP)" />
<param name="ROS_TCP_PORT" type="int" value="10000" />
<param name="TCP_NODE_NAME" type="str" value="TCPServer" />
<group ns="position_service_and_endpoint">
<node pkg="robotics_demo" name="position_service" type="position_service.py"/>
<node pkg="robotics_demo" name="server_endpoint" type="server_endpoint.py"/>
</group>
</launch>
```

112
tutorials/ros_unity_integration/service.md


# ROS–Unity Integration: Service
Create a simple Unity scene which calls a [ROS service](http://wiki.ros.org/Services) with a GameObject's position and rotation to receive a new position to move the GameObject towards.
## Setting Up ROS
(Skip to [Start the Position service](service.md#start-the-position-service) if you already did the [ROS–Unity Integration Publisher](publisher.md) or [Subscriber](subscriber.md) tutorials.)
- Copy the `tutorials/ros_packages/robotics_demo` folder of this repo into the `src` folder in your Catkin workspace.
- Follow the [ROS–Unity Initial Setup](setup.md) guide.
- Open a new terminal window, navigate to your ROS workspace, and run the following commands:
```bash
source devel/setup.bash
rosrun robotics_demo server_endpoint.py
```
Once the server_endpoint has started, it will print something similar to `[INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000`.
## Start the Position service
- Open a new terminal window, navigate to your ROS workspace, and run the following commands:
```bash
source devel/setup.bash
rosrun robotics_demo position_service.py
```
## Setting Up Unity Scene
- Generate the C# code for `PositionService`'s messages by going to `Robotics` -> `Generate ROS Messages...`
- Set the input file path to `PATH/TO/Unity-Robotics-Hub/tutorials/ros_packages/robotics_demo`, expand the robotics_demo folder and click `Build 2 srvs`.
![](images/generate_messages_2.png)
- The generated files will be saved in the default directory `Assets/RosMessages/RoboticsDemo/srv`.
- Create a script and name it `RosServiceExample.cs`
- Paste the following code into `RosServiceExample.cs`
- **Note:** This script can be found at `tutorials/ros_unity_integration/unity_scripts`.
```csharp
using RosMessageTypes.RoboticsDemo;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
public class RosServiceExample : MonoBehaviour
{
ROSConnection ros;
public string serviceName = "pos_srv";
public GameObject cube;
// Cube movement conditions
public float delta = 1.0f;
public float speed = 2.0f;
private Vector3 destination;
float awaitingResponseUntilTimestamp = -1;
void Start()
{
ros = ROSConnection.instance;
destination = cube.transform.position;
}
private void Update()
{
// Move our position a step closer to the target.
float step = speed * Time.deltaTime; // calculate distance to move
cube.transform.position = Vector3.MoveTowards(cube.transform.position, destination, step);
if (Vector3.Distance(cube.transform.position, destination) < delta && Time.time > awaitingResponseUntilTimestamp)
{
Debug.Log("Destination reached.");
MPosRot cubePos = new MPosRot(
cube.transform.position.x,
cube.transform.position.y,
cube.transform.position.z,
cube.transform.rotation.x,
cube.transform.rotation.y,
cube.transform.rotation.z,
cube.transform.rotation.w
);
MPositionServiceRequest positionServiceRequest = new MPositionServiceRequest(cubePos);
// Send message to ROS and return the response
ros.SendServiceMessage<MPositionServiceResponse>(serviceName, positionServiceRequest, Callback_Destination);
awaitingResponseUntilTimestamp = Time.time+1.0f; // don't send again for 1 second, or until we receive a response
}
}
void Callback_Destination(MPositionServiceResponse response)
{
awaitingResponseUntilTimestamp = -1;
destination = new Vector3(response.output.pos_x, response.output.pos_y, response.output.pos_z);
Debug.Log("New Destination: " + destination);
}
}
```
- From the main menu bar, open `Robotics/ROS Settings`, and change the `ROS IP Address` variable to the ROS IP.
- Create an empty GameObject and name it `RosService`.
- Attach the `RosServiceExample` script to the `RosService` GameObject. Drag the cube GameObject onto its `cube` parameter.
- Pressing play in the Editor should start communication with the `position_service` script, running as a ROS node, causing the cube to move to random positions in the scene.
> Please reference [networking troubleshooting](network.md) doc if any errors are thrown.
![](images/tcp_3.gif)

/tutorials/ros_unity_integration/unity_scripts/RosServiceExample.cs → /tutorials/ros_unity_integration/unity_scripts/RosServiceCallExample.cs

/tutorials/ros_packages/robotics_demo/launch → /tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/launch

/tutorials/ros_packages/robotics_demo/msg → /tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/msg

/tutorials/ros_packages/robotics_demo/scripts/position_service.py → /tutorials/ros_unity_integration/ros_packages/unity_robotics_demo/scripts/position_service.py

/tutorials/ros_packages/robotics_demo/srv → /tutorials/ros_unity_integration/ros2_packages/unity_robotics_demo_msgs/srv

正在加载...
取消
保存