Skip to content

First ROS 2 Session#

This procedure connects the ROS 2 bridge to the game, reads the Polaris topics, sends a drive-by-wire command and calls services. Then it repeats the session with ACRES Core as the simulator.

WARNING

Do all steps in shells that have the DDS loopback fence (source ROS/Env/setup_env.sh). The command topics have the names of the real Polaris. Outside the fence, a command can move the real vehicle and cause injury.

Before You Start#

  • The packaged game is in Packaged/Linux. Refer to Run the Packaged Game.
  • The build of the ROS 2 workspace is complete and the fence check shows PASS. Refer to Build the ROS 2 Workspace.
  • No other simulator uses the ports 5600, 5601 and 5556.

The procedure uses three shells. Shell 1 runs the simulator. Shell 2 runs the bridge. Shell 3 runs the commands. Do this in shells 2 and 3 before the first command:

source ROS/Env/setup_env.sh
The ROS 2 graph of one Polaris session: the three local sockets of the simulator, the node sim_bridge, the topic groups with their rates, the command topics, the services and the action, and the ROS 2 nodes that use them. LOCAL SOCKETS, 127.0.0.1 ROS 2 BRIDGE TOPICS, SERVICES, ACTION ROS 2 NODES Game or ACRES Core Sensor stream -SensorStream=5601 binary frames, TCP clock, INS, LiDAR, camera, barriers Vehicle bridge -RlPort=5556 JSON lines, TCP Simulator control channel -SimControl=5600 JSON lines, TCP Node sim_bridge Sensor reader The reader thread publishes the clock and the INS data. A second thread publishes the clouds and the images. Vehicle client publishes the reports sends each command immediately Control client A step reply waits for the barriers of all channels. frames reports commands requests Clock, 120 Hz /clock rosgraph_msgs/Clock Pose and INS, 100 Hz /vehicle/odom /tf /oxts/fix /oxts/imu /oxts/velocity /sim/ground_truth/odom Odometry, Imu, NavSatFix, TwistStamped LiDAR and camera /lidar/points PointCloud2, 10 Hz /camera/image_raw Image, 10 Hz /camera/camera_info CameraInfo Drive-by-wire reports, 50 Hz /vehicle/*/report ds_dbw_msgs /vehicle/vehicle_velocity /vehicle/dbw_enabled std_msgs/Bool Commands /vehicle/*/cmd ds_dbw_msgs /vehicle/enable /vehicle/disable /sim/reset PoseStamped Simulator control /sim/episode Episode, latched /step_simulation /simulate_steps /get_simulation_state /get_... /acres/record /acres/farm_state simulation_interfaces, acres_interfaces Subscribers RViz 2 ros2 bag record perception nodes Controller dbw_demo_driver or your node Client lockstep loop, task scoring
The session of this procedure. The bridge connects the three sockets of the simulator to the topics, the services and the action. Open the diagram

The game opens three local sockets. The game has no default ports. The ROS 2 launch files use these ports as defaults:

Socket Option of the Game Port Argument of the Launch File
Sensor stream -SensorStream= 5601 sensor_port
Vehicle bridge -RlPort= 5556 rl_port
Simulator control channel -SimControl= 5600 control_port

Start the Game and the Bridge#

  1. In shell 1, start the game with the Polaris and the three sockets.

    Packaged/Linux/Acres.sh -VehicleDemo -Vehicle=polaris \
        -SensorStream=5601 -RlPort=5556 -SimControl=5600
    

    Expected Result

    The Polaris is at the ICSC garage. The log of the game contains these lines:

    ACRES_SENSOR_STREAM_LISTENING agent=polaris port=5601
    ACRES_RL_LISTENING port=5556
    ACRES_SIM_CONTROL_LISTENING port=5600
    ACRES_SIM_CONTROL_READY port=5600 lockstep=0 replay=0 log=
    
  2. In shell 2, start the bridge.

    ros2 launch acres_sim sim_bridge.launch.py vehicle:=auto
    

    Expected Result

    [INFO] [sim_bridge-1]: process started with pid [3154363]
    [sim_bridge]: sim_bridge: sensor stream 127.0.0.1:5601, JSON bridge 127.0.0.1:5556, vehicle auto, frame prefix '', /clock on
    [sim_bridge]: simulator control: waiting for the game's control channel on 127.0.0.1:5600
    [sim_bridge]: publishing the polaris topics
    [sim_bridge]: connected to polaris (polaris): LiDAR 1800 x 32 at 10 Hz, camera 896 x 512 at 10 Hz, INS 100 Hz
    [sim_bridge]: simulator control: connected to 127.0.0.1:5600 (protocol 1, map V03ACRE, state 1, lockstep off, step 1405, 1 agents)
    

    Note

    With vehicle:=auto, the launch file starts only the bridge. This operates without the package purdue_ranger. If you have that package, omit vehicle:=auto. The launch file then also starts the Polaris description and the node odom_path. Add rviz:=true to see the vehicle, the LiDAR cloud and the camera image in RViz 2.

    RViz 2 with the Polaris description, the LiDAR cloud and the camera image of the game

    Without purdue_ranger, the default command 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, ...
    

