Skip to content

Latest commit

 

History

History
627 lines (503 loc) · 18.8 KB

File metadata and controls

627 lines (503 loc) · 18.8 KB

AGENTS.md - ROV ROS2 Workspace

This document provides essential information for agents working in this ROS2 workspace for ROV (Remotely Operated Vehicle) control and simulation.

Project Overview

  • Type: ROS2 workspace (Humble distribution)
  • Target: Remotely Operated Vehicle (ROV) control system
  • Domain: Underwater robotics simulation and control
  • Architecture: Distributed control system with simulation, trajectory generation, localization, and autonomy components

Essential Commands

Building

# Build the entire workspace
colcon build --symlink-install

# Build specific package
colcon build --symlink-install --packages-select <package_name>

# Build with diagnostics
colcon build --symlink-install --event-handlers console_direct+

Sourcing

# Source ROS2 (run this first)
source /opt/ros/humble/setup.bash

# Source workspace (after building)
source /home/dev/ros2_ws/install/setup.bash

# Both are automatically sourced in .bashrc

Running Nodes

# Run a specific node
ros2 run <package> <executable>

# Run with verbose logging
ros2 run <package> <executable> --ros-args --log-level debug

# Examples:
ros2 run rov_pid rov_pid_node
ros2 run traj_gen min_snap_traj_generator

Launching Systems

# Launch a system using Python launch files
ros2 launch <package> <launch_file.py>

# Example:
ros2 launch rov_pid pid.launch.py
ros2 launch rov_stonefish sea_bluerov2_nogpu.launch.py

Testing

# Run all tests
colcon test

# Run specific package tests
colcon test --packages-select <package_name>

# View test results
colcon test --packages-select <package_name> --event-handlers console_direct+

# Run pytest directly (from package directory)
pytest test/

Linting

# Run flake8
flake8 <file_or_directory>

# Run ament linting (ROS2 style)
ament_flake8 <directory>
ament_pep257 <directory>
ament_copyright <directory>

# Use .flake8 configuration (max line length: 125, ignore W191)

Code Organization

Workspace Structure

ros2_ws/
├── src/                          # All packages
│   ├── control_system/             # Control algorithms (PID, MFSMC, thruster management)
│   ├── controlers/                # Controller drivers (DS4)
│   ├── trajectory/                # Trajectory generation and waypoint management
│   ├── simulation/                # Physics simulation (Stonefish)
│   ├── localization/              # State estimation and sensor fusion
│   ├── autonomy_system/           # High-level autonomy and behavior trees
│   ├── autonomy_system_interfaces/  # Custom messages and actions
│   ├── mechanical/               # Robot description and hardware interface
│   └── utils/                   # Utilities (diagnostics, ros2_numpy)
├── build/                       # Generated by colcon
├── install/                     # Installation directory
└── log/                        # Build logs

Package Structure

Python Packages (ament_python):

<package>/
├── package.xml                   # Package metadata and dependencies
├── setup.cfg                    # Installation configuration (script_dir, install_scripts)
├── setup.py                     # setuptools configuration with entry_points
├── <package>/                   # Python module directory
│   ├── __init__.py              # Empty module file
│   └── <module>.py             # Implementation code
├── nodes/                       # Node entry points (main functions)
│   └── <node_name>.py
├── config/                      # YAML configuration files
│   └── params.yaml
├── launch/                     # Python launch files
│   └── <launch_file>.py
├── test/                       # Tests
│   ├── test_copyright.py       # Copyright linting
│   ├── test_flake8.py         # Python style linting
│   └── test_pep257.py        # Docstring linting
├── rviz/                       # RViz configuration files
│   └── <config>.rviz
└── resource/                    # Package resource marker
    └── <package>

C++ Packages (ament_cmake):

<package>/
├── CMakeLists.txt              # CMake build configuration
├── package.xml                # Package metadata
├── include/<package>/         # Header files
├── src/                      # Source files
├── msg/                      # Custom message definitions
├── srv/                      # Custom service definitions
└── launch/                   # Launch files

Key Packages

  • rov_pid: PID control for ROV
  • rov_thruster_manager: Thruster allocation matrix management
  • rov_passthrough_control: Joystick-to-wrench conversion
  • traj_gen: Trajectory generation (minimum snap, analytical)
  • rov_position_snapshot: Waypoint recording from DS4 controller
  • rov_description: URDF/xacro robot description
  • rov_bridge: Hardware interface (STM32 communication)
  • rov_stonefish: Stonefish simulation scenarios and configurations
  • stonefish_ros2: Stonefish simulation interface (C++)
  • robot_localization: EKF/UKF state estimation
  • autonomy_system: Behavior tree-based autonomy using py_trees
  • rov_ds4_driver: DS4 controller driver
  • diagnostic_updater, diagnostic_aggregator: ROS diagnostics

