Skip to content

Commit 3010415

Browse files
committed
First version of unified Ros2ForUnity - building into Unity package. Needs Windows support re-added
Signed-off-by: Adam Dabrowski <[email protected]>
0 parents  commit 3010415

37 files changed

+1945
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
install
2+
log
3+
build
4+
.idea
5+
src/ros2cs
6+
src/Ros2ForUnity/Plugins
7+
!src/Ros2ForUnity/Plugins/.gitkeep

README.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
Ros2 For Unity
2+
=============
3+
4+
ROS2 For Unity is a high-performance communication solution to connect Unity3D and ros2 ecosystem in a ros2 "native" way. Communication is not bridged as in several other solutions, but instead uses ros2 (rcl layer and below) middleware stack, which means your can have ros2 nodes in your simulation.
5+
Advantages of this module include:
6+
- High performance, as in supporting higher throughputs and having considerably lower latencies than bridging solutions.
7+
- Your simulation entities are real ros2 nodes / publishers / subscribers and will behave correctly with e.g. command line tooling such as `ros2 topic`. They will respect QoS settings and can use ros2 native time.
8+
- The module supplies abstractions and tools to use in your Unity project, including transformations, sensor interface, a clock, spinning loop wrapped in a Monobehavior, handling initialization and shutdown.
9+
- Suppots all standard ros2 messages
10+
- Custom messages are generated automatically with build, using standard ros2 way. It is straightforward to generate and use them without having to define `.cs` equivalents by hand.
11+
- The module is wrapped as Unity asset.
12+
13+
### Platforms
14+
15+
Supported OSes:
16+
- Ubuntu 20.04 (bash)
17+
- Windows 10 (powershell)
18+
19+
Supported ROS2 distributions:
20+
- Foxy
21+
- Galactic
22+
23+
The asset can be prepared in two flavors:
24+
- standalone (no ROS2 installation required on target machine, e.g. your Unity3D simulation server). All required dependencies are installed and can be used e.g. as a complete set of Unity3D plugins.
25+
- overlay (assuming existing (supported) ROS2 installation on target machine). Only asset libraries and generated messages are installed.
26+
27+
#### Platform considerations
28+
29+
Running the Editor or App using this Asset on Ubuntu requires a start script that populates the LD_LIBRARY_PATH. This is due to dynamic plugin loading mechanism used in the ros2cs library.
30+
On Windows, no script is necessary and both Editor and App can be ran the usual way (e.g. with a click or cmd line).
31+
32+
### Releases
33+
34+
You can download pre-built releases of the Asset that support both platforms and specific ros2 and Unity3D versions. (TODO - add links).
35+
36+
### Prerequisites
37+
38+
#### Ubuntu
39+
40+
* ROS2 installed on the system, along with `test-msgs` and `fastrtps` packages
41+
* vcstool package - [see here](https://github.com/dirk-thomas/vcstool)
42+
* .NET core 3.1 sdk - [see here](https://www.microsoft.com/net/learn/get-started)
43+
44+
The following script can be used to install the aforementioned prerequisites on Ubuntu 20.04:
45+
46+
```bash
47+
# Install tests-msgs for your ROS2 distribution
48+
apt install -y ros-${ROS_DISTRO}-test-msgs ros-${ROS_DISTRO}-fastrtps ros-${ROS_DISTRO}-rmw-fastrtps-cpp
49+
50+
# Install vcstool package
51+
curl -s https://packagecloud.io/install/repositories/dirk-thomas/vcstool/script.deb.sh | sudo bash
52+
sudo apt-get update
53+
sudo apt-get install -y python3-vcstool
54+
55+
# Install .NET core
56+
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
57+
sudo dpkg -i packages-microsoft-prod.deb
58+
rm packages-microsoft-prod.deb
59+
sudo apt-get update; \
60+
sudo apt-get install -y apt-transport-https && \
61+
sudo apt-get update && \
62+
sudo apt-get install -y dotnet-sdk-3.1
63+
```
64+
65+
#### Windows
66+
67+
* ROS2 installed on the system
68+
* vcstool package - [see here](https://github.com/dirk-thomas/vcstool)
69+
* .NET 5.0 sdk - [see here](https://dotnet.microsoft.com/download/dotnet/5.0)
70+
* xUnit testing framework (for tests only) - [see here](https://xunit.net/)
71+
72+
73+
### Note on project composition
74+
75+
The project will pull `ros2cs` into the workspace, which also functions independently as it is a more general project aimed at any `C# / .Net` environment. It has its own README and scripting, but for building the Unity Asset, please use instructions and scripting in this document instead, unless you also wish to run tests or examples for `ros2cs`.
76+
77+
### Building
78+
79+
#### Windows considerations
80+
81+
> For **Windows**, [path length is limited to 260 characters](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation). Clone your repo to `C:\dev` or a similar shallow path to avoid this issue during build.
82+
83+
> For **Windows**, a Visual Studio preconfigured powershell terminal must be used. Standard powershell prompt might not be configured properly to be used with MSVC compiler and Windows SDKs. You should have Visual Studio already installed (ROS2 dependency) and you can find shortcut for `Developer PowerShell for VS` here: `C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio 2019\Visual Studio Tools`.
84+
85+
> A powershell terminal with administrator privileges is required for **Windows** and **ros2 galactic**. This is because python packages installation requires a privilage for creating symlinks. More about this issue: [github issue](https://github.com/ament/ament_cmake/issues/350).
86+
87+
> There is a bug with hardcoded include exports in some **ros2 galactic** packages on **Windows**. Easiest workaround is to create a `C:\ci\ws\install\include` directory in your system. More about this bug and proposed workarounds: [github issue](https://github.com/ros2/rclcpp/issues/1688#issuecomment-858467147).
88+
89+
#### Build instructions
90+
91+
* Clone this project.
92+
* If you wish to include custom messages in your build, make sure to put them into `ros2_for_unity_custom_messages.repos` file. You can change this file in your fork or change `custom_messages.repos` in the ros2cs repository fork, it will work either way as the scripts will pull both sources.
93+
As an alternative, you can also add your custom messages package directly by copying it to `src/ros2cs/custom_messages` folder after the next step. Any message package in the build tree will be subjected to `.cs` file generator during the build.
94+
* You need to source your ROS2 installation (e.g. `source /opt/ros/foxy/setup.bash` on Ubuntu or `C:\dev\ros2_foxy\local_setup.ps1` on Windows) before you proceed, for each new open terminal. On Ubuntu, you can also include this command in your `~/.bashrc` file.
95+
* Run 'pull_repositories.sh'. This will pull `ros2cs` as well as your custom messages.
96+
* Run `build.sh` (Ubuntu) or `build.ps1` (Windows) script.
97+
* You can build tests by adding `--with-tests` argument to `build` command.
98+
* It invokes `colcon_build` with `--merge-install` argument to simplify libraries installation.
99+
* It deploys built plugins into the Asset directory. Note that only plugins built for the current platform will be deployed (there is no cross-compilation).
100+
* It prepares Unity Asset that is ready to import into your Unity project.
101+
102+
#### Standalone version
103+
104+
By default, build process generates standalone libraries.
105+
You can disable this feature by setting CMake option `STANDALONE_BUILD` to `OFF` (e.g. through editing `build.sh`).
106+
107+
## Running with Unity
108+
109+
## Standalone mode
110+
111+
If the Asset is built with `STANDALONE_BUILD` option set to `1` (the default), then nothing extra needs to be done. Otherwise, you have to source your ros distribution before launching either Unity3D Editor or Application.
112+
113+
## Running the Editor
114+
115+
Open your Unity3D project and import Ros2ForUnity Asset which is built by this project.
116+
117+
#### Additional considerations for Linux
118+
119+
TODO - we are looking to replace this solution with something simpler. This section needs changes!
120+
121+
After including the Asset, close the Editor. You need to use `start.py` from `linux-utils` directory. It is necessary to run your Unity3D Editor or built App.
122+
This can be done directly or through wrapping your Unity3D project into a ros2 python package (using files from `linux-utils`) and running `colcon build`, sourcing your workspace and calling `ros2 run ros2-for-unity start editor`.
123+
124+
> This is due to the necessity for Unity3D to find all required assemblies. `dlopen` is used under the hood to dynamically
125+
load necessary libraries (including custom messages and rmw implementation).
126+
Note that unlike Windows `LoadLibrary`, `dlopen` uses `LD_LIBRARY_PATH` value from the start of the process execution and later modifications do not
127+
affect the search paths. Thus, it is necessary to change `LD_LIBRARY_PATH` before the process starts.
128+
129+
> Note that as an alternative, you can set the path manually in your system for the Editor, but consider that built App will have a different absolute path to plugins and can be moved and copied around, so this approach is not recommended.
130+
131+
### Building Unity3D application
132+
133+
When there are no errors in the Editor, you can proceed with an application build.
134+
You can do this standard way through `Build->Build Settings...`.
135+
136+
## Running application
137+
138+
### Windows
139+
140+
You can run your application normally by clicking it or executing from command line.
141+
142+
### Linux
143+
144+
On Linux, follow the [Editor instructions](#running-the-editor), but use the start script (directly or through a package wrapper: `ros2 run ros2-for-unity start app --name:=<Your app name>`) to run your application.
145+
This is necessary to ensure plugin visibility by setting `LD_LIBRARY_PATH`.
146+
147+
## Full example (Windows)
148+
149+
Example for setting up `ros2cs` standalone with `Unity` editor on Windows (powershell with git). Let's assume working directory is `C:\dev` and we are using `ROS2 foxy`:
150+
151+
1. Install ros2 distribution, either Foxy or Galactic. We assume standard directory, e.g. `C:\dev\ros2_foxy`.
152+
You can find instructions [here (ros2 binary)](https://docs.ros.org/en/foxy/Installation/Windows-Install-Binary.html) and [here (development tools)](https://docs.ros.org/en/foxy/Installation/Windows-Development-Setup.html).
153+
2. Make sure you are running `Developer PowerShell for Visual Studio` (see **Building** section in `ros2cs` README.md).
154+
3. Source ROS2
155+
```
156+
C:\dev\ros2_foxy\local_setup.ps1
157+
```
158+
4. Follow Build Instructions
159+
5. Launch your Unity3D Project. The following command assumes that you have Unity3D installed in `C:\Program Files\Unity\Hub\Editor\2021.1.7f1\Editor\Unity.exe`:
160+
```
161+
& "C:\Program Files\Unity\Hub\Editor\2021.1.7f1\Editor\Unity.exe" -projectPath C:\dev\<UnityProjectPath>
162+
```
163+
6. Import `Ros2ForUnity` Asset into your project.
164+
10. You should be able to use `Ros2 For Unity` with the module now. You can test if everything works through `Ros2 For Unity` test publisher.
165+
> Note that after you build the Asset, you can use it on a machine that has no ros2 installation.
166+
> You can simply copy over the `Ros2ForUnity` subdirectory to update your Asset.

build.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
3+
if [ -z "${ROS_DISTRO}" ]; then
4+
echo "Source your ros2 distro first (Foxy and Galactic are supported)"
5+
exit 1
6+
fi
7+
8+
TESTS=0
9+
MSG="Build started."
10+
if [ "$1" = "--with-tests" ]; then
11+
TESTS=1
12+
MSG="$MSG (with tests)"
13+
elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
14+
echo "Usage: "
15+
echo "build.sh [--with-tests]"
16+
echo ""
17+
echo "Options:"
18+
echo "--with-tests - build with tests."
19+
exit 1
20+
fi
21+
22+
echo $MSG
23+
#TODO - call ros2cs ./build.sh instead, but with this workspace directory (parametrize the script)
24+
colcon build --merge-install --event-handlers console_direct+ --cmake-args -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=$TESTS && ./deploy_unity_plugins.sh src/Ros2ForUnity/Plugins/

create_unity_asset.ps1

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
<#
3+
.SYNOPSIS
4+
Creates a 'unitypackage' from an input asset.
5+
.DESCRIPTION
6+
This script screates a temporary Unity project in "%USERPROFILE%\AppData\Local\Temp" directory, copy input asset and makes an unity package out of it.
7+
.PARAMETER unity_path
8+
Unity editor executable path
9+
.PARAMETER input_asset
10+
input asset to pack into unity package
11+
.PARAMETER package_name
12+
Unity package name
13+
.PARAMETER output_dir
14+
output file directory
15+
#>
16+
Param (
17+
[Parameter(Mandatory=$true)][string]$unity_path,
18+
[Parameter(Mandatory=$true)][string]$input_asset,
19+
[Parameter(Mandatory=$true)][string]$package_name,
20+
[Parameter(Mandatory=$true)][string]$output_dir
21+
)
22+
23+
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
24+
$temp_dir = $Env:TEMP
25+
26+
& "$unity_path" -version | Tee-Object -Variable unity_version | Out-Null
27+
28+
if ($unity_version -match '^[0-9]{4}\.[0-9]*\.[0-9]*[f]?[0-9]*$') {
29+
Write-Host "Unity editor confirmed..."
30+
} else {
31+
Write-Host "Can't confirm Unity editor. Exiting."
32+
exit 1
33+
}
34+
35+
$tmp_project_path = Join-Path -Path "$temp_dir" -ChildPath "\ros2cs_unity_project\$unity_version"
36+
37+
# Create temp project
38+
if(Test-Path -Path "$tmp_project_path") {
39+
Write-Host "Found existing temporary project for Unity $unity_version."
40+
Remove-Item -Path "$tmp_project_path\Assets\*" -Force -Recurse -ErrorAction Ignore
41+
} else {
42+
Write-Host "Creating Unity temporary project for Unity $unity_version..."
43+
& "$unity_path" -createProject "$tmp_project_path" -batchmode -quit | Out-Null
44+
}
45+
46+
# Copy asset
47+
Write-Host "Copying asset '$input_asset' to export..."
48+
Copy-Item -Path "$input_asset" -Destination "$tmp_project_path\Assets\$package_name" -Recurse
49+
50+
# Creating asset
51+
Write-Host "Saving unitypackage '$output_dir\$package_name.unitypackage'..."
52+
& "$unity_path" -projectPath "$tmp_project_path" -exportPackage "$package_name" "$output_dir\$package_name.unitypackage" -batchmode -quit | Out-Null
53+
54+
# Cleaning up
55+
Write-Host "Cleaning up temporary project..."
56+
Remove-Item -Path "$tmp_project_path\Assets\*" -Force -Recurse -ErrorAction Ignore
57+
58+
Write-Host "Done!" -ForegroundColor Green
59+

create_unity_asset.sh

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/bin/bash
2+
3+
SCRIPT=$(readlink -f $0)
4+
SCRIPTPATH=`dirname $SCRIPT`
5+
6+
display_usage() {
7+
echo "This script creates a temporary Unity project in '/tmp' directory, copy input asset and makes an unity package out of it."
8+
echo ""
9+
echo "Usage:"
10+
echo "create_unity_asset.sh -u <UNITY_PATH> -i <INPUT_ASSET> -p <PACKAGE_NAME> -o <OUTPUT_DIR>"
11+
echo ""
12+
echo "UNITY_PATH - Unity editor executable path"
13+
echo "INPUT_ASSET - input asset to pack into unity package"
14+
echo "PACKAGE_NAME - unity package name"
15+
echo "OUTPUT_DIR - output file directory"
16+
}
17+
18+
UNITY_PATH=""
19+
INPUT_ASSET="src/Ros2ForUnity"
20+
PACKAGE_NAME="Ros2ForUnity"
21+
OUTPUT_DIR="$SCRIPTPATH/install/unity_package"
22+
23+
while [[ $# -gt 0 ]]; do
24+
key="$1"
25+
26+
case $key in
27+
-u|--unity-path)
28+
UNITY_PATH="$2"
29+
shift # past argument
30+
shift # past value
31+
;;
32+
-p|--package_name)
33+
PACKAGE_NAME="$2"
34+
shift # past argument
35+
shift # past value
36+
;;
37+
-i|--input-directory)
38+
INPUT_ASSET="$2"
39+
shift # past argument
40+
shift # past value
41+
;;
42+
-o|--output-directory)
43+
OUTPUT_DIR="$2"
44+
shift # past argument
45+
shift # past value
46+
;;
47+
-h|--help)
48+
display_usage
49+
exit 0
50+
shift # past argument
51+
shift # past value
52+
;;
53+
*) # unknown option
54+
shift # past argument
55+
;;
56+
esac
57+
done
58+
59+
if [ -z "$UNITY_PATH" ] || [ -z "$PACKAGE_NAME" ] || [ -z "$INPUT_ASSET" ] || [ -z "$OUTPUT_DIR" ]; then
60+
echo -e "\nMissing arguments!"
61+
echo ""
62+
display_usage
63+
exit 1
64+
fi
65+
66+
UNITY_VERSION=`$UNITY_PATH -version`
67+
68+
# Test if unity editor is valid
69+
if [[ $UNITY_VERSION =~ ^[0-9]{4}\.[0-9]*\.[0-9]*[f]?[0-9]*$ ]]; then
70+
echo "Unity editor confirmed..."
71+
else
72+
echo "Can't confirm Unity editor. Exiting."
73+
exit 1
74+
fi
75+
76+
TMP_PROJECT_PATH=/tmp/ros2cs_unity_project/$UNITY_VERSION
77+
# Create temp project
78+
if [ -d "$TMP_PROJECT_PATH" ]; then
79+
echo "Found existing temporary project for Unity $UNITY_VERSION."
80+
rm -rf $TMP_PROJECT_PATH/Assets/*
81+
else
82+
rm -rf $TMP_PROJECT_PATH
83+
echo "Creating Unity temporary project for Unity $UNITY_VERSION..."
84+
$UNITY_PATH -createProject $TMP_PROJECT_PATH -batchmode -quit
85+
fi
86+
87+
# Copy asset
88+
echo "Copying asset to export..."
89+
cp -r "$INPUT_ASSET" "$TMP_PROJECT_PATH/Assets/$PACKAGE_NAME"
90+
91+
# Creating asset
92+
echo "Saving unitypackage '$OUTPUT_DIR/$PACKAGE_NAME.unitypackage'..."
93+
mkdir -p $OUTPUT_DIR
94+
$UNITY_PATH -projectPath "$TMP_PROJECT_PATH" -exportPackage "Assets/$PACKAGE_NAME" "$OUTPUT_DIR/$PACKAGE_NAME.unitypackage" -batchmode -quit
95+
96+
# Cleaning up
97+
echo "Cleaning up temporary project..."
98+
rm -rf $TMP_PROJECT_PATH/Assets/*
99+
100+
echo "Done!"
101+

deploy_unity_plugins.ps1

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
2+
$pluginDir=$args[0]
3+
4+
function Print-Help {
5+
"
6+
Usage:
7+
deploy_unity_plugins.ps1 <PLUGINS_DIR>
8+
9+
PLUGINS_DIR - Assets/ROS2/Plugins/ directory of Unity project.
10+
"
11+
}
12+
13+
if (([string]::IsNullOrEmpty($pluginDir)) -Or $args[0] -eq "--help" -Or $args[0] -eq "-h")
14+
{
15+
Print-Help
16+
exit
17+
}
18+
19+
if (Test-Path -Path $pluginDir) {
20+
Write-Host "Copying plugins to to: '$pluginDir' ..."
21+
(Copy-Item -verbose -Path $scriptPath\install\lib\dotnet\* -Destination ${pluginDir} 4>&1).Message
22+
Write-Host "Plugins copied to: '$pluginDir'" -ForegroundColor Green
23+
if(-not (Test-Path -Path $pluginDir\Windows\x86_64\)) {
24+
mkdir ${pluginDir}\Windows\x86_64\
25+
}
26+
Write-Host "Copying libraries to: '$pluginDir\Windows\x86_64\' ..."
27+
(Copy-Item -verbose -Path $scriptPath\install\bin\*.dll -Destination ${pluginDir}\Windows\x86_64\ 4>&1).Message
28+
(Copy-Item -verbose -Path $scriptPath\install\standalone\*.dll -Destination ${pluginDir}\Windows\x86_64\ 4>&1).Message
29+
Write-Host "Libraries copied to '${pluginDir}\Windows\x86_64\'" -ForegroundColor Green
30+
} else {
31+
Write-Host "Plugins directory: '$pluginDir' doesn't exist. Please create it first manually." -ForegroundColor Red
32+
}

0 commit comments

Comments
 (0)