Read the Topics#

  1. In shell 3, list the topics.

    ros2 topic list -t
    

    Expected Result

    /camera/camera_info [sensor_msgs/msg/CameraInfo]
    /camera/image_raw [sensor_msgs/msg/Image]
    /clock [rosgraph_msgs/msg/Clock]
    /lidar/points [sensor_msgs/msg/PointCloud2]
    /oxts/fix [sensor_msgs/msg/NavSatFix]
    /oxts/imu [sensor_msgs/msg/Imu]
    /oxts/velocity [geometry_msgs/msg/TwistStamped]
    /parameter_events [rcl_interfaces/msg/ParameterEvent]
    /rosout [rcl_interfaces/msg/Log]
    /sim/episode [acres_interfaces/msg/Episode]
    /sim/ground_truth/odom [nav_msgs/msg/Odometry]
    /sim/reset [geometry_msgs/msg/PoseStamped]
    /tf [tf2_msgs/msg/TFMessage]
    /tf_static [tf2_msgs/msg/TFMessage]
    /vehicle/brake/cmd [ds_dbw_msgs/msg/BrakeCmd]
    /vehicle/brake/report [ds_dbw_msgs/msg/BrakeReport]
    /vehicle/dbw_enabled [std_msgs/msg/Bool]
    /vehicle/disable [std_msgs/msg/Empty]
    /vehicle/enable [std_msgs/msg/Empty]
    /vehicle/gear/cmd [ds_dbw_msgs/msg/GearCmd]
    /vehicle/gear/report [ds_dbw_msgs/msg/GearReport]
    /vehicle/odom [nav_msgs/msg/Odometry]
    /vehicle/steering/cmd [ds_dbw_msgs/msg/SteeringCmd]
    /vehicle/steering/report [ds_dbw_msgs/msg/SteeringReport]
    /vehicle/throttle/cmd [ds_dbw_msgs/msg/ThrottleCmd]
    /vehicle/throttle/report [ds_dbw_msgs/msg/ThrottleReport]
    /vehicle/ulc/cmd [ds_dbw_msgs/msg/UlcCmd]
    /vehicle/ulc/report [ds_dbw_msgs/msg/UlcReport]
    /vehicle/vehicle_velocity [ds_dbw_msgs/msg/VehicleVelocity]
    
  2. Read one message of the simulation clock.

    ros2 topic echo --once /clock
    

    Expected Result

    The time is the simulation time since the start of the game.

    clock:
      sec: 25
      nanosec: 741668009
    ---
    
  3. Read one message of the odometry.

    ros2 topic echo --once --no-arr /vehicle/odom
    

    Expected Result

    The position is in UTM zone 16N. The vehicle does not move.

    header:
      stamp:
        sec: 27
        nanosec: 250001421
      frame_id: utm
    child_frame_id: base_footprint
    pose:
      pose:
        position:
          x: 500438.12220755406
          y: 4479963.951710937
          z: 181.76825509173662
        orientation:
          x: -0.01584030324089254
          y: 0.009055761779796622
          z: 0.7071480518888165
          w: 0.7068300380638741
      covariance: '<array type: double[36]>'
    twist:
      twist:
        linear:
          x: -0.0066012713313529404
          y: 0.008960991459550805
          z: 0.0077292981674181305
        angular:
          x: 0.0009210506604661536
          y: 0.00010572694792926153
          z: 0.0006802870432511093
      covariance: '<array type: double[36]>'
    ---
    
  4. Measure the rate of a topic. Stop the command with Ctrl+C.

    ros2 topic hz /vehicle/odom
    

    Expected Result

    average rate: 99.943
    

    The other rates in the same session:

    Topic Rate
    /clock 120.1 Hz
    /vehicle/odom, /tf, /oxts/imu 99.9 Hz to 100.3 Hz
    /lidar/points 10.0 Hz
    /camera/image_raw, /camera/camera_info 9.9 Hz
    /vehicle/steering/report, /vehicle/gear/report, /vehicle/ulc/report 49.8 Hz to 50.2 Hz
  5. Read the episode clock. This topic keeps its last message, thus the command needs two QoS options.

    ros2 topic echo --once --qos-durability transient_local \
        --qos-reliability reliable /sim/episode
    

    Expected Result

    header:
      stamp:
        sec: 11
        nanosec: 708333944
      frame_id: ''
    episode_id: 20261002T072309-0000
    episode: 0
    reset_epoch: 0
    step: 1405
    episode_time_s: 11.708333943970501
    state: 1
    lockstep: false
    seed: 42
    source: unreal
    map: V03ACRE
    agents:
    - polaris
    ---
    