Naming Conventions

Packages

  • Format: Lowercase with underscores
  • Examples: rov_pid, traj_gen, rov_thruster_manager, rov_passthrough_control
  • Pattern: rov_<component> for ROV-specific packages

Nodes

  • Python Classes: PascalCase (e.g., PositionSnapshot, ThrusterManager, PassthroughControl)
  • Node Names: lowercase with underscores (e.g., rov_position_snapshot, rov_pid_node, thruster_manager)
  • Entry Points: lowercase with underscores (matching node names)

Topics

  • Format: Hierarchical with underscores
  • Examples:
    • /bluerov2/odometry
    • /joy_wrench_stmp
    • /calculated_wrench
    • /target_pose, /target_twist, /target_accel
    • /traj_gen/waypoints
  • Prefixes: /bluerov2/ for robot-specific topics

Parameters

  • Format: snake_case
  • Examples:
    • thruster_prefix
    • output_type
    • sub_input_wrench_topic_name
    • max_force, max_torque

Coordinate Frames

  • World Frame: world_ned (North-East-Down coordinate system)
  • Robot Frame: base_link
  • Sensor Frames: bluerov2/imu_filter, bluerov2/multibeam, bluerov2/fls
  • Trajectory Frame: traj_gen (for trajectory generation reference)

Code Style and Patterns

Python Style

  • Line Length: Maximum 125 characters (configured in .flake8)
  • Indentation: 4 spaces (configured to ignore W191/tabs in .flake8)
  • Linting: flake8, ament_pep257 (docstrings), ament_copyright

Node Pattern

Most Python nodes follow this structure:

import rclpy
from rclpy.node import Node
from <package> import <Class>

def main():
    rclpy.init()
    node = <Class>()  # Class inherits from Node
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == "__main__":
    main()

Parameter Handling Pattern

# Declare and retrieve parameters
self.declare_parameter('param_name', default_value)
param_value = self.get_parameter('param_name').value

# For parameters with type specification
param_value = self.get_parameter('param_name').get_parameter_value().string_value

Node Initialization Pattern

class MyNode(Node):
    def __init__(self):
        Node.__init__(self=self, node_name='my_node_name')  # Explicit parent init

        # Declare parameters
        self.declare_parameter('param', default)

        # Create publishers/subscribers
        self.pub = self.create_publisher(MsgType, 'topic', qos_profile)
        self.sub = self.create_subscription(MsgType, 'topic', callback, qos_profile)

        # Timer-based operations
        self.create_timer(period, self.callback)

Launch File Pattern

from launch_ros.actions import Node
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription, TimerAction, DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
from ament_index_python import get_package_share_directory

def generate_launch_description():
    # Declare arguments
    config_arg = DeclareLaunchArgument(name="config", default_value=default_path)

    # Define nodes
    my_node = Node(
        package='my_package',
        executable='my_executable',
        parameters=[LaunchConfiguration('config')],
        output='screen'
    )

    # Use TimerAction for delayed startup
    node_timer = TimerAction(period=1.0, actions=[my_node])

    return LaunchDescription([
        config_arg,
        node_timer
    ])

Testing

Test Structure

Each Python package has three standard tests in test/:

  • test_copyright.py: Validates Apache 2.0 license headers (many skip with @pytest.mark.skip)
  • test_flake8.py: Validates Python code style
  • test_pep257.py: Validates docstring format

Running Tests

# All tests in workspace
colcon test

# Specific package
colcon test --packages-select rov_pid

# With verbose output
colcon test --packages-select rov_pid --event-handlers console_direct+

# Direct pytest
cd src/<package>
pytest test/

CI/CD Testing

GitHub Actions workflows in src/utils/diagnostics/.github/workflows/:

  • test.yaml: Builds and tests on ROS2 Rolling
  • lint.yaml: Runs cppcheck, cpplint, flake8, uncrustify, xmllint

Launch System

Python Launch Files

All launch files use Python format (.launch.py) with launch_ros actions.

TimerAction Usage

Common pattern for sequential node startup:

# Delay rov_state_publisher by 1 second
description_timer = TimerAction(period=1.0, actions=[rov_state_publisher_node])

# Delay stonefish simulator by 2 seconds
stonefish_timer = TimerAction(period=2.0, actions=[launch_include])

