Skip to content

Build the ROS 2 Workspace#

This procedure creates the ROS 2 environment, installs the DDS loopback fence and builds the workspace in the folder ROS. All software goes into one conda environment. The procedure installs nothing in the system.

WARNING

Do not start a ROS 2 node of this workspace outside the DDS loopback fence. A drive-by-wire command that reaches the real Polaris can move the vehicle and cause injury. Do the steps in the given sequence. The fence is active before the first node starts.

The DDS Loopback Fence#

ROS 2 nodes find each other on the network automatically. A workstation of the lab can be on the same network as the real Polaris. The DDS loopback fence is a set of environment settings that keeps all ROS 2 traffic on the address 127.0.0.1.

The DDS loopback fence: the simulator, the ROS 2 bridge and the ROS 2 nodes of the workstation exchange data on 127.0.0.1 only. The settings of the fence stop all DDS traffic to the LAN and to the Tailscale network, where the real Polaris is. Workstation DDS loopback fence interface lo, address 127.0.0.1, ROS domain 77 Game or ACRES Core local TCP sockets ROS 2 bridge sim_bridge TCP ROS 2 nodes controller, RViz 2, CLI ROS 2 bag record and play DDS between the nodes: UDP unicast Ethernet, Wi-Fi LAN tailscale0 Tailscale network 1, 2 1, 2 Real Polaris vehicle computer ROS 2 Humble Cyclone DDS ROS domain 0 drive-by-wire commands move the vehicle network network 3: other ports Settings of the Fence ROS/Env/dds_safety.sh sets them in each shell of the conda environment ros2 1 ROS_LOCALHOST_ONLY=1 The middleware selects only the interface lo. 2 CYCLONEDDS_URI=cyclonedds_localhost.xml No multicast. The only discovery peer is 127.0.0.1. 3 ROS_DOMAIN_ID=77 UDP ports 26660 to 26789. Domain 0 starts at 7400. RMW_IMPLEMENTATION=rmw_cyclonedds_cpp The middleware that reads the configuration file. ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST The same limit for ROS 2 Iron and later versions. unset ROS_STATIC_PEERS ROS_DISCOVERY_SERVER No peer or discovery server from the parent shell.
The settings of the fence keep the ROS 2 traffic inside the workstation. The real Polaris is on the network outside. Open the diagram

The file ROS/Env/dds_safety.sh contains the settings. Two paths apply the file:

  • The script ROS/Env/setup_env.sh applies it when you source the script.
  • The conda hook applies it each time you activate the environment ros2.

Nodes and Launch Files gives each variable and its value.

Before You Start#

  • The computer has Linux and the bash shell.
  • Miniconda is in ~/miniconda3. If conda is in a different folder, set CONDA_ROOT to that folder.
  • The repository is on the disk. All commands start in the repository root.
  • The computer can download packages from the conda channels robostack-humble and conda-forge.

The build does not use the game. The package acres_core_sim compiles the sources of ACRES Core from the folder Core.

Create the Environment#

  1. Create the conda environment ros2 with ROS 2 Humble from RoboStack.

    conda env create -f ROS/Env/environment.yml --override-channels -c robostack-humble -c conda-forge
    

    Expected Result

    The command conda env list shows the environment ros2.

  2. Install the conda hooks of the fence.

    ROS/Env/install_conda_hooks.sh
    

    Expected Result

    installed DDS fence into /home/user/miniconda3/envs/ros2 (conda deactivate && conda activate ros2 to apply)
    

    Note

    The script copies the settings into the environment. Run the script again after you change a file in ROS/Env.

  3. Open a shell with the environment and the fence.

    source ROS/Env/setup_env.sh
    

    Expected Result

    acres_ros: workspace not built yet (see ROS/README.md)
    acres_ros: ROS 2 humble | rmw_cyclonedds_cpp | ROS_DOMAIN_ID=77 | ROS_LOCALHOST_ONLY=1
    

    Do this step in each new shell. The first line goes away after the build.