Send a Drive-by-Wire Command#

The Polaris starts in the gear L with the drive-by-wire off. A command has an effect only after you enable the drive-by-wire. The simulator stops a subsystem 0.1 s after its last command, as the real vehicle does. Thus you must send the command continuously.

WARNING

Make sure that the shell shows ROS_LOCALHOST_ONLY=1 when you source setup_env.sh. Do not send the commands of this section from a shell without the fence.

  1. Enable the drive-by-wire.

    ros2 topic pub --once /vehicle/enable std_msgs/msg/Empty "{}"
    ros2 topic echo --once /vehicle/dbw_enabled
    

    Expected Result

    publisher: beginning loop
    data: true
    ---
    
  2. Send a speed command of 1.5 m/s at 50 Hz for 10 s.

    ros2 topic pub -r 50 -t 500 /vehicle/ulc/cmd ds_dbw_msgs/msg/UlcCmd \
        "{cmd: 1.5, cmd_type: 1, enable: true}"
    

    Expected Result

    The Polaris moves to the north at 1.5 m/s. In a different shell, the ULC report shows the reference and the measured speed:

    ros2 topic echo --once /vehicle/ulc/report
    
    cmd_type: 1
    vel_ref: 1.5
    vel_meas: 1.5082000494003296
    accel_ref: 0.0
    accel_meas: 0.04100000113248825
    coast_decel: false
    ready: true
    enabled: true
    override_active: false
    

    After the last command, the vehicle stops and enabled becomes false in the ULC report.

  3. Disable the drive-by-wire.

    ros2 topic pub --once /vehicle/disable std_msgs/msg/Empty "{}"
    ros2 topic echo --once /vehicle/dbw_enabled
    

    Expected Result

    publisher: beginning loop
    data: false
    ---
    

The node dbw_demo_driver sends such commands along a route. Refer to Nodes and Launch Files.

Call Services#

  1. Read the simulation state.

    ros2 service call /get_simulation_state simulation_interfaces/srv/GetSimulationState
    

    Expected Result

    The state 1 is "playing". The result code 1 is "OK".

    response:
    simulation_interfaces.srv.GetSimulationState_Response(state=simulation_interfaces.msg.SimulationState(state=1), result=simulation_interfaces.msg.Result(result=1, error_message=''))
    
  2. Pause the simulation. The world stops, and the game continues to render.

    ros2 service call /set_simulation_state simulation_interfaces/srv/SetSimulationState \
        "{state: {state: 2}}"
    

    Expected Result

    response:
    simulation_interfaces.srv.SetSimulationState_Response(result=simulation_interfaces.msg.Result(result=1, error_message=''))
    
  3. Advance the simulation by 120 physics steps. This is 1 s of simulation time.

    ros2 service call /step_simulation simulation_interfaces/srv/StepSimulation "{steps: 120}"
    

    Expected Result

    The response arrives after the bridge published all sensor data of the 120 steps.

    response:
    simulation_interfaces.srv.StepSimulation_Response(result=simulation_interfaces.msg.Result(result=1, error_message=''))
    
  4. Let the simulation play again.

    ros2 service call /set_simulation_state simulation_interfaces/srv/SetSimulationState \
        "{state: {state: 1}}"
    
  5. Read the ground truth of field F48 from the farm.

    ros2 service call /acres/farm_state acres_interfaces/srv/FarmState \
        "{edge_band_m: 4.0, fields: [48]}"
    

    Expected Result

    response:
    acres_interfaces.srv.FarmState_Response(result=simulation_interfaces.msg.Result(result=1, error_message=''), header=std_msgs.msg.Header(stamp=builtin_interfaces.msg.Time(sec=176, nanosec=825009222), frame_id='world'), fields=[acres_interfaces.msg.FieldState(field=48, name='F48', crop='soybean', crop_area_m2=5098.080000000243, crushed_m2=0.0, crushed_in_band_m2=0.0, crushed_out_band_m2=0.0, harvested_m2=0.0, tilled_m2=0.0, seeded_m2=0.0, sprayed_m2=0.0, theta_mean=0.37230732510288195, pond_mean_m=0.0, rut_area_m2=0.0)], crushed_m2=0.0, harvested_kg=0.0)
    
  6. Stop the game from ROS 2. Then stop the bridge in shell 2 with Ctrl+C.

    ros2 service call /set_simulation_state simulation_interfaces/srv/SetSimulationState \
        "{state: {state: 3}}"
    

    Expected Result

    The game closes. The bridge writes these lines:

    [sim_bridge]: simulator control: disconnected from 127.0.0.1:5600
    [INFO] [sim_bridge-1]: process has finished cleanly [pid 3154363]
    