# Delay trajectory generator by 4 seconds
traj_gen_timer = TimerAction(period=4.0, actions=[traj_gen_node, tf_traj_gen])

Parameter Passing

# Pass config file to nodes
my_node = Node(
    package='my_package',
    executable='my_executable',
    parameters=[LaunchConfiguration('config')]
)

# Pass parameters from another launch
passthrough_launch = IncludeLaunchDescription(
    launch_description_source=PathJoinSubstitution([share, 'launch', 'base.launch.py']),
    launch_arguments={
        "config": LaunchConfiguration('config')
    }.items()
)

Configuration Management

YAML Parameter Files

Located in config/ directories within packages. Structure:

<node_name>:
  ros__parameters:
    param1: value
    param2: value

# Example from rov_pid/config/params.yaml
rov_state_publisher:
  ros__parameters:
    robot_name: bluerov2

rov_thruster_manager:
  ros__parameters:
    thruster_prefix: t200
    output_type: 'STONEFISH'
    thruster_voltage: 20

Key Configuration Areas

Thruster Manager Output Types:

  • PWM: Single topic with PWM values
  • RPM: Single topic with RPM values
  • FRC: Single topic with force values
  • SEP_PWM, SEP_RPM, SEP_FRC: Individual topics per thruster
  • STONEFISH: Normalized values for Stonefish simulation

Trajectory Generator:

  • use_traj_from_file: Load trajectory from JSON file
  • traj_file: JSON filename containing trajectory data

Passthrough Control:

  • controller: Input device type (ds4, joy, station)
  • max_force, max_torque: Force/torque limits
  • equalization_type: Linearization function (LINEAR, SQUARE, CUBE, INV_SQUARE, INV_CUBE)

Coordinate Systems

Frames

  • world_ned: Global NED (North-East-Down) reference frame
  • base_link: Robot body frame
  • odom: Odometry frame (local navigation)
  • map: Global map frame (for absolute positioning)

Transform Tree

world_ned (or map)
  └── base_link
      └── bluerov2/imu_filter
      └── bluerov2/multibeam
      └── bluerov2/fls
      └── t200_<N> (thrusters)

Static Transforms

Use tf2_ros static transform publisher:

ros2 run tf2_ros static_transform_publisher x y z yaw pitch roll parent_frame child_frame

In launch files:

Node(
    package='tf2_ros',
    executable='static_transform_publisher',
    arguments=["0", "0", "0", "0", "0", "0", "world_ned", "traj_gen"]
)

Key Patterns and Gotchas

Package Installation

  • Python packages use setup.cfg with script_dir=$base/lib/<package>
  • setup.py defines entry_points for console scripts
  • Use colcon build --symlink-install for faster development

Thruster Allocation

  • Thruster allocation matrix (TAM) requires exactly 6 thrusters
  • Thruster discovery uses tf_static topic with child frame prefix
  • Order of thrusters is sorted alphabetically

Trajectory Generation

  • Supports two types: Analytical (pre-defined shapes) and Minimum Snap (waypoint-based)
  • Minimum snap uses 7th-order polynomials
  • Outputs derivatives up to snap: pose, twist, accel, jerk, snap

Behavior Trees (Autonomy)

  • Uses py_trees and py_trees_ros libraries
  • Actions defined in autonomy_system_interfaces/action/
  • ActionBehaviour class wraps ROS2 actions as behavior tree nodes
  • Multi-threaded executor for concurrent action handling

Robot Localization

  • Uses robot_localization package (EKF/UKF)
  • Configuration in YAML with detailed sensor fusion options
  • Supports multiple odom, pose, twist, and IMU inputs
  • Parameters include odom0_config, imu0_config, etc. for sensor fusion

Simulation

  • Stonefish physics engine for underwater simulation
  • Two modes: GPU-accelerated and no-GPU
  • Scenarios defined in .scn files
  • DVL (Doppler Velocity Log) simulation for underwater velocity measurement

DS4 Controller

  • Uses ds4drv Python package for DualShock 4
  • Provides Status message with button and axis states
  • Button/axis mapping configurable in YAML
  • Example axes: axis_left_y, axis_left_x, axis_right_y, axis_right_x

Position Snapshot

  • Records waypoints by pressing DS4 buttons
  • Saves to JSON in output/ directory
  • Uses transforms between world_ned and base_link
  • Timestamping for time-ratio based trajectory generation

Development Environment

DevContainer

  • Uses ros:humble-desktop-full base image
  • NVIDIA GPU support enabled
  • Stonefish library pre-installed
  • ROS2 aliases sourced from /home/dev/ros2-aliases/ros2_aliases.bash