Prove the Fence#

The check starts one talker and one listener of the ROS 2 demo nodes. It reads the trace of Cyclone DDS and records each UDP packet that the talker sends.

  1. Run the check.

    ROS/Env/check_dds_isolation.sh
    

    Expected Result

    The last line is PASS: DDS traffic stays on loopback. The addresses of the other interfaces are different on each computer.

    == environment
      ROS_LOCALHOST_ONLY             1
      ROS_DOMAIN_ID                  77
      RMW_IMPLEMENTATION             rmw_cyclonedds_cpp
      CYCLONEDDS_URI                 file:///home/user/ACRES/ROS/Env/cyclonedds_localhost.xml
      ROS_AUTOMATIC_DISCOVERY_RANGE  LOCALHOST
      ok    ROS_LOCALHOST_ONLY=1
      ok    ROS_DOMAIN_ID set and not 0
      ok    RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
      ok    CYCLONEDDS_URI file exists
    == talker (under strace) + listener for 6s
      socket 0.0.0.0:26660
      socket 0.0.0.0:26661
      socket 127.0.0.1:40669
    == cyclone trace
      interfaces: lo udp/127.0.0.1(q1) eno1 udp/10.0.0.12(q9) tailscale0 udp/100.64.0.5(q9)
      selected interfaces: lo (index 1 priority 2)
      ownip: udp/127.0.0.1
      add_peer_addresses: add udp/127.0.0.1:26660, :26662, ... (peers: 127.0.0.1 only)
    == UDP send destinations (strace)
      289 inet_addr("127.0.0.1")
    == verdict
      ok    listener heard the talker over loopback (5 msgs)
      ok    Cyclone selected only lo
      ok    own locator is udp/127.0.0.1
      ok    every discovery peer is 127.0.0.1
      ok    multicast disabled
      ok    every UDP datagram sent went to 127.0.0.1 (0 to other addresses)
      ok    transmit socket bound to 127.0.0.1
    logs: /tmp/acres_dds_check.jvBkxh
    PASS: DDS traffic stays on loopback
    

    CAUTION

    If the last line is FAIL, do not start a node. Install the conda hooks again, open a new shell and repeat the check.

    Note

    The two sockets at 0.0.0.0 are the receive sockets of Cyclone DDS. The fence does not close them to the other interfaces. The transmit socket is at 127.0.0.1, thus no reply can go to a different computer. A firewall rule for the UDP ports 26600 to 26799 closes the receive sockets.

Build the Workspace#

  1. Build all packages with colcon.

    cd ROS
    colcon build
    cd ..
    

    Expected Result

    Starting >>> ds_dbw_msgs
    Starting >>> acres_interfaces
    Starting >>> rslidar_msg
    Finished <<< rslidar_msg [2.71s]
    Finished <<< acres_interfaces [16.7s]
    Finished <<< ds_dbw_msgs [30.8s]
    Starting >>> acres_description
    Finished <<< acres_description [0.87s]
    Starting >>> acres_sim
    Finished <<< acres_sim [31.1s]
    Starting >>> acres_core_sim
    Finished <<< acres_core_sim [16.8s]
    
    Summary: 6 packages finished [1min 20s]
      2 packages had stderr output: acres_core_sim acres_sim
    

    The time is for a workstation with 16 processor threads. The output on stderr is one CMake warning about the variable Python_FIND_VIRTUALENV. The warning has no effect.

  2. Source the script again to load the built workspace.

    source ROS/Env/setup_env.sh
    

    Expected Result

    acres_ros: ROS 2 humble | rmw_cyclonedds_cpp | ROS_DOMAIN_ID=77 | ROS_LOCALHOST_ONLY=1
    
  3. List the executables of the bridge package.

    ros2 pkg executables acres_sim
    

    Expected Result

    acres_sim dbw_demo_driver
    acres_sim lab_stubs
    acres_sim sim_bridge
    

