Linux Environment Preparation
Efficient interaction with the operating system is critical for robotics development. Launch the terminal using Ctrl + Alt + T. Core navigation commands include:
cd ~ # Navigate to home directory
cd / # Access root directory
Use pwd to verify the current path, mkdir -p catkin_ws/src to prepare the workspace structure, and standard file operations like rm, mv, cp, or GUI editors (gedit).
Regarding programming languages, Python serves as an interpreted language requiring runtime execution:
python3 test.py
C++ requires compilation before execution:
g++ source.cpp
./a.out
ROS2 Architecture Overview
ROS2 provides a middleware framework essential for integrating perception, decision-making, and control in robotic systems.
System Layers:
- Perception: Processes data from LiDAR, depth cameras, IMU, odometry, collision sensors, and SLAM.
- Decision: Executes path planning algorithms and localization strategies.
- Control: Manages actuator drivers (e.g., wheel motors).
Key Differences: ROS2 vs ROS1
- OS Compatibility: Broadened platform support in ROS2.
- Middleware: Eliminated the central Master node; adopted DDS (Data Distribution Service) for decentralized communication.
- Application Layer: Supports newer Python versions, improved build systems, C++11 standards, and unified API for inter-process and intra-process communication.
Initial Verification Commands:
ros2 run demo_nodes_py listener
ros2 run demo_nodes_cpp talker
Launch simulation environments:
ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key
Utilize rqt for plugin visualization and debugging.
Node Management and Build System
Building nodes typically involves GCC, Make, or CMake-based workflows defined in CMakeLists.txt. Common errors involve missing references or path issues, often resolved by checking package dependencies.
Node Operations: Run a specific executable within a package:
ros2 run <package_name> <executable_name>
List active nodes:
ros2 node list
Inspect details of a specific node:
ros2 node info <node_name>
Rename a node at runtime:
ros2 run turtlesim turtlesim_node --ros-args --remap __node:=virtual_turtle
Set parameters during execution:
ros2 run example_parameters_rclcpp parameters_basic --ros-args -p rcl_log_level:=10
Package Discovery (ros2 pkg):
Commands like create, list, executables, and prefix assist in managing package structures.
Build Tooling (colcon):
Similar to catkin_make but designed for modern workspaces.
Standard build process:
colcon build
source install/setup.bash
Targeted build options:
colcon build --packages-select YOUR_PKG_NAME
Exclude tests for faster iteration:
colcon build --packages-select YOUR_PKG_NAME --cmake-args -DBUILD_TESTING=0
Run tests after building:
colcon test
Enable symbolic linking to allow editing source files without rebuilding binaries:
colcon build --symlink-install
C++ Node Implementation with RCLCPP
Adopt Object-Oriented Programming principles where an object combines state (properties) and behavier (methods). Key OOP concepts include encapsulation, inheritance, and polymorphism.
Workspace Setup:
mkdir -p ros2_ws/src
cd ros2_ws
ros2 pkg create my_control_pkg --build-type ament_cmake --dependencies rclcpp
Main Source File (src/main_node.cpp):
Create a class inheriting from rclcpp::Node.
#include "rclcpp/rclcpp.hpp"
class RobotController : public rclcpp::Node {
public:
RobotController(std::string name) : Node(name) {
RCLCPP_INFO(this->get_logger(), "Initializing controller module: %s", name.c_str());
}
};
int main(int argc, char *argv[]) {
rclcpp::init(argc, argv);
auto robot = std::make_shared<RobotController>("base_ctrl");
rclcpp::spin(robot);
rclcpp::shutdown();
return 0;
}
Compilation Configuration (CMakeLists.txt):
Ensure strict warning flags and correct dependency finding.
cmake_minimum_required(VERSION 3.8)
project(my_control_pkg)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
add_executable(controller src/main_node.cpp)
ament_target_dependencies(controller rclcpp)
install(TARGETS controller DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
set(ament_cmake_copyright_FOUND TRUE)
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
Pub/Sub Communication Patterns
Explore topic management via CLI tools:
rqt_graph # Visualize node topology
ros2 topic list # List active topics
ros2 topic echo /topic_name # Stream real-time message data
ros2 interface show # Inspect message definitions
Publish test messages:
ros2 topic pub /test_topic std_msgs/msg/String 'data: "Hello World"'
Publisher Implementation (src/pub_node.cpp):
Using wall timers to publish periodically.
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class CommandSender : public rclcpp::Node {
public:
CommandSender() : Node("sender_node") {
RCLCPP_INFO(this->get_logger(), "Command Sender Started");
publisher_ = this->create_publisher<std_msgs::msg::String>("teleop_cmd", 10);
timer_ = this->create_wall_timer(
std::chrono::milliseconds(500),
std::bind(&CommandSender::on_timer, this));
}
private:
void on_timer() {
std_msgs::msg::String msg;
msg.data = "execute_move";
RCLCPP_INFO(this->get_logger(), "Broadcasting: %s", msg.data.c_str());
publisher_->publish(msg);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
};
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<CommandSender>());
rclcpp::shutdown();
return 0;
}
Subscriber Implementation (src/sub_node.cpp):
Listening for incoming messages and processing logic.
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class StatusReceiver : public rclcpp::Node {
public:
StatusReceiver() : Node("receiver_node") {
RCLCPP_INFO(this->get_logger(), "Status Receiver Active");
subscription_ = this->create_subscription<std_msgs::msg::String>(
"teleop_cmd", 10,
std::bind(&StatusReceiver::callback, this, std::placeholders::_1));
}
private:
void callback(const std_msgs::msg::String::SharedPtr msg) {
double limit_speed = 0.2f;
if (msg->data == "execute_move") {
RCLCPP_INFO(this->get_logger(), "Received command: %s -> Speed %.2f",
msg->data.c_str(), limit_speed);
}
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<StatusReceiver>());
rclcpp::shutdown();
return 0;
}
Dependencies (CMakeLists.txt):
Define both executables and required packages (std_msgs).
# ... (header content remains similar)
add_executable(publisher src/pub_node.cpp)
ament_target_dependencies(publisher rclcpp std_msgs)
add_executable(subscriber src/sub_node.cpp)
ament_target_dependencies(subscriber rclcpp std_msgs)
install(TARGETS publisher subscriber DESTINATION lib/${PROJECT_NAME})
# ... (footer content remains similar)
Manifest File (package.xml):
Ensure all dependencies are declared, including generators for interfaces if needed later.
<?xml version="1.0"?>
<package format="3">
<name>topic_demo</name>
<version>0.0.0</version>
<description>Demonstrates pub/sub patterns</description>
<maintainer email="dev@example.com">Developer</maintainer>
<license>Apache-2.0</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rclcpp</depend>
<depend>std_msgs</depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
Interface Definition
Interfaces define the data structure exchanged between components. Support includes basic types (bool, int32, float64, string) and complex types (arrays, custom messages).
Interface Types:
- Topics:
.msgfiles for asynchronous streaming data. Example:int64 counter - Services:
.srvfiles for request-response interaction. Example:int64 request_val --- int64 response_val - Actions:
.actionfiles for long-running tasks with feedback and goals. Example:int32 order_id --- int32[] progress --- int32 result_code
Custom Interface Generation:
To extend the system, generate interfaces using rosidl_default_generators.
- Create package:
ros2 pkg create nav_interfaces --build-type ament_cmake --dependencies rosidl_default_generators geometry_msgs - Modify
CMakeLists.txtto include generation logic:find_package(rosidl_default_generators REQUIRED) find_package(geometry_msgs REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} "msg/RobotPose.msg" "msg/RobotStatus.msg" "srv/NavigateCmd.srv" DEPENDENCIES geometry_msgs ) - Update
package.xml:<member_of_group>rosidl_interface_packages</member_of_group>
Navigation 2 Stack
Nav2 utilizes Behavior Trees (BT) to orchestrate complex navigation behaviors such as mapping, planning, and recovery.
Key Server Modules:
- Planner Server: Calculates the optimal global trajectory (CP operation).
- Controller Server: Handles local path following and obstacle avoidance (FP operation).
- Recovery Server: Manages states where the robot is stuck or error conditions occur.
The BT manager coordinates these servers. Upon receiving a target pose, the Planner calculates the route, and the Controller guides the robot along it. If an obstruction causes the robot to stop moving, the Recovery server intervenes to restore motion. This modular approach ensures robust autonomy capabilities.
Tags for Future Reference
LinuxTerminalC++ColconDDSNav2
Note: Ensure environment variables are sourced correctly before running any ROS2 commands.