Dependencies

ROS2 Packages:

  • ros-humble-joint-state-publisher
  • ros-humble-tf-transformations
  • ros-humble-imu-tools
  • ros-humble-plotjuggler-ros
  • ros-humble-py-trees
  • ros-humble-py-trees-ros

Python Packages:

  • ds4drv: DS4 controller driver
  • osqp: Quadratic programming solver
  • casadi: Optimization framework
  • numpy, ros2_numpy: Numerical computing

Simulation:

  • Stonefish 1.3.0+ (installed from AGH-Marines fork)

Build Configuration

  • Default: colcon build --symlink-install
  • ROS_DISTRO: humble
  • RMW_IMPLEMENTATION: rmw_fastrtps_cpp

Common Workflows

Adding a New Python Package

  1. Create package structure
  2. Write package.xml with dependencies
  3. Write setup.cfg with script directories
  4. Write setup.py with entry_points
  5. Add standard tests: test_copyright.py, test_flake8.py, test_pep257.py
  6. Build: colcon build --symlink-install
  7. Test: colcon test

Adding a New Node

  1. Create node file in nodes/ or module directory
  2. Inherit from rclpy.node.Node
  3. Follow node pattern: __init__, main, if __name__
  4. Add entry point in setup.py:
    entry_points={
        'console_scripts': [
            'node_name = package.module:main'
        ]
    }
  5. Rebuild and test

Adding a New Launch File

  1. Create .launch.py in launch/ directory
  2. Import necessary launch components
  3. Define nodes with Node() action
  4. Use TimerAction for startup delays if needed
  5. Add DeclareLaunchArgument for configurable parameters
  6. Return LaunchDescription with all actions

Modifying Robot Description

  1. Edit .urdf.xacro files in rov_description/xacro/
  2. Rebuild workspace
  3. Verify with ros2 run rov_description rov_state_publisher
  4. Check in RViz2 with provided configuration

Important Gotchas

  1. Python Path: PYTHONPATH is set to include src: in devcontainer, but after building, use workspace setup
  2. Copyright Headers: Many files skip copyright test with @pytest.mark.skip - this is intentional during development
  3. Thruster Discovery: Thruster manager waits for tf_static - ensure robot state publisher is running
  4. Simulation Timing: Stonefish requires sufficient startup time - use TimerAction delays in launch files
  5. Parameter Updates: Changing parameters requires node restart (no dynamic reconfigure in most nodes)
  6. Coordinate Frames: NED (North-East-Down) is standard - z-axis points DOWN
  7. Stonefish Integration: Requires specific output_type ('STONEFISH') for thruster manager
  8. Waypoint Recording: Position snapshot uses DS4 button presses - ensure controller is connected
  9. Test Dependencies: Some tests require ROS2 bag files in test/ directory (robot_localization)
  10. Git Submodules: Project uses git submodules (see .gitmodules)

Visualization Tools

RViz2

  • Configuration files in rviz/ directories
  • Launch with: rviz2 -d <config_file>
  • Common topics to visualize:
    • /tf: Transform tree
    • /traj_gen/path: Trajectory path
    • /traj_gen/waypoints: Waypoints for RViz
    • /bluerov2/odometry: Robot position

PlotJuggler

  • Layouts in plotjuggler_layouts/ directories
  • Useful for visualizing trajectory derivatives
  • Load with PlotJuggler application

Troubleshooting

Build Issues

# Clean build
rm -rf build install log
colcon build --symlink-install

Import Errors

# Ensure workspace is sourced
source /home/dev/ros2_ws/install/setup.bash

# Check PYTHONPATH
echo $PYTHONPATH

Runtime Errors

# Check node status
ros2 node list
ros2 topic list
ros2 topic echo /topic_name

# Check parameters
ros2 param list /node_name
ros2 param get /node_name /parameter_name

TF Issues

# View transform tree
ros2 run tf2_tools view_frames

# Check transform
ros2 run tf2_ros tf2_echo source_frame target_frame

File Extensions and Formats

  • .launch.py: Python launch files
  • .yaml: ROS2 parameter files
  • .urdf.xacro: Robot description files (Xacro macro format)
  • .rviz: RViz2 configuration files
  • .scn: Stonefish simulation scenarios
  • .obj, .dae: 3D mesh files
  • .msg: ROS2 message definitions
  • .srv: ROS2 service definitions
  • .action: ROS2 action definitions

Additional suggestions

NEVER add new markdown files with changes status, instead you can update README.md file after asking for permission