Skip to content

Vehicle Node#

The ROS 2 package ROS/acres_vehicle has the node vehicle_node: the vehicle program in C++. The node connects the topics of the Polaris to the run-time library. It has no numerical code. The pose, the scan, the inputs and the control step come from the vehicle handle.

In the simulator, the node drives the Polaris of ACRES Core over ROS 2 (Closed Loop with ACRES Core).

Part Location
Messages to inputs, and the control step include/acres_vehicle/VehicleProgram.h, src/VehicleProgram.cpp
Node, modes, record and commands src/vehicle_node.cpp
Launch files launch/vehicle.launch.py, launch/sim_drive.launch.py
Tests test/test_vehicle_node.py, test/test_drive_rules.py, test/test_gear_rules.py, test/test_skills.py, test/test_proposal.py
Tools scripts/shadow_compare.py, scripts/skill_client.py

Build#

  1. Build the run-time library: Runtime/build.sh.
  2. Open a shell of the fenced ROS 2 environment:

    source ROS/Env/setup_env.sh
    
  3. Build the package:

    colcon build --base-paths ROS/acres_vehicle --cmake-args -DACRES_RUNTIME_BUILD=<folder of libacres_runtime.so>
    

The package needs the message packages ds_dbw_msgs and oxts_msgs. The workspace has them in ROS/vendor. The page Build the ROS 2 Workspace has the full workspace.

Topics#

The node reads these topics with best-effort quality of service:

Topic Type Use
/oxts/ncom oxts_msgs/Ncom The packets of the pose selector
/vehicle/odom nav_msgs/Odometry The pose for the pose sources odom and auto
/lidar/points sensor_msgs/PointCloud2 The scan of the parameter real_scan
/oxts/fix sensor_msgs/NavSatFix The RTK quality for the pose source odom
/vehicle/steering/report, /vehicle/gear/report, /vehicle/wheel_speeds, /vehicle/vehicle_velocity ds_dbw_msgs/* The steering-wheel angle, the gear, the wheel speeds and the speed
/vehicle/dbw_enabled, /safety_stop std_msgs/Bool The drive-by-wire state and the finding safety_stop
/acres_vehicle/proposal std_msgs/Float64MultiArray The model hook
Output Content
/acres_vehicle/status (std_msgs/String) One JSON text for each control step: the mode, the state, the commands, the findings, the stops and the checker state
/acres_vehicle/verdicts (std_msgs/String) The verdicts of the library for a proposal
/vehicle/steering/cmd, /vehicle/ulc/cmd, /vehicle/gear/cmd The commands. DRIVE only. The gear command needs gear:=node.
records.jsonl, events.log, result.json, commands.csv The record of each control step, the events, the result, and each command sent

The service /acres_vehicle/stop (std_srvs/Trigger) stops the run.

Parameters#

Parameter Default Function
mission home F56, F53,F12 or home
drive false true arms DRIVE: the node sends commands
pose_source oxts oxts, odom or auto
limits first_test first_test, reverse_test or kturn_test (both need gear:=node), or simulator
gear driver driver: no gear publisher. node: the node shifts the gear (Gear by Wire).
real_scan config config, level_rings or height_band (Scan of a Vehicle)
speed_cap_mps, lateral_accel_cap_mps2, area_radius_m 0 A cap tighter than the limits file. 0 uses the file value.
tables Empty The cost-table file. Without it only home can start. Tables of a different map are refused.
root, map The repository, the default map The repository folder, and a map name or folder (Map Data)
out ~/acres_vehicle/<time>_<mission>_<mode> The folder of the record
bag Empty A recording. The node reads it in the recorded order. SHADOW only.
skills, first_skill, first_skill_args false, empty The node is the skill server, and the skill that it asks for at its start
on_cancel, client_timeout_s hold, 1.0 What a cancelled goal or a lost client gives, and the heartbeat timeout
stop_on, stall_s, off_path_m, max_run_s empty, -1, 3, 0 Findings that stop the run, and the limits of the findings stall, off_path and time
threads, propose_wall_s, exit_at_end 1, 0.02, true The pool size, the wall time of a proposal check, and the stop at the end of the run

Modes#

SHADOW is the default. The node has no publisher on a command topic.

  1. The node waits for a pose and for the first message of /lidar/points.
  2. The library plans the mission from the pose. A refused mission ends the run with the code and the sentence.
  3. A timer makes one control step every 0.1 s.
  4. A finding that stops the run is written as "would stop" in events.log. The run continues.
  5. The run ends when the mission is complete and the vehicle stands, or at Ctrl-C.

DRIVE needs drive:=true. The node then sends commands:

  • SteeringCmd in curvature mode, inside 0.2 1/m, and UlcCmd in velocity mode, not above the speed cap.
  • No command before /vehicle/dbw_enabled is true. The node never enables the drive-by-wire.
  • The last command is sent again at 50 Hz.
  • A lost pose, lost reports or a stop finding give the safe stop: ULC 0 m/s with the last curvature, then one release message.
  • When the drive-by-wire goes off, the node sends one release message and then nothing.
  • Ctrl-C gives the safe stop. A second Ctrl-C stops the commands. A third Ctrl-C ends the process.

Gear by Wire#

With gear:=node in DRIVE, the node publishes /vehicle/gear/cmd and the library gets allow_gear.

  • A gear command is REVERSE or the forward gear, never PARK or NEUTRAL.
  • The node sends a gear command only when the vehicle stands (0.1 m/s).
  • The node waits for the report to show the gear before it sends a speed in the new direction.
  • A reject, a fault or no report within gear.shift_timeout_s (4 s) gives the safe stop.
  • forward_gear (auto, drive or low) and reverse_speed_sign (negative or positive) set the forward gear and the sign of a backward speed.

Model Hook#

A process sends a proposal on /acres_vehicle/proposal. The values are in this order:

  1. The number of chunks.
  2. For each chunk: n, dt_s, station0_m, step_m, t0_s, deadline_s, then n offsets and n speeds.

The chunks are in the order of preference. In the next control step, the library checks each chunk. The first accepted chunk is the proposal of the chain. The node publishes the verdicts on /acres_vehicle/verdicts.

The node loads the checker plug-in libacres_runtime_lean.so from the library folder. The variable ACRES_RUNTIME_LEAN_PLUGIN names a different file. Without the plug-in, each verdict is "no checker" and the default chain drives.

Skills#

With skills:=true, a planner drives the vehicle through skills. The ROS 2 link of the harness is a client of the node (Harness: The Link).

Name Type Content
/acres/skill Action acres_interfaces/action/Skill The goal has the skill and its arguments. The result has the code, the cause and the observation.
/acres/observation std_msgs/String The document acres-observation-1 after each control step
/acres/events std_msgs/String, latched Each document acres-event-1
/acres/clock std_msgs/String The document acres-clock-1
/acres/skill/heartbeat std_msgs/Empty, from the client One message every 0.5 s or faster
python3 ROS/acres_vehicle/scripts/skill_client.py scout field=F56
python3 ROS/acres_vehicle/scripts/skill_client.py return_home

The script sends one skill, prints the events and the result, and sends the heartbeat. A client with no heartbeat loses each skill after client_timeout_s.

  • In SHADOW, the node plans and tracks the skill but sends nothing.
  • In DRIVE, the command between two skills, in a wait and in a stop, is ULC 0 m/s with the last curvature.
  • A cancelled goal or a lost client gives the skill stop (on_cancel:=hold), or the safe stop and the end of the run (release).
  • The node plans a skill in a separate thread. The control loop keeps its period during the plan.

Closed Loop with ACRES Core#

The launch file launch/sim_drive.launch.py starts four programs on loopback:

Program Package Function
core_sim acres_core_sim ACRES Core in real time: the Polaris, its sensors with noise, the ray-cast LiDAR and the drive-by-wire
sim_bridge acres_sim The ROS 2 topics of the Polaris from core_sim, and the commands to it
lab_stubs acres_sim The stand-in of the safety driver: it enables the drive-by-wire and puts the gear lever in L
vehicle_node acres_vehicle The node, with the pose source odom and the limits simulator
ros2 launch acres_vehicle sim_drive.launch.py tables:=<cost tables>/dry.npz mission:=F56 drive:=true
  • The pose source is odom: /vehicle/odom with the quality of /oxts/fix. The simulator has no /oxts/ncom packets.
  • The scan is the ray-cast LiDAR cloud through the switch real_scan.
  • The run is in real time only. The node reads the steady clock for its steps and for the age of each message.
  • spawn:=enu:<east>:<north>:<yaw in degrees> starts the vehicle at a pose. The mission home needs a lane within 25 m that runs along the heading.
  • core_sim has no contact topic and no objects. Use a skill world for objects on the path.

To compare two records of the node, run:

python3 ROS/acres_vehicle/scripts/shadow_compare.py <new>/records.jsonl <reference>/records.jsonl

Limits#

  • The node has no contact input. It finds a contact only as the stop finding stall.
  • The closed loop uses the pose source odom. The pose sources oxts and auto need NCOM packets.
  • The node has no keyboard input. Stop it with Ctrl-C or the service /acres_vehicle/stop.
  • The crop mask of the Scout phase is not in the node.