The file ROS/Env/colcon_defaults.yaml gives the build options to colcon. The script setup_env.sh sets COLCON_DEFAULTS_FILE to this file.

Run the Tests#

The tests use a substitute for the game (ROS/acres_sim/test/fake_game.py) and ACRES Core. They do not start the game. Each test uses free ports and a namespace of its own. A running session on the same computer does not change the results.

  1. Run the tests of the three packages that have tests.

    cd ROS
    colcon test --packages-select acres_sim acres_description acres_core_sim
    

    Expected Result

    Finished <<< acres_description [0.43s]
    Finished <<< acres_sim [16.2s]
    Finished <<< acres_core_sim [23.0s]
    
    Summary: 3 packages finished [39.7s]
    
  2. Show the results.

    colcon test-result --verbose
    cd ..
    

    Expected Result

    Summary: 60 tests, 0 errors, 0 failures, 5 skipped
    

The table gives the tests of each package.

Package Test Number Content
acres_sim test_acres_sim_unit 23 The stream frames, the message conversions, the JSON functions and the J1939 codec.
acres_sim test_integration.py 6 The topics, the commands, lockstep, the services, the CAN bus and two agents.
acres_sim test_j1939_golden.py 1 The C++ codec against the Python codec.
acres_sim test_parity.py 5 A comparison with the Python bridge that the project removed. colcon skips these tests.
acres_core_sim test_core_sim_unit 10 The georeference, the INS, the drive-by-wire path and the server sockets.
acres_core_sim test_integration.py 5 ACRES Core behind the bridge: topics, lockstep, services, determinism and rate.
acres_description test_fake_polaris.py 4 The layout of the synthetic LiDAR cloud.

colcon also counts one CTest entry for each test program. This adds 6 entries to the total of 60.

Packages That the Repository Does Not Contain#

The package purdue_ranger contains the URDF file and the launch files of the real Polaris. Its licence is proprietary. The public repository does not contain it. All 6 packages of the repository build and pass their tests without it.

The Polaris description needs the file urdf/ranger.urdf of purdue_ranger. Without the package, these launch files stop:

Launch File Without purdue_ranger
acres_sim sim_bridge.launch.py Stops with the default vehicle:=polaris. Operates with vehicle:=auto or vehicle:=maxxum.
acres_core_sim core_sim.launch.py Stops. Start core_sim and sim_bridge with ros2 run.
acres_description description.launch.py, bag_replay.launch.py, fake_polaris.launch.py Stop.

The launch file stops with this message:

[ERROR] [launch]: Caught exception in launch (see debug for traceback): executed command failed. Command: xacro .../urdf/polaris_ranger.urdf.xacro ...
Captured stderr output: error: <class 'ament_index_python.packages.PackageNotFoundError'>: "package 'purdue_ranger' not found, ...

The bridge does not need the package. All topics, services and actions of the bridge are available without it. Only the static frames of the URDF (base_footprint to lidar and to the camera) and the model in RViz are absent. First ROS 2 Session gives the commands for the two cases.

Add the Package as a Lab Member#

Members of the Purdue lab can copy the package from the Polaris repository of the lab. In the command below, POLARIS_REPO is the folder of that repository.

  1. Copy the folder ros-packages/purdue_ranger into ROS/vendor.

    cp -r "$POLARIS_REPO/ros-packages/purdue_ranger" ROS/vendor/
    
  2. Build the package.

    source ROS/Env/setup_env.sh
    cd ROS
    colcon build --packages-select purdue_ranger
    cd ..
    

    Expected Result

    colcon list shows 7 packages. The launch files of the table above start.

CAUTION

Do not add purdue_ranger to a public repository. The file .gitignore excludes the folder ROS/vendor/purdue_ranger.

WARNING

The package purdue_ranger also contains the launch files of the real vehicle and the node sys_enable_node.py. Do not start them. They are for the vehicle computer only.

Next Steps#