Repeat the Session with ACRES Core#

The executable core_sim runs the Polaris of ACRES Core behind the same three sockets. It needs no game and no GPU. The bridge and all commands of shell 3 are the same.

RViz 2 with the Polaris of ACRES Core and its ray-cast LiDAR cloud

  1. In shell 1, start ACRES Core.

    source ROS/Env/setup_env.sh
    ros2 run acres_core_sim core_sim
    

    Expected Result

    ACRES_CORE_SIM_READY agents=1 control=5600 lockstep=0 rate=1 world_load_s=0.52 utm_origin=500476.935,4480099.755 grid_rotation_deg=0.054092
    ACRES_CORE_SIM_AGENT name=polaris sensor_stream=5601 rl_port=5556 x=-38.710 y=-140.513 yaw_deg=90.00
    
  2. In shell 2, start the bridge with the same command as for the game.

    ros2 launch acres_sim sim_bridge.launch.py vehicle:=auto
    

    Expected Result

    ACRES Core has no camera:

    [sim_bridge]: connected to polaris (polaris): LiDAR 1800 x 32 at 10 Hz, camera None x None at 0 Hz, INS 100.0 Hz
    

    Note

    With the package purdue_ranger, one command starts the two programs: ros2 launch acres_core_sim core_sim.launch.py. Without the package, that launch file stops with the message about purdue_ranger.

  3. In shell 3, read the episode clock.

    ros2 topic echo --once --qos-durability transient_local \
        --qos-reliability reliable /sim/episode
    

    Expected Result

    The field source shows the simulator.

    episode_id: 20261002T070311-0000
    episode: 0
    reset_epoch: 0
    step: 0
    episode_time_s: 0.0
    state: 1
    lockstep: false
    seed: 42
    source: core
    map: V03ACRE
    agents:
    - polaris
    
  4. Do the steps of the sections "Read the Topics", "Send a Drive-by-Wire Command" and "Call Services" again.

    Expected Result

    The topic list, the services and the action are the same. The rates are 120 Hz, 100 Hz, 50 Hz and 10 Hz, as with the game. The differences are these:

    Item ACRES Core
    /camera/image_raw, /camera/camera_info The topics exist. No message arrives.
    /vehicle/odom After the start, the vehicle moves 24 m to the north in approximately 30 s without a command. Then it stops.
    /sim/episode source is core.
    The state 3 of /set_simulation_state It stops core_sim. The log of core_sim shows ACRES_SIM_CONTROL_QUIT.
  5. Stop core_sim with Ctrl+C and start it again at ten times real time.

    ros2 run acres_core_sim core_sim --rate 10
    

    Expected Result

    In shell 3, ros2 topic hz /clock shows average rate: 1200.065. ros2 topic hz /lidar/points shows average rate: 100.040. When you stop core_sim, it writes this line:

    ACRES_CORE_SIM_EXIT steps=25434 sim_s=211.950 wall_s=21.196 speedup=10.00 lidar_dropped=0
    

Next Steps#