├── .gitignore ├── action_py ├── resource │ └── action_py ├── action_py │ ├── __init__.py │ ├── fibonacci_server.py │ └── fibonacci_client.py ├── setup.cfg ├── launch │ └── fibonacci_launch.py ├── package.xml ├── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py └── setup.py ├── pubsub_py ├── resource │ └── pubsub_py ├── pubsub_py │ ├── __init__.py │ ├── subscriber.py │ ├── publisher.py │ ├── sub_diy_msg.py │ ├── sub_hello_qos.py │ ├── pub_diy_msg.py │ └── pub_hello_qos.py ├── setup.cfg ├── launch │ ├── pubsub_py_launch.py │ ├── pubsub_diy_msg_launch.py │ └── pubsub_qos_launch.py ├── package.xml ├── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py └── setup.py ├── service_py ├── resource │ └── service_py ├── service_py │ ├── __init__.py │ ├── server.py │ ├── server_diy.py │ ├── client_diy.py │ └── client.py ├── setup.cfg ├── launch │ ├── service_py_launch.py │ └── service_diy_launch.py ├── package.xml ├── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py └── setup.py ├── webots_demo ├── resource │ ├── webots_demo │ └── mbot.urdf ├── webots_demo │ ├── __init__.py │ ├── obstacle_avoider.py │ └── mbot_driver.py ├── setup.cfg ├── package.xml ├── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py ├── setup.py ├── launch │ └── mbot_launch.py └── worlds │ └── my_world.wbt ├── hello_ros2_py ├── resource │ └── hello_ros2_py ├── hello_ros2_py │ ├── __init__.py │ └── hello_ros2.py ├── setup.cfg ├── package.xml ├── setup.py └── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py ├── launch_example ├── resource │ └── launch_example ├── setup.cfg ├── config │ └── turtlesim_param.yaml ├── package.xml ├── launch_example │ ├── turtlesim_world_2_launch.py │ ├── main_simple_launch.py │ ├── turtlesim_mimic_launch.py │ └── substitution_launch.py ├── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py └── setup.py ├── parameters_py ├── resource │ └── parameters_py ├── parameters_py │ ├── __init__.py │ ├── param_monitor.py │ └── param_test.py ├── setup.cfg ├── launch │ ├── param_monitor_launch.py │ └── param_test_launch.py ├── package.xml ├── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py └── setup.py ├── learning_tf2_py ├── learning_tf2_py │ ├── __init__.py │ ├── turtle_tf2_broadcaster.py │ └── turtle_tf2_listener.py ├── resource │ └── learning_tf2_py ├── setup.cfg ├── package.xml ├── test │ ├── test_pep257.py │ ├── test_flake8.py │ └── test_copyright.py ├── setup.py └── launch │ └── turtle_tf2_demo_launch.py ├── diy_interface ├── msg │ ├── Student.msg │ └── Sphere.msg ├── srv │ └── QuestionAndAnswer.srv ├── action │ └── Fibonacci.action ├── CMakeLists.txt └── package.xml ├── service_mix ├── srv │ └── Circle.srv ├── launch │ └── service_mix_launch.py ├── package.xml ├── src │ └── server.cpp ├── CMakeLists.txt └── scripts │ └── client.py ├── README.md ├── learning_tf2_cpp ├── doc │ ├── turtle_tf.pdf │ └── turtle_tf.gv ├── package.xml ├── include │ └── learning_tf2_cpp │ │ ├── turtle_tf_broadcaster.hpp │ │ ├── turtle_tf_listener.hpp │ │ └── visibility_control.h ├── CMakeLists.txt ├── src │ ├── turtle_tf_broadcaster.cpp │ └── turtle_tf_listener.cpp └── launch │ └── turtle_tf2_demo_launch.py ├── pubsub_mix ├── msg │ └── AddressBook.msg ├── launch │ └── pubsub_mix_launch.py ├── scripts │ └── subscribe_address_book.py ├── package.xml ├── CMakeLists.txt └── src │ └── publish_address_book.cpp ├── gazebo_mbot_go_maze ├── worlds │ └── maze_room │ │ └── model.config ├── CMakeLists.txt ├── package.xml ├── urdf │ └── sensor │ │ ├── laser.xacro │ │ └── camera.xacro └── launch │ └── mbot_gazebo_launch.py ├── polygon_base ├── launch │ └── area_launch.py ├── package.xml ├── include │ └── polygon_base │ │ └── regular_polygon.hpp ├── CMakeLists.txt └── src │ └── area_node.cpp ├── polygon_plugins ├── plugins.xml ├── package.xml ├── CMakeLists.txt └── src │ └── polygon_plugins.cpp ├── pubsub_cpp ├── launch │ ├── pubsub_cpp_launch.py │ ├── pubsub_diy_msg_launch.py │ └── pubsub_qos_launch.py ├── package.xml ├── src │ ├── subscriber.cpp │ ├── publisher.cpp │ ├── sub_diy_msg.cpp │ ├── sub_hello_qos.cpp │ ├── pub_diy_msg.cpp │ └── pub_hello_qos.cpp └── CMakeLists.txt ├── service_cpp ├── launch │ ├── service_cpp_launch.py │ └── service_diy_launch.py ├── package.xml ├── CMakeLists.txt └── src │ ├── server.cpp │ ├── server_diy.cpp │ ├── client_diy.cpp │ └── client.cpp ├── parameters_cpp ├── launch │ ├── param_test_launch.py │ └── param_monitor_launch.py ├── package.xml ├── CMakeLists.txt └── src │ ├── param_test.cpp │ └── param_monitor.cpp ├── hello_ros2_cpp ├── package.xml ├── src │ └── hello_ros2.cpp └── CMakeLists.txt ├── component_demo ├── include │ └── component_demo │ │ ├── sub_component.hpp │ │ ├── pub_component.hpp │ │ └── visibility_control.h ├── src │ ├── sub_component.cpp │ └── pub_component.cpp ├── package.xml ├── CMakeLists.txt └── launch │ ├── separate_node_launch.py │ └── merge_node_launch.py ├── action_cpp ├── launch │ └── fibonacci_launch.py ├── package.xml ├── CMakeLists.txt └── src │ ├── fibonacci_server.cpp │ └── fibonacci_client.cpp └── bag_operator ├── package.xml ├── CMakeLists.txt └── scripts ├── bag_echo.py └── bag_filter.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ -------------------------------------------------------------------------------- /action_py/resource/action_py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pubsub_py/resource/pubsub_py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /action_py/action_py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pubsub_py/pubsub_py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /service_py/resource/service_py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /service_py/service_py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webots_demo/resource/webots_demo: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hello_ros2_py/resource/hello_ros2_py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /launch_example/resource/launch_example: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /parameters_py/resource/parameters_py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webots_demo/webots_demo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hello_ros2_py/hello_ros2_py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /learning_tf2_py/learning_tf2_py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /learning_tf2_py/resource/learning_tf2_py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /parameters_py/parameters_py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /diy_interface/msg/Student.msg: -------------------------------------------------------------------------------- 1 | string name 2 | uint8 age -------------------------------------------------------------------------------- /service_mix/srv/Circle.srv: -------------------------------------------------------------------------------- 1 | uint32 radius 2 | --- 3 | float64 area -------------------------------------------------------------------------------- /diy_interface/msg/Sphere.msg: -------------------------------------------------------------------------------- 1 | geometry_msgs/Point center 2 | float64 radius -------------------------------------------------------------------------------- /diy_interface/srv/QuestionAndAnswer.srv: -------------------------------------------------------------------------------- 1 | string question 2 | --- 3 | string answer -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ros2_code 2 | https://blog.csdn.net/cy1641395022/article/details/136120873 -------------------------------------------------------------------------------- /action_py/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/action_py 3 | [install] 4 | install_scripts=$base/lib/action_py 5 | -------------------------------------------------------------------------------- /pubsub_py/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/pubsub_py 3 | [install] 4 | install_scripts=$base/lib/pubsub_py 5 | -------------------------------------------------------------------------------- /learning_tf2_cpp/doc/turtle_tf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jieshoudaxue/ros2_code/HEAD/learning_tf2_cpp/doc/turtle_tf.pdf -------------------------------------------------------------------------------- /service_py/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/service_py 3 | [install] 4 | install_scripts=$base/lib/service_py 5 | -------------------------------------------------------------------------------- /webots_demo/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/webots_demo 3 | [install] 4 | install_scripts=$base/lib/webots_demo 5 | -------------------------------------------------------------------------------- /hello_ros2_py/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/hello_ros2_py 3 | [install] 4 | install_scripts=$base/lib/hello_ros2_py 5 | -------------------------------------------------------------------------------- /launch_example/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/launch_example 3 | [install] 4 | install_scripts=$base/lib/launch_example 5 | -------------------------------------------------------------------------------- /parameters_py/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/parameters_py 3 | [install] 4 | install_scripts=$base/lib/parameters_py 5 | -------------------------------------------------------------------------------- /learning_tf2_py/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/learning_tf2_py 3 | [install] 4 | install_scripts=$base/lib/learning_tf2_py 5 | -------------------------------------------------------------------------------- /diy_interface/action/Fibonacci.action: -------------------------------------------------------------------------------- 1 | # Request 2 | int32 order 3 | --- 4 | # Result 5 | int32[] sequence 6 | --- 7 | # Feedback 8 | int32[] partial_sequence -------------------------------------------------------------------------------- /launch_example/config/turtlesim_param.yaml: -------------------------------------------------------------------------------- 1 | # 使用通配符匹配所有节点 2 | /**: 3 | # 注意这里是两个下划线"__" 4 | ros__parameters: 5 | background_r: 199 6 | background_g: 237 7 | background_b: 204 -------------------------------------------------------------------------------- /pubsub_mix/msg/AddressBook.msg: -------------------------------------------------------------------------------- 1 | uint8 PHONE_TYPE_HOME=0 2 | uint8 PHONE_TYPE_WORK=1 3 | uint8 PHONE_TYPE_MOBILE=2 4 | 5 | string first_name 6 | string last_name 7 | string phone_number 8 | uint8 phone_type -------------------------------------------------------------------------------- /gazebo_mbot_go_maze/worlds/maze_room/model.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | maze_room 4 | 1.0 5 | model.sdf 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /polygon_base/launch/area_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='polygon_base', 8 | executable='area_node', 9 | name='area_node', 10 | output="screen", 11 | emulate_tty=True 12 | ) 13 | ]) -------------------------------------------------------------------------------- /polygon_plugins/plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | this is a square plugin 4 | 5 | 6 | 7 | this is a EquilateralTriangle plugin 8 | 9 | 10 | -------------------------------------------------------------------------------- /parameters_py/launch/param_monitor_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | from launch.actions import TimerAction 4 | 5 | def generate_launch_description(): 6 | return LaunchDescription([ 7 | Node( 8 | package='parameters_py', 9 | namespace='python', 10 | executable='param_monitor', 11 | name='param_monitor', 12 | output="screen", 13 | emulate_tty=True 14 | ) 15 | ]) -------------------------------------------------------------------------------- /pubsub_cpp/launch/pubsub_cpp_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='pubsub_cpp', 8 | namespace='cpp', 9 | executable='talker', 10 | name='talker' 11 | ), 12 | Node( 13 | package='pubsub_cpp', 14 | namespace='cpp', 15 | executable='listener', 16 | name='listener' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /service_cpp/launch/service_cpp_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='service_cpp', 8 | namespace='cpp', 9 | executable='server', 10 | name='server' 11 | ), 12 | Node( 13 | package='service_cpp', 14 | namespace='cpp', 15 | executable='client', 16 | name='client' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /pubsub_py/launch/pubsub_py_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='pubsub_py', 8 | namespace='python', 9 | executable='talker', 10 | name='talker' 11 | ), 12 | Node( 13 | package='pubsub_py', 14 | namespace='python', 15 | executable='listener', 16 | name='listener' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /service_mix/launch/service_mix_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='service_mix', 8 | namespace='mix', 9 | executable='server', 10 | name='server' 11 | ), 12 | Node( 13 | package='service_mix', 14 | namespace='mix', 15 | executable='client.py', 16 | name='client' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /service_py/launch/service_py_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='service_py', 8 | namespace='python', 9 | executable='server', 10 | name='server' 11 | ), 12 | Node( 13 | package='service_py', 14 | namespace='python', 15 | executable='client', 16 | name='client' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /parameters_cpp/launch/param_test_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='parameters_cpp', 8 | namespace='cpp', 9 | executable='param_test', 10 | name='param_test', 11 | output="screen", 12 | emulate_tty=True, 13 | parameters=[ 14 | {"demo_param": "set in launch !!"} 15 | ] 16 | ) 17 | ]) -------------------------------------------------------------------------------- /parameters_py/launch/param_test_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='parameters_py', 8 | namespace='python', 9 | executable='param_test', 10 | name='param_test', 11 | output="screen", 12 | emulate_tty=True, 13 | parameters=[ 14 | {"demo_param": "set in launch !!"} 15 | ] 16 | ) 17 | ]) -------------------------------------------------------------------------------- /service_cpp/launch/service_diy_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='service_cpp', 8 | namespace='cpp', 9 | executable='server_diy', 10 | name='server_diy' 11 | ), 12 | Node( 13 | package='service_cpp', 14 | namespace='cpp', 15 | executable='client_diy', 16 | name='client_diy' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /pubsub_cpp/launch/pubsub_diy_msg_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='pubsub_cpp', 8 | namespace='cpp', 9 | executable='talker_diy', 10 | name='talker_diy' 11 | ), 12 | Node( 13 | package='pubsub_cpp', 14 | namespace='cpp', 15 | executable='listener_diy', 16 | name='listener_diy' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /service_py/launch/service_diy_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='service_py', 8 | namespace='python', 9 | executable='server_diy', 10 | name='server_diy' 11 | ), 12 | Node( 13 | package='service_py', 14 | namespace='python', 15 | executable='client_diy', 16 | name='client_diy' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /pubsub_py/launch/pubsub_diy_msg_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='pubsub_py', 8 | namespace='python', 9 | executable='talker_diy', 10 | name='talker_diy' 11 | ), 12 | Node( 13 | package='pubsub_py', 14 | namespace='python', 15 | executable='listener_diy', 16 | name='listener_diy' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /learning_tf2_cpp/doc/turtle_tf.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | "world" -> "turtle1"[label=" Broadcaster: default_authority\nAverage rate: 57.541\nBuffer length: 5.005\nMost recent transform: 1712577575.641974\nOldest transform: 1712577570.636876\n"]; 3 | "world" -> "turtle2"[label=" Broadcaster: default_authority\nAverage rate: 57.541\nBuffer length: 5.005\nMost recent transform: 1712577575.642066\nOldest transform: 1712577570.636922\n"]; 4 | edge [style=invis]; 5 | subgraph cluster_legend { style=bold; color=black; label ="view_frames Result"; 6 | "Recorded at time: 1712577575.650509"[ shape=plaintext ] ; 7 | }->"world"; 8 | } -------------------------------------------------------------------------------- /pubsub_mix/launch/pubsub_mix_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='pubsub_mix', 8 | namespace='mix', 9 | executable='publish_address_book', 10 | name='publish_address_book' 11 | ), 12 | Node( 13 | package='pubsub_mix', 14 | namespace='mix', 15 | executable='subscribe_address_book.py', 16 | name='subscribe_address_book' 17 | ) 18 | ]) -------------------------------------------------------------------------------- /webots_demo/resource/mbot.urdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | /left_sensor 7 | true 8 | 9 | 10 | 11 | 12 | /right_sensor 13 | true 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /hello_ros2_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | hello_ros2_cpp 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | ament_lint_auto 13 | ament_lint_common 14 | 15 | 16 | ament_cmake 17 | 18 | 19 | -------------------------------------------------------------------------------- /hello_ros2_cpp/src/hello_ros2.cpp: -------------------------------------------------------------------------------- 1 | #include "rclcpp/rclcpp.hpp" 2 | 3 | class HelloRos2 : public rclcpp::Node { 4 | public: 5 | HelloRos2() : Node("hello_ros2") { 6 | RCLCPP_INFO(this->get_logger(), "start hello ros2 in cpp !!"); 7 | } 8 | 9 | void run() { 10 | while(rclcpp::ok()) { 11 | RCLCPP_INFO(this->get_logger(), "hello ros2 in cpp !!"); 12 | sleep(1); 13 | } 14 | } 15 | 16 | }; 17 | 18 | int main(int argc, char* argv[]) { 19 | rclcpp::init(argc, argv); 20 | 21 | auto node = std::make_shared(); 22 | 23 | node->run(); 24 | 25 | rclcpp::shutdown(); 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /component_demo/include/component_demo/sub_component.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMPONENT_DEMO__SUB_COMPONENT_HPP_ 2 | #define COMPONENT_DEMO__SUB_COMPONENT_HPP_ 3 | 4 | #include "component_demo/visibility_control.h" 5 | #include "rclcpp/rclcpp.hpp" 6 | #include "std_msgs/msg/string.hpp" 7 | 8 | namespace component_demo 9 | { 10 | // 注释请查看 pub_component.hpp 11 | class SubComponent : public rclcpp::Node 12 | { 13 | public: 14 | COMPONENT_DEMO_PUBLIC 15 | explicit SubComponent(const rclcpp::NodeOptions & options); 16 | 17 | private: 18 | rclcpp::Subscription::SharedPtr sub_msg_; 19 | }; 20 | 21 | 22 | } // namespace component_demo 23 | 24 | 25 | #endif // COMPONENT_DEMO__SUB_COMPONENT_HPP_ -------------------------------------------------------------------------------- /hello_ros2_py/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | hello_ros2_py 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_copyright 11 | ament_flake8 12 | ament_pep257 13 | python3-pytest 14 | 15 | 16 | ament_python 17 | 18 | 19 | -------------------------------------------------------------------------------- /launch_example/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | launch_example 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_copyright 11 | ament_flake8 12 | ament_pep257 13 | python3-pytest 14 | 15 | 16 | ament_python 17 | 18 | 19 | -------------------------------------------------------------------------------- /action_py/launch/fibonacci_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='action_py', 8 | namespace='python', 9 | executable='fibonacci_server', 10 | name='fibonacci_server', 11 | output="screen", 12 | emulate_tty=True 13 | ), 14 | Node( 15 | package='action_py', 16 | namespace='python', 17 | executable='fibonacci_client', 18 | name='fibonacci_client', 19 | output="screen", 20 | emulate_tty=True 21 | ) 22 | ]) -------------------------------------------------------------------------------- /parameters_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | parameters_cpp 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | 14 | ament_lint_auto 15 | ament_lint_common 16 | 17 | 18 | ament_cmake 19 | 20 | 21 | -------------------------------------------------------------------------------- /polygon_base/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | polygon_base 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | pluginlib 13 | 14 | ament_lint_auto 15 | ament_lint_common 16 | 17 | 18 | ament_cmake 19 | 20 | 21 | -------------------------------------------------------------------------------- /action_cpp/launch/fibonacci_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | def generate_launch_description(): 5 | return LaunchDescription([ 6 | Node( 7 | package='action_cpp', 8 | namespace='cpp', 9 | executable='action_server_diy', 10 | name='action_server_diy', 11 | output="screen", 12 | emulate_tty=True 13 | ), 14 | Node( 15 | package='action_cpp', 16 | namespace='cpp', 17 | executable='action_client_diy', 18 | name='action_client_diy', 19 | output="screen", 20 | emulate_tty=True 21 | ) 22 | ]) -------------------------------------------------------------------------------- /parameters_py/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | parameters_py 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | rclpy 11 | 12 | ament_copyright 13 | ament_flake8 14 | ament_pep257 15 | python3-pytest 16 | 17 | 18 | ament_python 19 | 20 | 21 | -------------------------------------------------------------------------------- /bag_operator/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bag_operator 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | rosbag2_cpp 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /launch_example/launch_example/turtlesim_world_2_launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from ament_index_python.packages import get_package_share_directory 4 | 5 | from launch import LaunchDescription 6 | from launch_ros.actions import Node 7 | 8 | 9 | def generate_launch_description(): 10 | # Tips: 使用 yaml 文件配置节点参数的方法 11 | # 加载全局参数文件,设置窗口背景色为护眼绿 12 | turtlesim_world_2_param = os.path.join( 13 | get_package_share_directory('launch_example'), 14 | 'config', 15 | 'turtlesim_param.yaml' 16 | ) 17 | 18 | return LaunchDescription([ 19 | Node( 20 | package='turtlesim', 21 | executable='turtlesim_node', 22 | name='sim', 23 | parameters=[turtlesim_world_2_param] 24 | ) 25 | ]) 26 | -------------------------------------------------------------------------------- /pubsub_py/pubsub_py/subscriber.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from std_msgs.msg import String 8 | 9 | class Subscriber(Node): 10 | def __init__(self): 11 | super().__init__('test_subscriber') 12 | self._subscriber = self.create_subscription(String, "hello_topic", self.topic_callback, 10) 13 | 14 | def topic_callback(self, msg): 15 | self.get_logger().info("subscribe: %s" % msg.data) 16 | 17 | 18 | def main(args=None): 19 | rclpy.init(args=args) 20 | 21 | sub_node = Subscriber() 22 | rclpy.spin(sub_node) 23 | 24 | sub_node.destroy_node() 25 | rclpy.shutdown() 26 | 27 | 28 | if __name__ == '__main__': 29 | main() -------------------------------------------------------------------------------- /polygon_plugins/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | polygon_plugins 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake_ros 11 | 12 | polygon_base 13 | pluginlib 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /action_py/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | action_py 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | diy_interface 11 | rclpy 12 | 13 | ament_copyright 14 | ament_flake8 15 | ament_pep257 16 | python3-pytest 17 | 18 | 19 | ament_python 20 | 21 | 22 | -------------------------------------------------------------------------------- /parameters_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(parameters_cpp) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(rclcpp REQUIRED) 11 | 12 | add_executable(param_test src/param_test.cpp) 13 | ament_target_dependencies(param_test rclcpp) 14 | 15 | add_executable(param_monitor src/param_monitor.cpp) 16 | ament_target_dependencies(param_monitor rclcpp) 17 | 18 | install(TARGETS 19 | param_test 20 | param_monitor 21 | DESTINATION lib/${PROJECT_NAME}) 22 | 23 | install(DIRECTORY 24 | launch 25 | DESTINATION share/${PROJECT_NAME} 26 | ) 27 | 28 | ament_package() 29 | -------------------------------------------------------------------------------- /action_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | action_cpp 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | diy_interface 13 | rclcpp 14 | rclcpp_action 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /component_demo/src/sub_component.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rclcpp/rclcpp.hpp" 5 | #include "component_demo/sub_component.hpp" 6 | 7 | #include "rclcpp_components/register_node_macro.hpp" 8 | RCLCPP_COMPONENTS_REGISTER_NODE(component_demo::SubComponent) 9 | 10 | namespace component_demo 11 | { 12 | SubComponent::SubComponent(const rclcpp::NodeOptions & options) 13 | : Node("sub_component", options) { 14 | auto msg_callback = [this](std_msgs::msg::String::ConstSharedPtr msg) { 15 | RCLCPP_INFO(this->get_logger(), "I heard: [%s]", msg->data.c_str()); 16 | }; 17 | 18 | sub_msg_ = create_subscription("hello_msg", 10, msg_callback); 19 | } 20 | 21 | }; // namespace component_demo -------------------------------------------------------------------------------- /component_demo/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | component_demo 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | rclcpp_components 14 | std_msgs 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /service_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | service_cpp 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | example_interfaces 14 | diy_interface 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /polygon_plugins/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(polygon_plugins) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(ament_cmake_ros REQUIRED) 11 | find_package(polygon_base REQUIRED) 12 | find_package(pluginlib REQUIRED) 13 | 14 | # 必须调用,不然polygon_base的area_node样例运行时找不到这个插件,无法实例化 15 | pluginlib_export_plugin_description_file(polygon_base plugins.xml) 16 | 17 | add_library(polygon_plugins src/polygon_plugins.cpp) 18 | ament_target_dependencies(polygon_plugins polygon_base pluginlib) 19 | 20 | install(TARGETS 21 | polygon_plugins 22 | LIBRARY DESTINATION lib 23 | ) 24 | 25 | ament_package() 26 | -------------------------------------------------------------------------------- /diy_interface/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(diy_interface) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | # uncomment the following section in order to fill in 11 | # further dependencies manually. 12 | find_package(geometry_msgs REQUIRED) 13 | find_package(rosidl_default_generators REQUIRED) 14 | 15 | rosidl_generate_interfaces(${PROJECT_NAME} 16 | "msg/Student.msg" 17 | "msg/Sphere.msg" 18 | "srv/QuestionAndAnswer.srv" 19 | "action/Fibonacci.action" 20 | DEPENDENCIES geometry_msgs # Add packages that above messages depend on, in this case geometry_msgs for Sphere.msg 21 | ) 22 | 23 | ament_package() 24 | -------------------------------------------------------------------------------- /service_py/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | service_py 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | rclcpy 11 | example_interfaces 12 | diy_interface 13 | 14 | ament_copyright 15 | ament_flake8 16 | ament_pep257 17 | python3-pytest 18 | 19 | 20 | ament_python 21 | 22 | 23 | -------------------------------------------------------------------------------- /gazebo_mbot_go_maze/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(gazebo_mbot_go_maze) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(rclcpp REQUIRED) 11 | find_package(rclcpp_components REQUIRED) 12 | find_package(rosidl_default_generators REQUIRED) 13 | find_package(rclcpp_action REQUIRED) 14 | find_package(std_msgs REQUIRED) 15 | find_package(geometry_msgs REQUIRED) 16 | 17 | 18 | install(DIRECTORY 19 | launch 20 | urdf 21 | worlds 22 | rviz 23 | DESTINATION share/${PROJECT_NAME} 24 | ) 25 | 26 | install(PROGRAMS 27 | tool/mbot_teletop.py 28 | DESTINATION lib/${PROJECT_NAME} 29 | ) 30 | 31 | ament_package() 32 | -------------------------------------------------------------------------------- /hello_ros2_py/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import find_packages, setup 2 | 3 | package_name = 'hello_ros2_py' 4 | 5 | setup( 6 | name=package_name, 7 | version='0.0.0', 8 | packages=find_packages(exclude=['test']), 9 | data_files=[ 10 | ('share/ament_index/resource_index/packages', 11 | ['resource/' + package_name]), 12 | ('share/' + package_name, ['package.xml']), 13 | ], 14 | install_requires=['setuptools'], 15 | zip_safe=True, 16 | maintainer='ycao', 17 | maintainer_email='1641395022@qq.com', 18 | description='TODO: Package description', 19 | license='Apache-2.0', 20 | tests_require=['pytest'], 21 | entry_points={ 22 | 'console_scripts': [ 23 | 'hello_ros2 = hello_ros2_py.hello_ros2:main' 24 | ], 25 | }, 26 | ) 27 | -------------------------------------------------------------------------------- /pubsub_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pubsub_cpp 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | ament_lint_auto 13 | ament_lint_common 14 | 15 | rclcpp 16 | std_msgs 17 | diy_interface 18 | ros2launch 19 | 20 | 21 | ament_cmake 22 | 23 | 24 | -------------------------------------------------------------------------------- /webots_demo/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | webots_demo 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | rclpy 11 | geometry_msgs 12 | webots_ros2_driver 13 | 14 | ament_copyright 15 | ament_flake8 16 | ament_pep257 17 | python3-pytest 18 | 19 | 20 | ament_python 21 | 22 | 23 | -------------------------------------------------------------------------------- /polygon_base/include/polygon_base/regular_polygon.hpp: -------------------------------------------------------------------------------- 1 | #ifndef POLYGON_BASE_REGULAR_POLYGON_HPP 2 | #define POLYGON_BASE_REGULAR_POLYGON_HPP 3 | 4 | namespace polygon_base { 5 | 6 | // 整个 RegularPolygon 类是一个抽象基类(ABC),由于存在纯虚函数,不能直接实例化,因此也叫接口类 7 | class RegularPolygon { 8 | public: 9 | // = 0: 表示纯虚函数,必须需要在派生(子)类中被实现。 10 | virtual void init(double side_length) = 0; 11 | virtual double area() = 0; 12 | // 虚析构函数。在基类中声明虚析构函数是为了确保当通过基类指针删除派生类对象时能够调用正确的析构函数,从而避免资源泄漏。 13 | virtual ~RegularPolygon(){} 14 | 15 | // protected: 表明下面的成员函数和构造函数只能在类内部及继承它的子类中被访问。 16 | protected: 17 | // 受保护的默认构造函数。由于是受保护的,这个构造函数不能被类的外部直接调用,但可以在派生类中被调用。 18 | // 它被定义为受保护是为了防止直接创建 RegularPolygon 类型的对象,因为它是一个抽象基类。 19 | RegularPolygon(){} 20 | }; 21 | 22 | } // namespace polygon_base 23 | 24 | #endif // POLYGON_BASE_REGULAR_POLYGON_HPP -------------------------------------------------------------------------------- /pubsub_cpp/launch/pubsub_qos_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | from launch.actions import TimerAction 4 | 5 | def generate_launch_description(): 6 | return LaunchDescription([ 7 | Node( 8 | package='pubsub_cpp', 9 | namespace='qos', 10 | executable='talker_qos', 11 | name='talker_qos' 12 | ), 13 | TimerAction( 14 | # period=5.0, # test qos durability:TRANSIENT_LOCAL 15 | period=0.0, 16 | actions=[ 17 | Node( 18 | package='pubsub_cpp', 19 | namespace='qos', 20 | executable='listener_qos', 21 | name='listener_qos' 22 | ) 23 | ] 24 | ) 25 | ]) -------------------------------------------------------------------------------- /pubsub_py/launch/pubsub_qos_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | from launch.actions import TimerAction 4 | 5 | def generate_launch_description(): 6 | return LaunchDescription([ 7 | Node( 8 | package='pubsub_py', 9 | namespace='qos', 10 | executable='talker_qos', 11 | name='talker_qos' 12 | ), 13 | TimerAction( 14 | period=3.0, # test qos durability:TRANSIENT_LOCAL 15 | # period=0.0, 16 | actions=[ 17 | Node( 18 | package='pubsub_py', 19 | namespace='qos', 20 | executable='listener_qos', 21 | name='listener_qos' 22 | ) 23 | ] 24 | ) 25 | ]) -------------------------------------------------------------------------------- /pubsub_py/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pubsub_py 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_copyright 11 | ament_flake8 12 | ament_pep257 13 | python3-pytest 14 | 15 | rclpy 16 | std_msgs 17 | ros2launch 18 | diy_interfaces 19 | 20 | 21 | ament_python 22 | 23 | 24 | -------------------------------------------------------------------------------- /learning_tf2_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | learning_tf2_cpp 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | rclcpp_components 13 | geometry_msgs 14 | rclcpp 15 | tf2 16 | tf2_ros 17 | turtlesim 18 | 19 | ament_lint_auto 20 | ament_lint_common 21 | 22 | 23 | ament_cmake 24 | 25 | 26 | -------------------------------------------------------------------------------- /learning_tf2_py/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | learning_tf2_py 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | geometry_msgs 11 | python3-numpy 12 | rclpy 13 | tf2_ros_py 14 | turtlesim 15 | 16 | ament_copyright 17 | ament_flake8 18 | ament_pep257 19 | python3-pytest 20 | 21 | 22 | ament_python 23 | 24 | 25 | -------------------------------------------------------------------------------- /pubsub_mix/scripts/subscribe_address_book.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from pubsub_mix.msg import AddressBook 8 | 9 | class Subscriber(Node): 10 | def __init__(self): 11 | super().__init__('address_book_subscriber') 12 | self._subscriber = self.create_subscription(AddressBook, "address_book", self.topic_callback, 10) 13 | 14 | def topic_callback(self, msg): 15 | self.get_logger().info("subscribe in python: {0}, {1}, {2}, {3}".format( 16 | msg.first_name, msg.last_name, msg.phone_number, msg.phone_type)) 17 | 18 | 19 | def main(args=None): 20 | rclpy.init(args=args) 21 | 22 | sub_node = Subscriber() 23 | rclpy.spin(sub_node) 24 | 25 | sub_node.destroy_node() 26 | rclpy.shutdown() 27 | 28 | 29 | if __name__ == '__main__': 30 | main() -------------------------------------------------------------------------------- /parameters_cpp/launch/param_monitor_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | from launch.actions import TimerAction 4 | 5 | def generate_launch_description(): 6 | return LaunchDescription([ 7 | Node( 8 | package='turtlesim', 9 | executable='turtlesim_node', 10 | name='turtlesim_node', 11 | output="screen", 12 | emulate_tty=True 13 | ), 14 | TimerAction( 15 | period=3.0, 16 | actions=[ 17 | Node( 18 | package='parameters_cpp', 19 | namespace='cpp', 20 | executable='param_monitor', 21 | name='param_monitor', 22 | output="screen", 23 | emulate_tty=True 24 | ) 25 | ] 26 | ) 27 | 28 | ]) -------------------------------------------------------------------------------- /pubsub_cpp/src/subscriber.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rclcpp/rclcpp.hpp" 4 | #include "std_msgs/msg/string.hpp" 5 | 6 | class Subscriber : public rclcpp::Node 7 | { 8 | public: 9 | Subscriber() : Node("test_subscriber") { 10 | subscription_ = this->create_subscription( 11 | "hello_topic", 10, std::bind(&Subscriber::topic_callback, this, std::placeholders::_1)); 12 | } 13 | 14 | private: 15 | void topic_callback(const std_msgs::msg::String &msg) const { 16 | RCLCPP_INFO(this->get_logger(), "i received: %s", msg.data.c_str()); 17 | } 18 | 19 | private: 20 | rclcpp::Subscription::SharedPtr subscription_; 21 | }; 22 | 23 | 24 | int main(int argc, char * argv[]) { 25 | rclcpp::init(argc, argv); 26 | rclcpp::spin(std::make_shared()); 27 | rclcpp::shutdown(); 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /pubsub_mix/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pubsub_mix 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | ament_lint_auto 13 | ament_lint_common 14 | ament_cmake_python 15 | 16 | rosidl_default_generators 17 | rosidl_default_runtime 18 | rosidl_interface_packages 19 | 20 | 21 | ament_cmake 22 | 23 | 24 | -------------------------------------------------------------------------------- /action_py/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /pubsub_py/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /gazebo_mbot_go_maze/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gazebo_mbot_go_maze 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | rclcpp_components 14 | rosidl_default_generators 15 | rclcpp_action 16 | std_msgs 17 | geometry_msgs 18 | 19 | ament_lint_auto 20 | ament_lint_common 21 | 22 | 23 | ament_cmake 24 | 25 | 26 | -------------------------------------------------------------------------------- /hello_ros2_py/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /launch_example/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /parameters_py/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /service_py/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /webots_demo/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /component_demo/include/component_demo/pub_component.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMPONENT_DEMO__PUB_COMPONENT_HPP_ 2 | #define COMPONENT_DEMO__PUB_COMPONENT_HPP_ 3 | 4 | // 必须配置可见头文件,主要是为了兼容 lunix 和 windows 5 | #include "component_demo/visibility_control.h" 6 | #include "rclcpp/rclcpp.hpp" 7 | #include "std_msgs/msg/string.hpp" 8 | 9 | namespace component_demo 10 | { 11 | 12 | class PubComponent : public rclcpp::Node 13 | { 14 | public: 15 | // 来自可见头文件 16 | COMPONENT_DEMO_PUBLIC 17 | // explicit 是为了防止实例化PubComponent时的隐式转换 18 | explicit PubComponent(const rclcpp::NodeOptions & options); 19 | 20 | protected: 21 | void on_timer(); 22 | 23 | private: 24 | size_t count_; 25 | std::string msg_inner_; 26 | rclcpp::Publisher::SharedPtr pub_msg_; 27 | rclcpp::TimerBase::SharedPtr timer_; 28 | }; 29 | 30 | } // namespace component_demo 31 | 32 | 33 | #endif // COMPONENT_DEMO__PUB_COMPONENT_HPP_ -------------------------------------------------------------------------------- /learning_tf2_py/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /service_mix/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | service_mix 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | ament_lint_auto 14 | ament_lint_common 15 | ament_cmake_python 16 | 17 | rosidl_default_generators 18 | rosidl_default_runtime 19 | rosidl_interface_packages 20 | 21 | 22 | ament_cmake 23 | 24 | 25 | -------------------------------------------------------------------------------- /diy_interface/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | diy_interface 5 | 0.0.0 6 | TODO: Package description 7 | ycao 8 | Apache-2.0 9 | 10 | ament_cmake 11 | 12 | ament_lint_auto 13 | ament_lint_common 14 | 15 | geometry_msgs 16 | action_msgs 17 | 18 | rosidl_default_generators 19 | rosidl_default_runtime 20 | rosidl_interface_packages 21 | 22 | 23 | ament_cmake 24 | 25 | 26 | -------------------------------------------------------------------------------- /polygon_base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(polygon_base) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(pluginlib REQUIRED) 11 | 12 | add_executable(area_node src/area_node.cpp) 13 | target_include_directories(area_node PUBLIC 14 | ${CMAKE_CURRENT_SOURCE_DIR}/include) 15 | ament_target_dependencies(area_node pluginlib) 16 | 17 | install(TARGETS 18 | area_node 19 | DESTINATION lib/${PROJECT_NAME}) 20 | 21 | 22 | install(DIRECTORY 23 | launch 24 | DESTINATION share/${PROJECT_NAME} 25 | ) 26 | 27 | # 必须把接口类的头文件安装出来,不然插件库编译的时候找不到头文件 28 | install(DIRECTORY 29 | include/ 30 | DESTINATION include 31 | ) 32 | 33 | # 接口类头文件必须声明出来,不然插件库编译的时候也找不到头文件 34 | ament_export_include_directories( 35 | include 36 | ) 37 | 38 | ament_package() 39 | -------------------------------------------------------------------------------- /hello_ros2_py/hello_ros2_py/hello_ros2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | import time 7 | 8 | class HelloRos2(Node): 9 | def __init__(self, name): 10 | super().__init__(name) 11 | self.get_logger().info("start hello_ros2_py node !!") 12 | 13 | def run(self): 14 | try: 15 | while rclpy.ok(): 16 | self.get_logger().info("hello ros2 in python !!") 17 | time.sleep(1) 18 | except KeyboardInterrupt: 19 | self.get_logger().info("Node was interrupted, shutting down...") 20 | 21 | 22 | def main(args=None): 23 | rclpy.init(args=args) 24 | node = HelloRos2("hello_ros2_py") 25 | 26 | try: 27 | node.run() 28 | except KeyboardInterrupt: 29 | node.destroy_node() 30 | rclpy.shutdown() 31 | 32 | if __name__ == '__main__': 33 | main() -------------------------------------------------------------------------------- /pubsub_py/pubsub_py/publisher.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from std_msgs.msg import String 8 | 9 | class Publisher(Node): 10 | def __init__(self): 11 | super().__init__('test_publisher') 12 | self._publisher = self.create_publisher(String, "hello_topic", 10) 13 | self._timer = self.create_timer(0.5, self.timer_callback) 14 | self._i = 0 15 | 16 | def timer_callback(self): 17 | msg = String() 18 | msg.data = "hello, i am fine in python! %d" % self._i 19 | self._publisher.publish(msg) 20 | self.get_logger().info("publish: %s" % msg.data) 21 | self._i += 1 22 | 23 | 24 | def main(args=None): 25 | rclpy.init(args=args) 26 | 27 | pub_node = Publisher() 28 | rclpy.spin(pub_node) 29 | 30 | pub_node.destroy_node() 31 | rclpy.shutdown() 32 | 33 | if __name__ == '__main__': 34 | main() -------------------------------------------------------------------------------- /service_py/service_py/server.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from example_interfaces.srv import AddTwoInts 8 | 9 | class ServiceServer(Node): 10 | def __init__(self): 11 | super().__init__('service_server') 12 | self._service = self.create_service(AddTwoInts, "add_two_ints", self.server_callback) 13 | 14 | def server_callback(self, request, response): 15 | response.sum = request.a + request.b 16 | self.get_logger().info("python server: receive {0}(a) + {1}(b), return {2}(sum)".format( 17 | request.a, request.b, response.sum)) 18 | return response 19 | 20 | def main(args=None): 21 | rclpy.init(args=args) 22 | 23 | server_node = ServiceServer() 24 | rclpy.spin(server_node) 25 | 26 | server_node.destroy_node() 27 | rclpy.shutdown() 28 | 29 | if __name__ == '__main__': 30 | main() -------------------------------------------------------------------------------- /service_py/service_py/server_diy.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from diy_interface.srv import QuestionAndAnswer 8 | 9 | class ServiceServer(Node): 10 | def __init__(self): 11 | super().__init__('service_server') 12 | self._service = self.create_service(QuestionAndAnswer, "question_and_answer", self.server_callback) 13 | 14 | def server_callback(self, request, response): 15 | response.answer = "feel good!" 16 | self.get_logger().info("[python server] receive: {0}, return: {1}".format( 17 | request.question, response.answer)) 18 | return response 19 | 20 | def main(args=None): 21 | rclpy.init(args=args) 22 | 23 | server_node = ServiceServer() 24 | rclpy.spin(server_node) 25 | 26 | server_node.destroy_node() 27 | rclpy.shutdown() 28 | 29 | if __name__ == '__main__': 30 | main() -------------------------------------------------------------------------------- /action_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(action_cpp) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(ament_cmake_ros REQUIRED) 11 | find_package(diy_interface REQUIRED) 12 | find_package(rclcpp REQUIRED) 13 | find_package(rclcpp_action REQUIRED) 14 | 15 | add_executable(action_client_diy src/fibonacci_client.cpp) 16 | ament_target_dependencies(action_client_diy rclcpp rclcpp_action diy_interface) 17 | 18 | add_executable(action_server_diy src/fibonacci_server.cpp) 19 | ament_target_dependencies(action_server_diy rclcpp rclcpp_action diy_interface) 20 | 21 | install(TARGETS 22 | action_client_diy 23 | action_server_diy 24 | DESTINATION lib/${PROJECT_NAME}) 25 | 26 | install(DIRECTORY 27 | launch 28 | DESTINATION share/${PROJECT_NAME} 29 | ) 30 | 31 | 32 | ament_package() 33 | -------------------------------------------------------------------------------- /action_py/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /hello_ros2_py/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /parameters_py/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /pubsub_py/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /service_py/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /webots_demo/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /launch_example/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /learning_tf2_py/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /bag_operator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(bag_operator) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(rclcpp REQUIRED) 11 | find_package(rosbag2_cpp REQUIRED) 12 | 13 | add_executable(bag_record src/bag_record.cpp) 14 | target_include_directories(bag_record PUBLIC 15 | ${CMAKE_CURRENT_SOURCE_DIR}/include) 16 | ament_target_dependencies(bag_record rclcpp rosbag2_cpp) 17 | 18 | add_executable(bag_play src/bag_play.cpp) 19 | target_include_directories(bag_play PUBLIC 20 | ${CMAKE_CURRENT_SOURCE_DIR}/include) 21 | ament_target_dependencies(bag_play rclcpp rosbag2_cpp) 22 | 23 | install(TARGETS 24 | bag_record 25 | bag_play 26 | DESTINATION lib/${PROJECT_NAME}) 27 | 28 | install(PROGRAMS 29 | scripts/bag_echo.py 30 | scripts/bag_filter.py 31 | DESTINATION lib/${PROJECT_NAME}) 32 | 33 | ament_package() 34 | -------------------------------------------------------------------------------- /action_py/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from setuptools import find_packages, setup 4 | 5 | package_name = 'action_py' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=find_packages(exclude=['test']), 11 | data_files=[ 12 | ('share/ament_index/resource_index/packages', 13 | ['resource/' + package_name]), 14 | ('share/' + package_name, ['package.xml']), 15 | (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*_launch.py'))) 16 | ], 17 | install_requires=['setuptools'], 18 | zip_safe=True, 19 | maintainer='ycao', 20 | maintainer_email='1641395022@qq.com', 21 | description='TODO: Package description', 22 | license='Apache-2.0', 23 | tests_require=['pytest'], 24 | entry_points={ 25 | 'console_scripts': [ 26 | 'fibonacci_server = action_py.fibonacci_server:main', 27 | 'fibonacci_client = action_py.fibonacci_client:main' 28 | ], 29 | }, 30 | ) 31 | -------------------------------------------------------------------------------- /parameters_py/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from setuptools import find_packages, setup 4 | 5 | package_name = 'parameters_py' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=find_packages(exclude=['test']), 11 | data_files=[ 12 | ('share/ament_index/resource_index/packages', 13 | ['resource/' + package_name]), 14 | ('share/' + package_name, ['package.xml']), 15 | (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*_launch.py'))) 16 | ], 17 | install_requires=['setuptools'], 18 | zip_safe=True, 19 | maintainer='ycao', 20 | maintainer_email='1641395022@qq.com', 21 | description='TODO: Package description', 22 | license='Apache-2.0', 23 | tests_require=['pytest'], 24 | entry_points={ 25 | 'console_scripts': [ 26 | 'param_test = parameters_py.param_test:main', 27 | 'param_monitor = parameters_py.param_monitor:main' 28 | ], 29 | }, 30 | ) 31 | -------------------------------------------------------------------------------- /learning_tf2_py/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from setuptools import find_packages, setup 4 | 5 | package_name = 'learning_tf2_py' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=find_packages(exclude=['test']), 11 | data_files=[ 12 | ('share/ament_index/resource_index/packages', 13 | ['resource/' + package_name]), 14 | ('share/' + package_name, ['package.xml']), 15 | (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*_launch.py'))) 16 | ], 17 | install_requires=['setuptools'], 18 | zip_safe=True, 19 | maintainer='ycao', 20 | maintainer_email='1641395022@qq.com', 21 | description='TODO: Package description', 22 | license='Apache-2.0', 23 | tests_require=['pytest'], 24 | entry_points={ 25 | 'console_scripts': [ 26 | 'turtle_tf2_broadcaster = learning_tf2_py.turtle_tf2_broadcaster:main', 27 | 'turtle_tf2_listener = learning_tf2_py.turtle_tf2_listener:main' 28 | ], 29 | }, 30 | ) 31 | -------------------------------------------------------------------------------- /action_py/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /pubsub_py/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /service_py/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /webots_demo/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /hello_ros2_py/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /launch_example/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /learning_tf2_py/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /parameters_py/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /launch_example/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from setuptools import find_packages, setup 4 | 5 | package_name = 'launch_example' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=find_packages(exclude=['test']), 11 | data_files=[ 12 | ('share/ament_index/resource_index/packages', 13 | ['resource/' + package_name]), 14 | ('share/' + package_name, ['package.xml']), 15 | (os.path.join('share', package_name, 'launch_example'), glob(os.path.join('launch_example', '*_launch.py'))), 16 | (os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.yaml'))), 17 | (os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.rviz'))) 18 | ], 19 | install_requires=['setuptools'], 20 | zip_safe=True, 21 | maintainer='ycao', 22 | maintainer_email='1641395022@qq.com', 23 | description='TODO: Package description', 24 | license='Apache-2.0', 25 | tests_require=['pytest'], 26 | entry_points={ 27 | 'console_scripts': [ 28 | ], 29 | }, 30 | ) 31 | -------------------------------------------------------------------------------- /service_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(service_cpp) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(rclcpp REQUIRED) 11 | find_package(example_interfaces REQUIRED) 12 | find_package(diy_interface REQUIRED) 13 | 14 | add_executable(server src/server.cpp) 15 | ament_target_dependencies(server rclcpp example_interfaces) 16 | 17 | add_executable(client src/client.cpp) 18 | ament_target_dependencies(client rclcpp example_interfaces) 19 | 20 | add_executable(server_diy src/server_diy.cpp) 21 | ament_target_dependencies(server_diy rclcpp diy_interface) 22 | 23 | add_executable(client_diy src/client_diy.cpp) 24 | ament_target_dependencies(client_diy rclcpp diy_interface) 25 | 26 | install(TARGETS 27 | server 28 | client 29 | server_diy 30 | client_diy 31 | DESTINATION lib/${PROJECT_NAME}) 32 | 33 | install(DIRECTORY 34 | launch 35 | DESTINATION share/${PROJECT_NAME} 36 | ) 37 | 38 | ament_package() 39 | -------------------------------------------------------------------------------- /service_py/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from setuptools import find_packages, setup 4 | 5 | package_name = 'service_py' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=find_packages(exclude=['test']), 11 | data_files=[ 12 | ('share/ament_index/resource_index/packages', 13 | ['resource/' + package_name]), 14 | ('share/' + package_name, ['package.xml']), 15 | (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*_launch.py'))) 16 | ], 17 | install_requires=['setuptools'], 18 | zip_safe=True, 19 | maintainer='ycao', 20 | maintainer_email='1641395022@qq.com', 21 | description='TODO: Package description', 22 | license='Apache-2.0', 23 | tests_require=['pytest'], 24 | entry_points={ 25 | 'console_scripts': [ 26 | 'server = service_py.server:main', 27 | 'client = service_py.client:main', 28 | 'server_diy = service_py.server_diy:main', 29 | 'client_diy = service_py.client_diy:main' 30 | ], 31 | }, 32 | ) 33 | -------------------------------------------------------------------------------- /component_demo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(component_demo) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(rclcpp REQUIRED) 11 | find_package(rclcpp_components REQUIRED) 12 | find_package(std_msgs REQUIRED) 13 | 14 | include_directories(include) 15 | 16 | add_library(sub_component SHARED src/sub_component.cpp) 17 | ament_target_dependencies(sub_component rclcpp rclcpp_components std_msgs) 18 | rclcpp_components_register_nodes(sub_component "component_demo::SubComponent") 19 | 20 | add_library(pub_component SHARED src/pub_component.cpp) 21 | ament_target_dependencies(pub_component rclcpp rclcpp_components std_msgs) 22 | rclcpp_components_register_nodes(pub_component "component_demo::PubComponent") 23 | 24 | install(TARGETS 25 | sub_component 26 | pub_component 27 | LIBRARY DESTINATION lib 28 | ) 29 | 30 | install(DIRECTORY 31 | launch 32 | DESTINATION share/${PROJECT_NAME} 33 | ) 34 | 35 | ament_package() 36 | -------------------------------------------------------------------------------- /learning_tf2_py/launch/turtle_tf2_demo_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | 4 | 5 | def generate_launch_description(): 6 | return LaunchDescription([ 7 | Node( 8 | package='turtlesim', 9 | executable='turtlesim_node', 10 | name='turtlesim_node' 11 | ), 12 | Node( 13 | package='learning_tf2_py', 14 | executable='turtle_tf2_broadcaster', 15 | name='turtle1_tf_bc', 16 | parameters=[ 17 | {'turtle_name': 'turtle1'} 18 | ] 19 | ), 20 | Node( 21 | package='learning_tf2_py', 22 | executable='turtle_tf2_broadcaster', 23 | name='turtle2_tf_bc', 24 | parameters=[ 25 | {'turtle_name': 'turtle2'} 26 | ] 27 | ), 28 | Node( 29 | package='learning_tf2_py', 30 | executable='turtle_tf2_listener', 31 | name='turtle_tf_ls', 32 | parameters=[ 33 | {'target_frame': 'turtle1'} 34 | ] 35 | ), 36 | ]) -------------------------------------------------------------------------------- /polygon_base/src/area_node.cpp: -------------------------------------------------------------------------------- 1 | #include "pluginlib/class_loader.hpp" 2 | #include "polygon_base/regular_polygon.hpp" 3 | 4 | int main(void) { 5 | pluginlib::ClassLoader polygon_loader("polygon_base", "polygon_base::RegularPolygon"); 6 | 7 | try { 8 | // "polygon_plugins::Square" 和 "polygon_plugins::EquilateralTriangle" 是插件的类名 9 | // 插件的类名信息来自插件的 plugins.xml ,在 polygon_plugins 包里面 10 | // polygon_plugins 使用 pluginlib_export_plugin_description_file(polygon_base plugins.xml) 把插件信息申明出来,运行时加载插件 11 | std::shared_ptr square = polygon_loader.createSharedInstance("polygon_plugins::Square"); 12 | square->init(1.0); 13 | printf("sauare area: %f\n", square->area()); 14 | 15 | std::shared_ptr equilateral_triangle = polygon_loader.createSharedInstance("polygon_plugins::EquilateralTriangle"); 16 | equilateral_triangle->init(1.0); 17 | printf("equilateral triangle area: %f\n", equilateral_triangle->area()); 18 | 19 | } catch (pluginlib::PluginlibException& ex) { 20 | printf("plugin failed to load: %s\n", ex.what()); 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /pubsub_py/pubsub_py/sub_diy_msg.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from diy_interface.msg import Student 8 | from diy_interface.msg import Sphere 9 | 10 | class Subscriber(Node): 11 | def __init__(self): 12 | super().__init__('test_sub_diy_msg') 13 | self._sub_student = self.create_subscription(Student, "student_topic", self.student_topic_callback, 10) 14 | self._sub_sphere = self.create_subscription(Sphere, "sphere_topic", self.sphere_topic_callback, 10) 15 | 16 | def student_topic_callback(self, msg): 17 | self.get_logger().info("i received student in python: {0}, {1}".format(msg.name, msg.age)) 18 | 19 | def sphere_topic_callback(self, msg): 20 | self.get_logger().info("i received sphere in python: ({0}, {1}, {2}), {3}".format(msg.center.x, msg.center.y, msg.center.z, msg.radius)) 21 | 22 | 23 | def main(args=None): 24 | rclpy.init(args=args) 25 | 26 | sub_node = Subscriber() 27 | rclpy.spin(sub_node) 28 | 29 | sub_node.destroy_node() 30 | rclpy.shutdown() 31 | 32 | 33 | if __name__ == '__main__': 34 | main() -------------------------------------------------------------------------------- /service_cpp/src/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rclcpp/rclcpp.hpp" 4 | #include "example_interfaces/srv/add_two_ints.hpp" 5 | 6 | class ServiceServer : public rclcpp::Node 7 | { 8 | public: 9 | ServiceServer() : Node("service_server") { 10 | server_ = this->create_service("add_two_ints", 11 | std::bind(&ServiceServer::add_callback, this, std::placeholders::_1, std::placeholders::_2)); 12 | } 13 | private: 14 | void add_callback(const std::shared_ptr request, 15 | std::shared_ptr response) { 16 | response->sum = request->a + request->b; 17 | RCLCPP_INFO(this->get_logger(), "cpp server: receive %ld(a) + %ld(b), send %ld(sum)", request->a, request->b, response->sum); 18 | } 19 | 20 | private: 21 | rclcpp::Service::SharedPtr server_; 22 | }; 23 | 24 | int main(int argc, char * argv[]) { 25 | rclcpp::init(argc, argv); 26 | rclcpp::spin(std::make_shared()); 27 | rclcpp::shutdown(); 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /learning_tf2_cpp/include/learning_tf2_cpp/turtle_tf_broadcaster.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LEARNING_TF2_CPP__TURTLE_TF_BROADCASTER_HPP_ 2 | #define LEARNING_TF2_CPP__TURTLE_TF_BROADCASTER_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "learning_tf2_cpp/visibility_control.h" 9 | 10 | #include "geometry_msgs/msg/transform_stamped.hpp" 11 | #include "rclcpp/rclcpp.hpp" 12 | #include "tf2/LinearMath/Quaternion.h" 13 | #include "tf2_ros/transform_broadcaster.h" 14 | #include "turtlesim/msg/pose.hpp" 15 | 16 | namespace learning_tf2_cpp 17 | { 18 | 19 | class TurtleTfBroadcaster : public rclcpp::Node 20 | { 21 | public: 22 | LEARNING_TF2_CPP_PUBLIC 23 | explicit TurtleTfBroadcaster(const rclcpp::NodeOptions & options); 24 | 25 | private: 26 | void handle_turtle_pose(const std::shared_ptr msg); 27 | 28 | private: 29 | rclcpp::Subscription::SharedPtr turtle_pose_sub_; 30 | std::unique_ptr tf_broadcaster_; 31 | std::string turtle_name_; 32 | }; 33 | 34 | 35 | 36 | } // namespace learning_tf2_cpp 37 | 38 | 39 | #endif // LEARNING_TF2_CPP__TURTLE_TF_BROADCASTER_HPP_ -------------------------------------------------------------------------------- /pubsub_cpp/src/publisher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rclcpp/rclcpp.hpp" 7 | #include "std_msgs/msg/string.hpp" 8 | 9 | class Publisher : public rclcpp::Node 10 | { 11 | public: 12 | Publisher() : Node("test_publisher"), count_(0) { 13 | publisher_ = this->create_publisher("hello_topic", 10); 14 | timer_ = this->create_wall_timer(std::chrono::seconds(1), std::bind(&Publisher::timer_callback, this)); 15 | } 16 | 17 | private: 18 | void timer_callback() { 19 | auto msg = std_msgs::msg::String(); 20 | msg.data = "hello, i am fine in cpp! " + std::to_string(count_++); 21 | RCLCPP_INFO(this->get_logger(), "publishing: %s", msg.data.c_str()); 22 | publisher_->publish(msg); 23 | } 24 | 25 | private: 26 | rclcpp::TimerBase::SharedPtr timer_; 27 | rclcpp::Publisher::SharedPtr publisher_; 28 | size_t count_; 29 | }; 30 | 31 | int main(int argc, char * argv[]) { 32 | rclcpp::init(argc, argv); 33 | rclcpp::spin(std::make_shared()); 34 | rclcpp::shutdown(); 35 | 36 | return 0; 37 | } -------------------------------------------------------------------------------- /service_mix/src/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rclcpp/rclcpp.hpp" 5 | #include "service_mix/srv/circle.hpp" 6 | 7 | class ServiceServer : public rclcpp::Node 8 | { 9 | public: 10 | ServiceServer() : Node("service_server") { 11 | server_ = this->create_service("circle", 12 | std::bind(&ServiceServer::area_callback, this, std::placeholders::_1, std::placeholders::_2)); 13 | } 14 | private: 15 | void area_callback(const std::shared_ptr request, 16 | std::shared_ptr response) { 17 | response->area = M_PI * request->radius * request->radius; 18 | RCLCPP_INFO(this->get_logger(), "[cpp server] receive radius: %u, return area: %lf", 19 | request->radius, response->area); 20 | } 21 | 22 | private: 23 | rclcpp::Service::SharedPtr server_; 24 | }; 25 | 26 | int main(int argc, char * argv[]) { 27 | rclcpp::init(argc, argv); 28 | rclcpp::spin(std::make_shared()); 29 | rclcpp::shutdown(); 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /webots_demo/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from setuptools import find_packages, setup 4 | 5 | package_name = 'webots_demo' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=find_packages(exclude=['test']), 11 | data_files=[ 12 | ('share/ament_index/resource_index/packages', 13 | ['resource/' + package_name]), 14 | ('share/' + package_name, ['package.xml']), 15 | (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*_launch.py'))), 16 | (os.path.join('share', package_name, 'worlds'), glob(os.path.join('worlds', '*.wbt'))), 17 | (os.path.join('share', package_name, 'resource'), glob(os.path.join('resource', '*.urdf'))) 18 | ], 19 | install_requires=['setuptools'], 20 | zip_safe=True, 21 | maintainer='ycao', 22 | maintainer_email='1641395022@qq.com', 23 | description='TODO: Package description', 24 | license='Apache-2.0', 25 | tests_require=['pytest'], 26 | entry_points={ 27 | 'console_scripts': [ 28 | 'mbot_driver = webots_demo.mbot_driver:main', 29 | 'obstacle_avoider = webots_demo.obstacle_avoider:main' 30 | ], 31 | }, 32 | ) 33 | -------------------------------------------------------------------------------- /pubsub_py/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from setuptools import find_packages, setup 4 | 5 | package_name = 'pubsub_py' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=find_packages(exclude=['test']), 11 | data_files=[ 12 | ('share/ament_index/resource_index/packages', 13 | ['resource/' + package_name]), 14 | ('share/' + package_name, ['package.xml']), 15 | (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*_launch.py'))) 16 | ], 17 | install_requires=['setuptools'], 18 | zip_safe=True, 19 | maintainer='ycao', 20 | maintainer_email='1641395022@qq.com', 21 | description='TODO: Package description', 22 | license='Apache-2.0', 23 | tests_require=['pytest'], 24 | entry_points={ 25 | 'console_scripts': [ 26 | 'talker = pubsub_py.publisher:main', 27 | 'talker_diy = pubsub_py.pub_diy_msg:main', 28 | 'listener = pubsub_py.subscriber:main', 29 | 'listener_diy = pubsub_py.sub_diy_msg:main', 30 | 'talker_qos = pubsub_py.pub_hello_qos:main', 31 | 'listener_qos = pubsub_py.sub_hello_qos:main' 32 | ], 33 | }, 34 | ) 35 | -------------------------------------------------------------------------------- /service_cpp/src/server_diy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rclcpp/rclcpp.hpp" 4 | #include "diy_interface/srv/question_and_answer.hpp" 5 | 6 | class ServiceServer : public rclcpp::Node 7 | { 8 | public: 9 | ServiceServer() : Node("service_server") { 10 | server_ = this->create_service("question_and_answer", 11 | std::bind(&ServiceServer::answer_callback, this, std::placeholders::_1, std::placeholders::_2)); 12 | } 13 | private: 14 | void answer_callback(const std::shared_ptr request, 15 | std::shared_ptr response) { 16 | response->answer = "I'm fine, thank you."; 17 | RCLCPP_INFO(this->get_logger(), "[cpp server] receive: %s, return: %s", 18 | request->question.c_str(), response->answer.c_str()); 19 | } 20 | 21 | private: 22 | rclcpp::Service::SharedPtr server_; 23 | }; 24 | 25 | int main(int argc, char * argv[]) { 26 | rclcpp::init(argc, argv); 27 | rclcpp::spin(std::make_shared()); 28 | rclcpp::shutdown(); 29 | 30 | return 0; 31 | } -------------------------------------------------------------------------------- /service_mix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(service_mix) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | # uncomment the following section in order to fill in 11 | # further dependencies manually. 12 | find_package(rosidl_default_generators REQUIRED) 13 | find_package(rclcpp REQUIRED) 14 | find_package(ament_cmake_python REQUIRED) 15 | 16 | set(srv_files 17 | "srv/Circle.srv" 18 | ) 19 | rosidl_generate_interfaces(${PROJECT_NAME} 20 | ${srv_files} 21 | ) 22 | 23 | ament_export_dependencies(rosidl_default_runtime) 24 | 25 | add_executable(server src/server.cpp) 26 | ament_target_dependencies(server rclcpp) 27 | rosidl_get_typesupport_target(cpp_typesupport_target 28 | ${PROJECT_NAME} rosidl_typesupport_cpp) 29 | target_link_libraries(server "${cpp_typesupport_target}") 30 | 31 | install(TARGETS 32 | server 33 | DESTINATION lib/${PROJECT_NAME}) 34 | 35 | install(DIRECTORY 36 | launch 37 | DESTINATION share/${PROJECT_NAME} 38 | ) 39 | 40 | install(PROGRAMS 41 | scripts/client.py 42 | DESTINATION lib/${PROJECT_NAME} 43 | ) 44 | 45 | ament_package() 46 | -------------------------------------------------------------------------------- /hello_ros2_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(hello_ros2_cpp) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | # uncomment the following section in order to fill in 11 | # further dependencies manually. 12 | # find_package( REQUIRED) 13 | find_package(rclcpp REQUIRED) 14 | 15 | add_executable(${PROJECT_NAME} src/hello_ros2.cpp) 16 | ament_target_dependencies(${PROJECT_NAME} rclcpp) 17 | 18 | install(TARGETS 19 | ${PROJECT_NAME} 20 | DESTINATION lib/${PROJECT_NAME}) 21 | 22 | if(BUILD_TESTING) 23 | find_package(ament_lint_auto REQUIRED) 24 | # the following line skips the linter which checks for copyrights 25 | # comment the line when a copyright and license is added to all source files 26 | set(ament_cmake_copyright_FOUND TRUE) 27 | # the following line skips cpplint (only works in a git repo) 28 | # comment the line when this package is in a git repo and when 29 | # a copyright and license is added to all source files 30 | set(ament_cmake_cpplint_FOUND TRUE) 31 | ament_lint_auto_find_test_dependencies() 32 | endif() 33 | 34 | ament_package() 35 | -------------------------------------------------------------------------------- /parameters_py/parameters_py/param_monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | from rcl_interfaces.msg import ParameterDescriptor, SetParametersResult 7 | 8 | class MiniParam(Node): 9 | def __init__(self, name): 10 | super().__init__(name) 11 | # set param description 12 | parameter_descriptor = ParameterDescriptor(description='This parameter is mine!') 13 | 14 | self.declare_parameter("demo_param", "set in python !!", parameter_descriptor) 15 | 16 | # Monitor updates to 'demo_param' 17 | self.add_on_set_parameters_callback(self.demo_param_change_callback) 18 | 19 | def demo_param_change_callback(self, params): 20 | result = SetParametersResult() # Create a result instance 21 | for param in params: 22 | if param.name == 'demo_param': 23 | self.get_logger().info(f'received an update to : {param.name}, type is {type(param.value).__name__}, value is {param.value}') 24 | result.successful = True 25 | return result 26 | 27 | def main(args=None): 28 | rclpy.init(args=args) 29 | node = MiniParam("param_monitor_py") 30 | rclpy.spin(node) 31 | 32 | if __name__ == '__main__': 33 | main() -------------------------------------------------------------------------------- /polygon_plugins/src/polygon_plugins.cpp: -------------------------------------------------------------------------------- 1 | #include "polygon_base/regular_polygon.hpp" 2 | #include 3 | 4 | namespace polygon_plugins { 5 | 6 | class Square : public polygon_base::RegularPolygon { 7 | public: 8 | void init(double side_length) override { 9 | side_length_ = side_length; 10 | } 11 | 12 | double area() override { 13 | return side_length_ * side_length_; 14 | } 15 | 16 | protected: 17 | double side_length_; 18 | }; 19 | 20 | class EquilateralTriangle : public polygon_base::RegularPolygon { 21 | public: 22 | void init(double side_length) override { 23 | side_length_ = side_length; 24 | } 25 | 26 | double getHight() { 27 | // or: side_length_ * sin(M_PI / 3); 28 | return side_length_ * sqrt(3) * 0 / 2; 29 | } 30 | 31 | double area() override { 32 | // or: side_length_ * side_length_ * sqrt(3) / 4; 33 | return side_length_ * getHight() * 0.5; 34 | } 35 | 36 | 37 | protected: 38 | double side_length_; 39 | }; 40 | 41 | } // namespace polygon_plugins 42 | 43 | #include "pluginlib/class_list_macros.hpp" 44 | 45 | PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon) 46 | PLUGINLIB_EXPORT_CLASS(polygon_plugins::EquilateralTriangle, polygon_base::RegularPolygon) -------------------------------------------------------------------------------- /learning_tf2_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(learning_tf2_cpp) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(geometry_msgs REQUIRED) 11 | find_package(rclcpp REQUIRED) 12 | find_package(rclcpp_components REQUIRED) 13 | find_package(tf2 REQUIRED) 14 | find_package(tf2_ros REQUIRED) 15 | find_package(turtlesim REQUIRED) 16 | 17 | include_directories(include) 18 | 19 | add_library(tf_broadcaster SHARED src/turtle_tf_broadcaster.cpp) 20 | ament_target_dependencies(tf_broadcaster rclcpp rclcpp_components tf2 tf2_ros turtlesim) 21 | rclcpp_components_register_nodes(tf_broadcaster "learning_tf2_cpp::TurtleTfBroadcaster") 22 | 23 | add_library(tf_listener SHARED src/turtle_tf_listener.cpp) 24 | ament_target_dependencies(tf_listener rclcpp rclcpp_components tf2 tf2_ros turtlesim) 25 | rclcpp_components_register_nodes(tf_listener "learning_tf2_cpp::TurtleTfListener") 26 | 27 | install(TARGETS 28 | tf_broadcaster 29 | tf_listener 30 | LIBRARY DESTINATION lib 31 | ) 32 | 33 | install(DIRECTORY 34 | launch 35 | config 36 | DESTINATION share/${PROJECT_NAME} 37 | ) 38 | 39 | 40 | 41 | ament_package() 42 | -------------------------------------------------------------------------------- /pubsub_mix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(pubsub_mix) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | # uncomment the following section in order to fill in 11 | # further dependencies manually. 12 | find_package(rosidl_default_generators REQUIRED) 13 | find_package(rclcpp REQUIRED) 14 | find_package(ament_cmake_python REQUIRED) 15 | 16 | set(msg_files 17 | "msg/AddressBook.msg" 18 | ) 19 | rosidl_generate_interfaces(${PROJECT_NAME} 20 | ${msg_files} 21 | ) 22 | 23 | ament_export_dependencies(rosidl_default_runtime) 24 | 25 | add_executable(publish_address_book src/publish_address_book.cpp) 26 | ament_target_dependencies(publish_address_book rclcpp) 27 | rosidl_get_typesupport_target(cpp_typesupport_target 28 | ${PROJECT_NAME} rosidl_typesupport_cpp) 29 | target_link_libraries(publish_address_book "${cpp_typesupport_target}") 30 | 31 | install(TARGETS 32 | publish_address_book 33 | DESTINATION lib/${PROJECT_NAME}) 34 | 35 | install(DIRECTORY 36 | launch 37 | DESTINATION share/${PROJECT_NAME} 38 | ) 39 | 40 | install(PROGRAMS 41 | scripts/subscribe_address_book.py 42 | DESTINATION lib/${PROJECT_NAME} 43 | ) 44 | 45 | ament_package() 46 | -------------------------------------------------------------------------------- /service_py/service_py/client_diy.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | import time 6 | from rclpy.node import Node 7 | 8 | from diy_interface.srv import QuestionAndAnswer 9 | 10 | class ServiceClient(Node): 11 | def __init__(self): 12 | super().__init__('service_client') 13 | self._client = self.create_client(QuestionAndAnswer, "question_and_answer") 14 | 15 | while not self._client.wait_for_service(timeout_sec=1.0): 16 | self.get_logger().info("service not available, waiting again...") 17 | 18 | def send_req(self, str): 19 | req = QuestionAndAnswer.Request() 20 | req.question = str 21 | future = self._client.call_async(req) 22 | rclpy.spin_until_future_complete(self, future) 23 | return future.result() 24 | 25 | def main(args=None): 26 | rclpy.init(args=args) 27 | 28 | client_node = ServiceClient() 29 | 30 | while True: 31 | str = "How do you feel?" 32 | response = client_node.send_req(str) 33 | client_node.get_logger().info("[python client] send: {0}, receive: {1}".format( 34 | str, response.answer)) 35 | time.sleep(1) 36 | 37 | client_node.destroy_node() 38 | rclpy.shutdown() 39 | 40 | if __name__ == '__main__': 41 | main() -------------------------------------------------------------------------------- /service_mix/scripts/client.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | import random 6 | import time 7 | from rclpy.node import Node 8 | 9 | from service_mix.srv import Circle 10 | 11 | class ServiceClient(Node): 12 | def __init__(self): 13 | super().__init__('service_client') 14 | self._client = self.create_client(Circle, "circle") 15 | 16 | while not self._client.wait_for_service(timeout_sec=1.0): 17 | self.get_logger().info("service not available, waiting again...") 18 | 19 | def send_req(self, pr): 20 | req = Circle.Request() 21 | req.radius = pr 22 | future = self._client.call_async(req) 23 | rclpy.spin_until_future_complete(self, future) 24 | return future.result() 25 | 26 | def main(args=None): 27 | rclpy.init(args=args) 28 | 29 | client_node = ServiceClient() 30 | 31 | while True: 32 | random.seed() 33 | radius = random.randint(0, 100) 34 | response = client_node.send_req(radius) 35 | client_node.get_logger().info("python client: send radius: {0}, receive area: {1}".format( 36 | radius, response.area)) 37 | time.sleep(1) 38 | 39 | client_node.destroy_node() 40 | rclpy.shutdown() 41 | 42 | if __name__ == '__main__': 43 | main() -------------------------------------------------------------------------------- /parameters_py/parameters_py/param_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | class MiniParam(Node): 8 | def __init__(self, name): 9 | super().__init__(name) 10 | # set param description 11 | from rcl_interfaces.msg import ParameterDescriptor 12 | parameter_descriptor = ParameterDescriptor(description='This parameter is mine!') 13 | # "set in python !!" will be cover by launch file: "set in launch !!" 14 | self.declare_parameter("demo_param", "set in python !!", parameter_descriptor) 15 | self._timer = self.create_timer(1, self.timer_cb) 16 | 17 | def timer_cb(self): 18 | my_param = self.get_parameter("demo_param").get_parameter_value().string_value 19 | self.get_logger().info("param: %s" % my_param) 20 | 21 | # Reset all parameters to prevent external modifications 22 | all_parameters = [] 23 | demo_param = rclpy.parameter.Parameter( 24 | 'demo_param', 25 | rclpy.Parameter.Type.STRING, 26 | 'set in python !!' 27 | ) 28 | all_parameters.append(demo_param) 29 | self.set_parameters(all_parameters) 30 | 31 | 32 | def main(args=None): 33 | rclpy.init(args=args) 34 | node = MiniParam("test_param_py") 35 | rclpy.spin(node) 36 | 37 | if __name__ == '__main__': 38 | main() -------------------------------------------------------------------------------- /pubsub_mix/src/publish_address_book.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rclcpp/rclcpp.hpp" 7 | #include "pubsub_mix/msg/address_book.hpp" 8 | 9 | class Publisher : public rclcpp::Node 10 | { 11 | public: 12 | Publisher() : Node("address_book_publisher"), count_(0) { 13 | publisher_ = this->create_publisher("address_book", 10); 14 | timer_ = this->create_wall_timer(std::chrono::seconds(1), std::bind(&Publisher::timer_callback, this)); 15 | } 16 | 17 | private: 18 | void timer_callback() { 19 | auto msg = pubsub_mix::msg::AddressBook(); 20 | msg.first_name = "yi"; 21 | msg.last_name = "cao"; 22 | msg.phone_number = "123456789"; 23 | msg.phone_type = msg.PHONE_TYPE_MOBILE; 24 | 25 | RCLCPP_INFO(this->get_logger(), "publishing in cpp: %s %s %s %d", 26 | msg.first_name.c_str(), msg.last_name.c_str(), msg.phone_number.c_str(), msg.phone_type); 27 | publisher_->publish(msg); 28 | } 29 | 30 | private: 31 | rclcpp::TimerBase::SharedPtr timer_; 32 | rclcpp::Publisher::SharedPtr publisher_; 33 | size_t count_; 34 | }; 35 | 36 | int main(int argc, char * argv[]) { 37 | rclcpp::init(argc, argv); 38 | rclcpp::spin(std::make_shared()); 39 | rclcpp::shutdown(); 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /service_py/service_py/client.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | import random 6 | import time 7 | from rclpy.node import Node 8 | 9 | from example_interfaces.srv import AddTwoInts 10 | 11 | class ServiceClient(Node): 12 | def __init__(self): 13 | super().__init__('service_client') 14 | self._client = self.create_client(AddTwoInts, "add_two_ints") 15 | 16 | while not self._client.wait_for_service(timeout_sec=1.0): 17 | self.get_logger().info("service not available, waiting again...") 18 | 19 | def send_req(self, a, b): 20 | req = AddTwoInts.Request() 21 | req.a = a 22 | req.b = b 23 | future = self._client.call_async(req) 24 | rclpy.spin_until_future_complete(self, future) 25 | return future.result() 26 | 27 | def main(args=None): 28 | rclpy.init(args=args) 29 | 30 | client_node = ServiceClient() 31 | 32 | while True: 33 | random.seed() 34 | a = random.randint(0, 2**31-1) 35 | b = random.randint(0, 2**31-1) 36 | response = client_node.send_req(a, b) 37 | client_node.get_logger().info("python client: send {0}(a) + {1}(b), receive {2}(sum)".format( 38 | a, b, response.sum)) 39 | time.sleep(1) 40 | 41 | client_node.destroy_node() 42 | rclpy.shutdown() 43 | 44 | if __name__ == '__main__': 45 | main() -------------------------------------------------------------------------------- /launch_example/launch_example/main_simple_launch.py: -------------------------------------------------------------------------------- 1 | from launch_ros.substitutions import FindPackageShare 2 | 3 | from launch import LaunchDescription 4 | from launch.actions import IncludeLaunchDescription 5 | from launch.launch_description_sources import PythonLaunchDescriptionSource 6 | from launch.substitutions import PathJoinSubstitution, TextSubstitution 7 | 8 | 9 | def generate_launch_description(): 10 | # 定义一个字典,包含背景颜色的红色值 11 | colors = { 12 | 'background_r': '240' 13 | } 14 | # Tips:launch 文件包含 15 | # 通过引用launch_example 包内的 launch 文件夹下的 substitution_launch.py 来启动 16 | return LaunchDescription([ 17 | IncludeLaunchDescription( 18 | PythonLaunchDescriptionSource([ 19 | PathJoinSubstitution([ 20 | FindPackageShare('launch_example'), 21 | 'launch_example', 22 | 'substitution_launch.py' 23 | ]) 24 | ]), 25 | # 创建一个字典,使用.items()获取字典的键值对组成的元组列表,向 substitution_launch.py 传递三个参数 26 | # TextSubstitution 是ROS 2 launch文件中的一个功能,它允许在launch过程中动态生成字符串 27 | # TextSubstitution 支持从环境变量中读取值,也支持将多个字符串拼接起来 28 | launch_arguments={ 29 | 'turtlesim_ns': 'turtlesim', 30 | 'use_provided_red': 'True', 31 | 'new_background_r': TextSubstitution(text=str(colors['background_r'])) 32 | }.items() 33 | ) 34 | ]) -------------------------------------------------------------------------------- /parameters_cpp/src/param_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "rclcpp/rclcpp.hpp" 6 | 7 | class MiniParam : public rclcpp::Node { 8 | public: 9 | MiniParam() : Node("test_param_cpp") { 10 | // set param description 11 | auto param_desc = rcl_interfaces::msg::ParameterDescriptor{}; 12 | param_desc.description = "This parameter is mine!"; 13 | // "set in cpp !!" will be cover by launch file: "set in launch !!" 14 | this->declare_parameter("demo_param", "set in cpp !!", param_desc); 15 | timer_ = this->create_wall_timer(std::chrono::seconds(1), std::bind(&MiniParam::timer_cb, this)); 16 | } 17 | 18 | void timer_cb() { 19 | std::string demo_param = this->get_parameter("demo_param").as_string(); 20 | RCLCPP_INFO(this->get_logger(), "demo_param: %s", demo_param.c_str()); 21 | 22 | // Reset all parameters to prevent external modifications 23 | std::vector all_parameters; 24 | all_parameters.push_back(rclcpp::Parameter("demo_param", "set in cpp !!")); 25 | this->set_parameters(all_parameters); 26 | } 27 | 28 | private: 29 | rclcpp::TimerBase::SharedPtr timer_; 30 | 31 | }; 32 | 33 | int main(int argc, char* argv[]) { 34 | rclcpp::init(argc, argv); 35 | 36 | rclcpp::spin(std::make_shared()); 37 | 38 | rclcpp::shutdown(); 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /learning_tf2_cpp/include/learning_tf2_cpp/turtle_tf_listener.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LEARNING_TF2_CPP__TURTLE_TF_LISTENER_HPP_ 2 | #define LEARNING_TF2_CPP__TURTLE_TF_LISTENER_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "learning_tf2_cpp/visibility_control.h" 9 | 10 | #include "geometry_msgs/msg/transform_stamped.hpp" 11 | #include "geometry_msgs/msg/twist.hpp" 12 | #include "turtlesim/srv/spawn.hpp" 13 | #include "rclcpp/rclcpp.hpp" 14 | #include "tf2_ros/transform_listener.h" 15 | #include "tf2_ros/buffer.h" 16 | #include "tf2/exceptions.h" 17 | 18 | 19 | namespace learning_tf2_cpp 20 | { 21 | 22 | class TurtleTfListener : public rclcpp::Node 23 | { 24 | public: 25 | LEARNING_TF2_CPP_PUBLIC 26 | explicit TurtleTfListener(const rclcpp::NodeOptions & options); 27 | 28 | private: 29 | void on_timer(); 30 | 31 | private: 32 | bool turtle_spawning_service_ready_ = false; 33 | bool turtle_spawned_ = false; 34 | 35 | std::string target_frame_; 36 | std::unique_ptr tf_buffer_; 37 | std::shared_ptr tf_listener_; 38 | 39 | rclcpp::Client::SharedPtr spawn_turtle_client_; 40 | rclcpp::Publisher::SharedPtr turtle_cmd_pub_; 41 | rclcpp::TimerBase::SharedPtr timer_; 42 | }; 43 | 44 | 45 | 46 | } // namespace learning_tf2_cpp 47 | 48 | 49 | #endif // LEARNING_TF2_CPP__TURTLE_TF_LISTENER_HPP_ -------------------------------------------------------------------------------- /component_demo/launch/separate_node_launch.py: -------------------------------------------------------------------------------- 1 | import launch 2 | from launch_ros.actions import ComposableNodeContainer 3 | from launch_ros.descriptions import ComposableNode 4 | 5 | 6 | def generate_launch_description(): 7 | # 两个组件放在两个 container 里,也就是分别在两个进程,这种状况比较容易排查问题,当然负载也要高一些 8 | # 通常情况下,开发阶段使用这种方式,生产环境使用合并进程的方式 9 | pub_container = ComposableNodeContainer( 10 | name='pub_container', 11 | namespace='', 12 | package='rclcpp_components', 13 | # component_container_mt 14 | executable='component_container', 15 | composable_node_descriptions=[ 16 | ComposableNode( 17 | package='component_demo', 18 | plugin='component_demo::PubComponent', 19 | name='pub_component') 20 | ], 21 | output='screen', 22 | ) 23 | 24 | sub_container = ComposableNodeContainer( 25 | name='sub_container', 26 | namespace='', 27 | package='rclcpp_components', 28 | executable='component_container', 29 | composable_node_descriptions=[ 30 | ComposableNode( 31 | package='component_demo', 32 | plugin='component_demo::SubComponent', 33 | name='sub_component') 34 | ], 35 | output='screen', 36 | ) 37 | 38 | return launch.LaunchDescription([pub_container, sub_container]) -------------------------------------------------------------------------------- /pubsub_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(pubsub_cpp) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | # uncomment the following section in order to fill in 11 | # further dependencies manually. 12 | find_package(rclcpp REQUIRED) 13 | find_package(std_msgs REQUIRED) 14 | find_package(diy_interface REQUIRED) 15 | 16 | add_executable(talker src/publisher.cpp) 17 | ament_target_dependencies(talker rclcpp std_msgs) 18 | 19 | add_executable(listener src/subscriber.cpp) 20 | ament_target_dependencies(listener rclcpp std_msgs) 21 | 22 | add_executable(talker_qos src/pub_hello_qos.cpp) 23 | ament_target_dependencies(talker_qos rclcpp std_msgs) 24 | 25 | add_executable(listener_qos src/sub_hello_qos.cpp) 26 | ament_target_dependencies(listener_qos rclcpp std_msgs) 27 | 28 | add_executable(talker_diy src/pub_diy_msg.cpp) 29 | ament_target_dependencies(talker_diy rclcpp diy_interface) 30 | 31 | add_executable(listener_diy src/sub_diy_msg.cpp) 32 | ament_target_dependencies(listener_diy rclcpp diy_interface) 33 | 34 | 35 | install(TARGETS 36 | talker 37 | listener 38 | talker_qos 39 | listener_qos 40 | talker_diy 41 | listener_diy 42 | DESTINATION lib/${PROJECT_NAME}) 43 | 44 | install(DIRECTORY 45 | launch 46 | DESTINATION share/${PROJECT_NAME} 47 | ) 48 | 49 | ament_package() 50 | -------------------------------------------------------------------------------- /action_py/action_py/fibonacci_server.py: -------------------------------------------------------------------------------- 1 | import time 2 | import rclpy 3 | from rclpy.action import ActionServer 4 | from rclpy.node import Node 5 | from diy_interface.action import Fibonacci 6 | 7 | class FibonacciActionServer(Node): 8 | def __init__(self): 9 | super().__init__('fibonacci_action_server') 10 | self._action_server = ActionServer( 11 | self, 12 | Fibonacci, 13 | 'fibonacci', 14 | self.execute_callback) 15 | 16 | def execute_callback(self, goal_handle): 17 | self.get_logger().info("executing goal...") 18 | 19 | feedback_msg = Fibonacci.Feedback() 20 | feedback_msg.partial_sequence = [0, 1] 21 | 22 | for i in range(1, goal_handle.request.order): 23 | feedback_msg.partial_sequence.append( 24 | feedback_msg.partial_sequence[i] + feedback_msg.partial_sequence[i-1]) 25 | goal_handle.publish_feedback(feedback_msg) 26 | self.get_logger().info("pub feedback") 27 | time.sleep(1) 28 | 29 | goal_handle.succeed() 30 | result = Fibonacci.Result() 31 | result.sequence = feedback_msg.partial_sequence 32 | return result 33 | 34 | def main(args=None): 35 | rclpy.init(args=args) 36 | 37 | fibonacci_action_server = FibonacciActionServer() 38 | rclpy.spin(fibonacci_action_server) 39 | 40 | fibonacci_action_server.destroy_node() 41 | rclpy.shutdown() 42 | 43 | 44 | 45 | if __name__ == '__main__': 46 | main() -------------------------------------------------------------------------------- /component_demo/include/component_demo/visibility_control.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPONENT_DEMO__VISIBILITY_CONTROL_H_ 2 | #define COMPONENT_DEMO__VISIBILITY_CONTROL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | // This logic was borrowed (then namespaced) from the examples on the gcc wiki: 10 | // https://gcc.gnu.org/wiki/Visibility 11 | 12 | #if defined _WIN32 || defined __CYGWIN__ 13 | #ifdef __GNUC__ 14 | #define COMPONENT_DEMO_EXPORT __attribute__ ((dllexport)) 15 | #define COMPONENT_DEMO_IMPORT __attribute__ ((dllimport)) 16 | #else 17 | #define COMPONENT_DEMO_EXPORT __declspec(dllexport) 18 | #define COMPONENT_DEMO_IMPORT __declspec(dllimport) 19 | #endif 20 | #ifdef COMPONENT_DEMO_BUILDING_DLL 21 | #define COMPONENT_DEMO_PUBLIC COMPONENT_DEMO_EXPORT 22 | #else 23 | #define COMPONENT_DEMO_PUBLIC COMPONENT_DEMO_IMPORT 24 | #endif 25 | #define COMPONENT_DEMO_PUBLIC_TYPE COMPONENT_DEMO_PUBLIC 26 | #define COMPONENT_DEMO_LOCAL 27 | #else 28 | #define COMPONENT_DEMO_EXPORT __attribute__ ((visibility("default"))) 29 | #define COMPONENT_DEMO_IMPORT 30 | #if __GNUC__ >= 4 31 | #define COMPONENT_DEMO_PUBLIC __attribute__ ((visibility("default"))) 32 | #define COMPONENT_DEMO_LOCAL __attribute__ ((visibility("hidden"))) 33 | #else 34 | #define COMPONENT_DEMO_PUBLIC 35 | #define COMPONENT_DEMO_LOCAL 36 | #endif 37 | #define COMPONENT_DEMO_PUBLIC_TYPE 38 | #endif 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif // COMPONENT_DEMO__VISIBILITY_CONTROL_H_ 45 | -------------------------------------------------------------------------------- /pubsub_cpp/src/sub_diy_msg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rclcpp/rclcpp.hpp" 4 | #include "diy_interface/msg/student.hpp" 5 | #include "diy_interface/msg/sphere.hpp" 6 | 7 | class Subscriber : public rclcpp::Node 8 | { 9 | public: 10 | Subscriber() : Node("test_sub_diy_msg") { 11 | sub_student_ = this->create_subscription( 12 | "student_topic", 10, std::bind(&Subscriber::student_topic_callback, this, std::placeholders::_1)); 13 | sub_sphere_ = this->create_subscription( 14 | "sphere_topic", 10, std::bind(&Subscriber::sphere_topic_callback, this, std::placeholders::_1)); 15 | } 16 | 17 | private: 18 | void student_topic_callback(const diy_interface::msg::Student &msg) const { 19 | RCLCPP_INFO(this->get_logger(), "i received student in cpp: %s, %d", msg.name.c_str(), msg.age); 20 | } 21 | void sphere_topic_callback(const diy_interface::msg::Sphere &msg) const { 22 | RCLCPP_INFO(this->get_logger(), "i received sphere in cpp: (%f, %f, %f), %f", 23 | msg.center.x, msg.center.y, msg.center.z, msg.radius); 24 | } 25 | 26 | private: 27 | rclcpp::Subscription::SharedPtr sub_student_; 28 | rclcpp::Subscription::SharedPtr sub_sphere_; 29 | }; 30 | 31 | 32 | int main(int argc, char * argv[]) { 33 | rclcpp::init(argc, argv); 34 | rclcpp::spin(std::make_shared()); 35 | rclcpp::shutdown(); 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /learning_tf2_cpp/include/learning_tf2_cpp/visibility_control.h: -------------------------------------------------------------------------------- 1 | #ifndef LEARNING_TF2_CPP__VISIBILITY_CONTROL_H_ 2 | #define LEARNING_TF2_CPP__VISIBILITY_CONTROL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | // This logic was borrowed (then namespaced) from the examples on the gcc wiki: 10 | // https://gcc.gnu.org/wiki/Visibility 11 | 12 | #if defined _WIN32 || defined __CYGWIN__ 13 | #ifdef __GNUC__ 14 | #define LEARNING_TF2_CPP_EXPORT __attribute__ ((dllexport)) 15 | #define LEARNING_TF2_CPP_IMPORT __attribute__ ((dllimport)) 16 | #else 17 | #define LEARNING_TF2_CPP_EXPORT __declspec(dllexport) 18 | #define LEARNING_TF2_CPP_IMPORT __declspec(dllimport) 19 | #endif 20 | #ifdef LEARNING_TF2_CPP_BUILDING_DLL 21 | #define LEARNING_TF2_CPP_PUBLIC LEARNING_TF2_CPP_EXPORT 22 | #else 23 | #define LEARNING_TF2_CPP_PUBLIC LEARNING_TF2_CPP_IMPORT 24 | #endif 25 | #define LEARNING_TF2_CPP_PUBLIC_TYPE LEARNING_TF2_CPP_PUBLIC 26 | #define LEARNING_TF2_CPP_LOCAL 27 | #else 28 | #define LEARNING_TF2_CPP_EXPORT __attribute__ ((visibility("default"))) 29 | #define LEARNING_TF2_CPP_IMPORT 30 | #if __GNUC__ >= 4 31 | #define LEARNING_TF2_CPP_PUBLIC __attribute__ ((visibility("default"))) 32 | #define LEARNING_TF2_CPP_LOCAL __attribute__ ((visibility("hidden"))) 33 | #else 34 | #define LEARNING_TF2_CPP_PUBLIC 35 | #define LEARNING_TF2_CPP_LOCAL 36 | #endif 37 | #define LEARNING_TF2_CPP_PUBLIC_TYPE 38 | #endif 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif // LEARNING_TF2_CPP__VISIBILITY_CONTROL_H_ 45 | -------------------------------------------------------------------------------- /webots_demo/webots_demo/obstacle_avoider.py: -------------------------------------------------------------------------------- 1 | import rclpy 2 | from rclpy.node import Node 3 | from sensor_msgs.msg import Range 4 | from geometry_msgs.msg import Twist 5 | 6 | MAX_RANGE = 0.15 7 | 8 | # ObstacleAvoider 是机器人行动的控制程序,主要是避障,防止机器人撞墙 9 | # 他创建了一个 ros2 节点 obstacle_avoider,订阅了两个传感器话题 left_sensor 和 right_sensor, 10 | # 接收 Range 消息,然后根据传感器的距离,通过 cmd_vel 发给 mbot_driver 控制机器人运动 11 | class ObstacleAvoider(Node): 12 | def __init__(self): 13 | super().__init__('obstacle_avoider') 14 | 15 | self._publisher = self.create_publisher(Twist, 'cmd_vel', 1) 16 | 17 | self.create_subscription(Range, 'left_sensor', self._left_sensor_callback, 1) 18 | self.create_subscription(Range, 'right_sensor', self._right_sensor_callback, 1) 19 | 20 | def _left_sensor_callback(self, message): 21 | self._left_sensor_value = message.range 22 | 23 | def _right_sensor_callback(self, message): 24 | self._right_sensor_value = message.range 25 | 26 | # 每次收到一个传感器的数据,就计算一次机器人的运动控制 27 | command_message = Twist() 28 | command_message.linear.x = 0.1 29 | # 如果左右传感器的距离有一个小于 0.9 * MAX_RANGE,就让机器人向顺时针向右转,否则默认为0,即直线行驶 30 | if self._left_sensor_value < 0.9 * MAX_RANGE or self._right_sensor_value < 0.9 * MAX_RANGE: 31 | command_message.angular.z = -2.0 32 | 33 | self._publisher.publish(command_message) 34 | 35 | 36 | def main(args=None): 37 | rclpy.init(args=args) 38 | avoider = ObstacleAvoider() 39 | rclpy.spin(avoider) 40 | avoider.destroy_node() 41 | rclpy.shutdown() 42 | 43 | 44 | if __name__ == '__main__': 45 | main() -------------------------------------------------------------------------------- /component_demo/launch/merge_node_launch.py: -------------------------------------------------------------------------------- 1 | import launch 2 | from launch_ros.actions import ComposableNodeContainer 3 | from launch_ros.descriptions import ComposableNode 4 | 5 | 6 | def generate_launch_description(): 7 | # 两个组件放在一个 container 里,也就是共享一个进程,可以降低负载 8 | # 通常情况下,开发阶段使用分开进程的方式,生产环境使用这种方式 9 | container = ComposableNodeContainer( 10 | name='my_container', 11 | namespace='', 12 | package='rclcpp_components', 13 | # component_container 是单线程容器,容器内所有组件共享一个线程,没有并发问题,但是效率低 14 | # component_container_mt 是多线程容器,容器内每个组件都有自己的线程,可以并发处理,效率高,但需要考虑并发风险 15 | executable='component_container', 16 | composable_node_descriptions=[ 17 | ComposableNode( 18 | package='component_demo', 19 | plugin='component_demo::PubComponent', 20 | name='pub_component', 21 | # 尽管多个组件合并在同一个进程,ros2 也是默认走 DDS 中间件通信 22 | # 下面的参数,可以设置组件之间通过 intra-process 通信 23 | # 理论上,intra-process 直接传递指针,效率更高 24 | # 但是本样例太小了,实际测试无法看出使用 intra-process 的优势 25 | extra_arguments=[{'use_intra_process_comms': True}] 26 | ), 27 | ComposableNode( 28 | package='component_demo', 29 | plugin='component_demo::SubComponent', 30 | name='sub_component', 31 | # 接收端也要配置 intra-process 32 | extra_arguments=[{'use_intra_process_comms': True}] 33 | ) 34 | ], 35 | output='screen', 36 | ) 37 | 38 | return launch.LaunchDescription([container]) -------------------------------------------------------------------------------- /webots_demo/launch/mbot_launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | import launch 3 | from launch_ros.actions import Node 4 | from launch import LaunchDescription 5 | from ament_index_python.packages import get_package_share_directory 6 | from webots_ros2_driver.webots_launcher import WebotsLauncher 7 | from webots_ros2_driver.webots_controller import WebotsController 8 | 9 | 10 | def generate_launch_description(): 11 | package_dir = get_package_share_directory('webots_demo') 12 | mbot_description_path = os.path.join(package_dir, 'resource', 'mbot.urdf') 13 | 14 | # 使用 webots_ros2_driver.webots_launcher.WebotsLauncher 来启动 webots,加载 my_world.wbt 15 | # my_world.wbt 内有一个 mbot_car 机器人 16 | # 补充:如何制作 my_world.wbt,可以参考: 17 | # https://cyberbotics.com/doc/guide/tutorials 18 | webots_world = WebotsLauncher( 19 | world=os.path.join(package_dir, 'worlds', 'my_world.wbt') 20 | ) 21 | 22 | # 使用 webots_ros2_driver.webots_controller.WebotsController 来启动 mbot_car 机器人的控制器 23 | # 参数 robot_description 为 mbot.urdf,里面指定了 webots_demo.mbot_driver.MbotDriver 为机器人的控制器 24 | mbot_controller = WebotsController( 25 | robot_name='mbot_car', 26 | parameters=[ 27 | {'robot_description': mbot_description_path}, 28 | ], 29 | ) 30 | 31 | # 额外启动一个避障控制器,订阅 mbot_car 发来的左右距离传感器数据,通过 cmd_vel,控制 mbot_car 机器人的运动 32 | obstacle_avoider = Node( 33 | package='webots_demo', 34 | executable='obstacle_avoider', 35 | ) 36 | 37 | return LaunchDescription([ 38 | webots_world, 39 | mbot_controller, 40 | obstacle_avoider, 41 | launch.actions.RegisterEventHandler( 42 | event_handler=launch.event_handlers.OnProcessExit( 43 | target_action=webots_world, 44 | on_exit=[launch.actions.EmitEvent(event=launch.events.Shutdown())], 45 | ) 46 | ) 47 | ]) -------------------------------------------------------------------------------- /launch_example/launch_example/turtlesim_mimic_launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | from launch.actions import ExecuteProcess, TimerAction 4 | 5 | def generate_launch_description(): 6 | return LaunchDescription([ 7 | # 默认命名空间是 /, 但是这里的命名空间是 turtlesim1 8 | # 因此所有的计算图源名称都会带上/turtlesim1,例如: 9 | # 节点名:/turtlesim1/sim 10 | # topic名: /turtlesim1/turtle1/cmd_vel,/turtlesim1/turtle1/pose 11 | Node( 12 | package='turtlesim', 13 | namespace='turtlesim1', 14 | executable='turtlesim_node', 15 | name='sim' 16 | ), 17 | # 同上 18 | Node( 19 | package='turtlesim', 20 | namespace='turtlesim2', 21 | executable='turtlesim_node', 22 | name='sim' 23 | ), 24 | # remap后,mimic 节点会订阅 /turtlesim1/turtle1/pose 话题, 25 | # 处理后发布 /turtlesim2/turtle1/cmd_vel 话题,从而实现两个乌龟的同步运动 26 | Node( 27 | package='turtlesim', 28 | executable='mimic', 29 | name='mimic', 30 | remappings=[ 31 | ('/input/pose', '/turtlesim1/turtle1/pose'), 32 | ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'), 33 | ] 34 | ), 35 | # 延迟5秒,启动一个额外命令,向 /turtlesim1/sim 发送转圈控制命令,让乌龟1转圈,乌龟2会跟随 36 | TimerAction( 37 | period=5.0, 38 | actions=[ 39 | ExecuteProcess( 40 | cmd=[ 41 | 'ros2', 'topic', 'pub', '-r', '1', 42 | '/turtlesim1/turtle1/cmd_vel', 'geometry_msgs/msg/Twist', 43 | '{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}' 44 | ], 45 | output='screen' 46 | ) 47 | ] 48 | ) 49 | 50 | ]) -------------------------------------------------------------------------------- /parameters_cpp/src/param_monitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "rclcpp/rclcpp.hpp" 6 | 7 | class MiniParam : public rclcpp::Node { 8 | public: 9 | MiniParam() : Node("param_monitor_cpp") { 10 | // set param description 11 | auto param_desc = rcl_interfaces::msg::ParameterDescriptor{}; 12 | param_desc.description = "This parameter is mine!"; 13 | this->declare_parameter("demo_param", "set in cpp !!", param_desc); 14 | 15 | // used to monitor parameter changes 16 | param_sub_ = std::make_shared(this); 17 | // 监测本节点的参数变化 18 | demo_param_change_cb_ = param_sub_->add_parameter_callback("demo_param", 19 | [this](const rclcpp::Parameter &p) { 20 | RCLCPP_INFO(this->get_logger(), "received an update to : %s , type is %s, value is %s", 21 | p.get_name().c_str(), 22 | p.get_type_name().c_str(), 23 | p.as_string().c_str()); 24 | }); 25 | // 监测其他节点的参数变化 26 | turtlesim_node_background_b_change_cb_ = param_sub_->add_parameter_callback("background_b", 27 | [this](const rclcpp::Parameter &p) { 28 | RCLCPP_INFO(this->get_logger(), "received an update to : %s , type is %s, value is %ld", 29 | p.get_name().c_str(), 30 | p.get_type_name().c_str(), 31 | p.as_int()); 32 | }, "/turtlesim_node"); 33 | } 34 | 35 | private: 36 | std::shared_ptr param_sub_; 37 | std::shared_ptr demo_param_change_cb_; 38 | std::shared_ptr turtlesim_node_background_b_change_cb_; 39 | }; 40 | 41 | int main(int argc, char* argv[]) { 42 | rclcpp::init(argc, argv); 43 | 44 | rclcpp::spin(std::make_shared()); 45 | 46 | rclcpp::shutdown(); 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /pubsub_py/pubsub_py/sub_hello_qos.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from std_msgs.msg import String 8 | from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy, QoSDurabilityPolicy, LivelinessPolicy 9 | from rclpy.duration import Duration 10 | from time import sleep 11 | 12 | class Subscriber(Node): 13 | def __init__(self): 14 | super().__init__('test_qos_subscriber') 15 | 16 | qos_profile = QoSProfile( 17 | # RELIABLE(default), BEST_EFFORT 18 | reliability = QoSReliabilityPolicy.RELIABLE, 19 | # VOLATILE(default) 20 | # TRANSIENT_LOCAL(Only works when reliability is RELIABLE and needs history:KEEP_LAST and depth) 21 | durability=QoSDurabilityPolicy.TRANSIENT_LOCAL, 22 | # history: only works when reliability is RELIABLE 23 | # KEEP_LAST(default), KEEP_ALL 24 | history = QoSHistoryPolicy.KEEP_LAST, 25 | # default is 10 26 | depth=10, 27 | # default is Infinite 28 | lifespan=Duration(seconds=5), 29 | 30 | # default is Infinite 31 | deadline=Duration(seconds=5, nanoseconds=0), 32 | # AUTOMATIC(default), MANUAL_BY_TOPIC 33 | liveliness=LivelinessPolicy.AUTOMATIC, 34 | # default is Infinite 35 | liveliness_lease_duration=Duration(seconds=5) 36 | ) 37 | 38 | self._subscriber = self.create_subscription(String, "hello_topic", self.topic_callback, qos_profile) 39 | 40 | def topic_callback(self, msg): 41 | self.get_logger().info("subscribe: %s" % msg.data) 42 | # sleep(2) # test qos history and depth parameters 43 | 44 | 45 | def main(args=None): 46 | rclpy.init(args=args) 47 | 48 | sub_node = Subscriber() 49 | rclpy.spin(sub_node) 50 | 51 | sub_node.destroy_node() 52 | rclpy.shutdown() 53 | 54 | 55 | if __name__ == '__main__': 56 | main() -------------------------------------------------------------------------------- /action_py/action_py/fibonacci_client.py: -------------------------------------------------------------------------------- 1 | import rclpy 2 | from rclpy.action import ActionClient 3 | from rclpy.node import Node 4 | 5 | from diy_interface.action import Fibonacci 6 | 7 | class FibonacciActionClient(Node): 8 | def __init__(self): 9 | super().__init__('fibonacci_action_client') 10 | self._action_client = ActionClient(self, Fibonacci, 'fibonacci') 11 | 12 | def send_goal(self, order): 13 | goal_msg = Fibonacci.Goal() 14 | goal_msg.order = order 15 | self._action_client.wait_for_server() 16 | 17 | send_goal_future = self._action_client.send_goal_async(goal_msg, 18 | feedback_callback=self.feedback_callback) 19 | send_goal_future.add_done_callback(self.goal_response_callback) 20 | self.get_logger().info('Sent goal request: {0}'.format(order)) 21 | 22 | def feedback_callback(self, feedback_msg): 23 | feedback = feedback_msg.feedback 24 | self.get_logger().info('Received feedback: {0}'.format(feedback.partial_sequence)) 25 | 26 | def goal_response_callback(self, future): 27 | goal_handle = future.result() 28 | if not goal_handle.accepted: 29 | self.get_logger().info("goal rejected :(") 30 | return 31 | 32 | self.get_logger().info("goal accepted :)") 33 | 34 | get_result_future = goal_handle.get_result_async() 35 | get_result_future.add_done_callback(self.get_result_callback) 36 | 37 | def get_result_callback(self, future): 38 | result = future.result().result 39 | self.get_logger().info('Result: {0}'.format(result.sequence)) 40 | rclpy.shutdown() 41 | 42 | def main(args=None): 43 | rclpy.init(args=args) 44 | 45 | fibonacci_action_client = FibonacciActionClient() 46 | fibonacci_action_client.send_goal(10) 47 | 48 | rclpy.spin(fibonacci_action_client) 49 | 50 | fibonacci_action_client.destroy_node() 51 | rclpy.shutdown() 52 | 53 | 54 | 55 | if __name__ == '__main__': 56 | main() -------------------------------------------------------------------------------- /pubsub_py/pubsub_py/pub_diy_msg.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from diy_interface.msg import Student 8 | from diy_interface.msg import Sphere 9 | 10 | class Publisher(Node): 11 | def __init__(self): 12 | super().__init__('test_pub_diy_msg') 13 | self._pub_student = self.create_publisher(Student, "student_topic", 10) 14 | self._pub_sphere = self.create_publisher(Sphere, "Sphere_topic", 10) 15 | self._timer = self.create_timer(0.5, self.timer_callback) 16 | self._i = 0 17 | 18 | self._students = [ 19 | ("yi", 32), 20 | ("miao", 18), 21 | ("bao", 3) 22 | ] 23 | self._spheres = [ 24 | ((1.0, 2.0, 3.0), 4.0), 25 | ((1.1, 2.1, 3.1), 4.1) 26 | ] 27 | 28 | def timer_callback(self): 29 | stu_msg = Student() 30 | stu_msg.name = self._students[self._i % len(self._students)][0] 31 | stu_msg.age = self._students[self._i % len(self._students)][1] 32 | self.get_logger().info("Publishing student in python: {0}, {1}".format(stu_msg.name, stu_msg.age)) 33 | self._pub_student.publish(stu_msg) 34 | 35 | sph_msg = Sphere() 36 | sph_msg.center.x = self._spheres[self._i % len(self._spheres)][0][0] 37 | sph_msg.center.y = self._spheres[self._i % len(self._spheres)][0][1] 38 | sph_msg.center.z = self._spheres[self._i % len(self._spheres)][0][2] 39 | sph_msg.radius = self._spheres[self._i % len(self._spheres)][1] 40 | self.get_logger().info("Publishing sphere in python: ({0}, {1}, {2}), {3}".format(sph_msg.center.x, sph_msg.center.y, sph_msg.center.z, sph_msg.radius)) 41 | self._pub_sphere.publish(sph_msg) 42 | 43 | self._i += 1 44 | 45 | 46 | def main(args=None): 47 | rclpy.init(args=args) 48 | 49 | pub_node = Publisher() 50 | rclpy.spin(pub_node) 51 | 52 | pub_node.destroy_node() 53 | rclpy.shutdown() 54 | 55 | if __name__ == '__main__': 56 | main() -------------------------------------------------------------------------------- /component_demo/src/pub_component.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rclcpp/rclcpp.hpp" 7 | #include "std_msgs/msg/string.hpp" 8 | #include "component_demo/pub_component.hpp" 9 | 10 | #include "rclcpp_components/register_node_macro.hpp" 11 | RCLCPP_COMPONENTS_REGISTER_NODE(component_demo::PubComponent) 12 | 13 | namespace component_demo 14 | { 15 | 16 | PubComponent::PubComponent(const rclcpp::NodeOptions & options) 17 | : Node("pub_component", options), count_(0) { 18 | msg_inner_ = "从前有位程序员,名叫杰克。杰克在一家知名科技公司工作,以出神入化的编程技巧而闻名。" 19 | "可即便是杰克,也有他的死穴—他没有咖啡就无法编码。" 20 | "某天早上,杰克来到了办公室,兴冲冲地准备开始新的一天。" 21 | "他按下了咖啡机的开关,却发现这台终年不离不弃的老伙计竟然罢工了!" 22 | "杰克惊慌失措,因为他知道没有咖啡,他的大脑就像没有安装操作系统的电脑一样毫无用处。" 23 | "需要紧急解决方案!于是他做了什么每个程序员在遇到问题时都会做的事——Google搜索“没有咖啡如何生存”。" 24 | "成百上千的建议涌现在屏幕上,但都不对味。就在此时,他注意到了一篇奇怪的文章,标题是:“用代码唤醒你的大脑”。" 25 | "这篇文章提到了一种传说中的编程技术,可以让程序员通过编写代码来生成身体所需的能量。" 26 | "虽然看起来很荒谬,但杰克决定尝试一下。" 27 | "他迅速打开了他的编程环境,并开始编写一些非常复杂的函数。" 28 | "随着每一个键击,他能感觉到一股虚拟的“能量”在体内流淌。" 29 | "一小时后,杰克完成了他的作品,一个模拟咖啡因分子结构的程序。" 30 | "他按下运行键,闭上眼睛,希望奇迹发生。" 31 | "几秒钟后,他睁开眼睛,感觉... 完全一样。" 32 | "显然,代码并不能真正取代咖啡。" 33 | "杰克失望极了,但他还是决定去办公楼下的咖啡店买一杯咖啡来解决问题。。。。"; 34 | pub_msg_ = create_publisher("hello_msg", 10); 35 | // 帧率设置为 200 hz,较高的帧率,可以比较明显的看出合并进程与分离进程负载的变化 36 | timer_ = create_wall_timer(std::chrono::milliseconds(5), std::bind(&PubComponent::on_timer, this)); 37 | } 38 | 39 | void PubComponent::on_timer() { 40 | // 如果想使用 ros2 的 intra-process 通信,最好使用 unique_ptr,然后发送时使用std::move()转移所有权 41 | // 这种方式可以明确告诉 ros2 , 这个消息你拥有唯一的所有权,可以使用 intra-process 直接传递指针进行通信 42 | auto msg = std::make_unique(); 43 | msg->data = msg_inner_ + std::to_string(++count_); 44 | pub_msg_->publish(std::move(msg)); 45 | } 46 | 47 | 48 | } // namespace component_demo -------------------------------------------------------------------------------- /service_cpp/src/client_diy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rclcpp/rclcpp.hpp" 5 | #include "diy_interface/srv/question_and_answer.hpp" 6 | 7 | class ServiceClient : public rclcpp::Node 8 | { 9 | public: 10 | ServiceClient() : Node("service_client") { 11 | client_ = this->create_client("question_and_answer"); 12 | } 13 | 14 | int init() { 15 | while (!client_->wait_for_service(std::chrono::seconds(1))) { 16 | if (!rclcpp::ok()) { 17 | RCLCPP_ERROR(this->get_logger(), "Interrupted while waiting for the service. Exiting."); 18 | return 0; 19 | } 20 | RCLCPP_INFO(this->get_logger(), "service not available, waiting again..."); 21 | } 22 | return 0; 23 | } 24 | 25 | void run(const std::string &str) { 26 | auto request = std::make_shared(); 27 | request->question = str; 28 | 29 | auto result = client_->async_send_request(request); 30 | if (rclcpp::spin_until_future_complete(this->get_node_base_interface(), result) == 31 | rclcpp::FutureReturnCode::SUCCESS) { 32 | RCLCPP_INFO(this->get_logger(), "[cpp client] send: %s, receive: %s", 33 | request->question.c_str(), result.get()->answer.c_str()); 34 | } else { 35 | RCLCPP_ERROR(this->get_logger(), "Failed to call service add_two_ints"); 36 | } 37 | } 38 | 39 | private: 40 | rclcpp::Client::SharedPtr client_; 41 | }; 42 | 43 | int main(int argc, char * argv[]) { 44 | rclcpp::init(argc, argv); 45 | auto node = std::make_shared(); 46 | node->init(); 47 | while (rclcpp::ok()) { 48 | std::string str = "how are you?"; 49 | node->run(str); 50 | std::this_thread::sleep_for(std::chrono::seconds(1)); 51 | } 52 | 53 | rclcpp::shutdown(); 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /service_cpp/src/client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rclcpp/rclcpp.hpp" 5 | #include "example_interfaces/srv/add_two_ints.hpp" 6 | 7 | class ServiceClient : public rclcpp::Node 8 | { 9 | public: 10 | ServiceClient() : Node("service_client") { 11 | client_ = this->create_client("add_two_ints"); 12 | } 13 | 14 | int init() { 15 | while (!client_->wait_for_service(std::chrono::seconds(1))) { 16 | if (!rclcpp::ok()) { 17 | RCLCPP_ERROR(this->get_logger(), "Interrupted while waiting for the service. Exiting."); 18 | return 0; 19 | } 20 | RCLCPP_INFO(this->get_logger(), "service not available, waiting again..."); 21 | } 22 | return 0; 23 | } 24 | 25 | void run(const int pa, const int pb) { 26 | auto request = std::make_shared(); 27 | request->a = pa; 28 | request->b = pb; 29 | 30 | auto result = client_->async_send_request(request); 31 | if (rclcpp::spin_until_future_complete(this->get_node_base_interface(), result) == 32 | rclcpp::FutureReturnCode::SUCCESS) { 33 | RCLCPP_INFO(this->get_logger(), "cpp client: send %ld(a) + %ld(b), receive %ld(sum)", 34 | request->a, request->b, result.get()->sum); 35 | } else { 36 | RCLCPP_ERROR(this->get_logger(), "Failed to call service add_two_ints"); 37 | } 38 | } 39 | 40 | private: 41 | rclcpp::Client::SharedPtr client_; 42 | }; 43 | 44 | int main(int argc, char * argv[]) { 45 | rclcpp::init(argc, argv); 46 | auto node = std::make_shared(); 47 | node->init(); 48 | while (rclcpp::ok()) { 49 | srand((unsigned)time(NULL)); 50 | node->run(rand(), rand()); 51 | std::this_thread::sleep_for(std::chrono::seconds(1)); 52 | } 53 | 54 | rclcpp::shutdown(); 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /pubsub_py/pubsub_py/pub_hello_qos.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rclpy 5 | from rclpy.node import Node 6 | 7 | from std_msgs.msg import String 8 | from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy, QoSDurabilityPolicy, LivelinessPolicy 9 | from rclpy.duration import Duration 10 | 11 | class Publisher(Node): 12 | def __init__(self): 13 | super().__init__('test_qos_publisher') 14 | 15 | qos_profile = QoSProfile( 16 | # RELIABLE(default), BEST_EFFORT 17 | reliability = QoSReliabilityPolicy.RELIABLE, 18 | # VOLATILE(default) 19 | # TRANSIENT_LOCAL(Only works when reliability is RELIABLE and needs history:KEEP_LAST and depth) 20 | durability=QoSDurabilityPolicy.TRANSIENT_LOCAL, 21 | # history: only works when reliability is RELIABLE 22 | # KEEP_LAST(default), KEEP_ALL 23 | history = QoSHistoryPolicy.KEEP_LAST, 24 | # default is 10 25 | depth=10, 26 | # default is Infinite 27 | lifespan=Duration(seconds=5), 28 | 29 | # default is Infinite 30 | deadline=Duration(seconds=5, nanoseconds=0), 31 | # AUTOMATIC(default), MANUAL_BY_TOPIC 32 | liveliness=LivelinessPolicy.AUTOMATIC, 33 | # default is Infinite 34 | liveliness_lease_duration=Duration(seconds=5) 35 | ) 36 | 37 | self._publisher = self.create_publisher(String, "hello_topic", qos_profile) 38 | self._timer = self.create_timer(0.5, self.timer_callback) 39 | self._i = 0 40 | 41 | def timer_callback(self): 42 | msg = String() 43 | msg.data = "hello, i am fine in python! %d" % self._i 44 | self._publisher.publish(msg) 45 | self.get_logger().info("publish: %s" % msg.data) 46 | self._i += 1 47 | 48 | 49 | def main(args=None): 50 | rclpy.init(args=args) 51 | 52 | pub_node = Publisher() 53 | rclpy.spin(pub_node) 54 | 55 | pub_node.destroy_node() 56 | rclpy.shutdown() 57 | 58 | if __name__ == '__main__': 59 | main() -------------------------------------------------------------------------------- /learning_tf2_cpp/src/turtle_tf_broadcaster.cpp: -------------------------------------------------------------------------------- 1 | #include "learning_tf2_cpp/turtle_tf_broadcaster.hpp" 2 | 3 | #include "rclcpp_components/register_node_macro.hpp" 4 | RCLCPP_COMPONENTS_REGISTER_NODE(learning_tf2_cpp::TurtleTfBroadcaster) 5 | 6 | namespace learning_tf2_cpp 7 | { 8 | 9 | TurtleTfBroadcaster::TurtleTfBroadcaster(const rclcpp::NodeOptions & options) 10 | : Node("turtle_tf_broadcaster", options) { 11 | auto param_desc = rcl_interfaces::msg::ParameterDescriptor{}; 12 | param_desc.description = "This parameter is used to pass in the name of the turtle"; 13 | turtle_name_ = this->declare_parameter("turtle_name", "turtle1", param_desc); 14 | 15 | tf_broadcaster_ = std::make_unique(*this); 16 | 17 | std::string topic_name = "/" + turtle_name_ + "/pose"; 18 | turtle_pose_sub_ = this->create_subscription( 19 | topic_name, 10, std::bind(&TurtleTfBroadcaster::handle_turtle_pose, this, std::placeholders::_1)); 20 | 21 | } 22 | 23 | // 小乌龟 TF 广播器的核心是通过订阅小乌龟的 Pose 信息,将 Pose 信息经过加工得到小乌龟相对 world 坐标系的 TF 坐标变换, 24 | // 坐标变换主要分为两部分,一是平移变换,二是旋转变换,然后通过 TF 广播器将 TF 信息广播出去。 25 | // 关于 Pose 信息,欧拉角以及四元数的理解,请参考:https://blog.csdn.net/cy1641395022/article/details/131236155 26 | // 关于计算过程的理解,请参考:https://blog.csdn.net/cy1641395022/article/details/131236155 27 | void TurtleTfBroadcaster::handle_turtle_pose(const std::shared_ptr msg) { 28 | geometry_msgs::msg::TransformStamped tf_stamped; 29 | 30 | tf_stamped.header.stamp = this->now(); 31 | tf_stamped.header.frame_id = "world"; 32 | tf_stamped.child_frame_id = this->turtle_name_; 33 | 34 | tf_stamped.transform.translation.x = msg->x; 35 | tf_stamped.transform.translation.y = msg->y; 36 | tf_stamped.transform.translation.z = 0.0; 37 | 38 | tf2::Quaternion tf_q; 39 | tf_q.setRPY(0, 0, msg->theta); 40 | 41 | tf_stamped.transform.rotation.x = tf_q.x(); 42 | tf_stamped.transform.rotation.y = tf_q.y(); 43 | tf_stamped.transform.rotation.z = tf_q.z(); 44 | tf_stamped.transform.rotation.w = tf_q.w(); 45 | 46 | this->tf_broadcaster_->sendTransform(tf_stamped); 47 | } 48 | 49 | } // namespace learning_tf2_cpp -------------------------------------------------------------------------------- /pubsub_cpp/src/sub_hello_qos.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rclcpp/rclcpp.hpp" 4 | #include "std_msgs/msg/string.hpp" 5 | #include "builtin_interfaces/msg/duration.hpp" 6 | 7 | class Subscriber : public rclcpp::Node 8 | { 9 | public: 10 | Subscriber() : Node("test_qos_subscriber") { 11 | // set qos profile 12 | // set history depth to 10, 10 is also the default value 13 | rclcpp::QoS qos_profile(10); 14 | // RMW_QOS_POLICY_RELIABILITY_RELIABLE(default), RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT 15 | qos_profile.reliability(RMW_QOS_POLICY_RELIABILITY_RELIABLE); 16 | // RMW_QOS_POLICY_DURABILITY_VOLATILE(default) 17 | // RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL(Only works when reliability is RELIABLE and needs history:KEEP_LAST and depth) 18 | qos_profile.durability(RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL); 19 | // history: only works when reliability is RELIABLE 20 | // RMW_QOS_POLICY_HISTORY_KEEP_LAST(default), RMW_QOS_POLICY_HISTORY_KEEP_ALL 21 | qos_profile.history(RMW_QOS_POLICY_HISTORY_KEEP_LAST); 22 | // default is Infinite 23 | qos_profile.lifespan(rclcpp::Duration(5, 0)); 24 | 25 | // default is Infinite 26 | qos_profile.deadline(rclcpp::Duration(5, 0)); 27 | // RMW_QOS_POLICY_LIVELINESS_AUTOMATIC(default), RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC 28 | qos_profile.liveliness(RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC); 29 | // default is Infinite 30 | qos_profile.liveliness_lease_duration(rclcpp::Duration(5, 0)); 31 | 32 | subscription_ = this->create_subscription( 33 | "hello_topic", qos_profile, std::bind(&Subscriber::topic_callback, this, std::placeholders::_1)); 34 | } 35 | 36 | private: 37 | void topic_callback(const std_msgs::msg::String &msg) const { 38 | RCLCPP_INFO(this->get_logger(), "i received: %s", msg.data.c_str()); 39 | sleep(2); // test qos history and depth parameters 40 | } 41 | 42 | private: 43 | rclcpp::Subscription::SharedPtr subscription_; 44 | }; 45 | 46 | 47 | int main(int argc, char * argv[]) { 48 | rclcpp::init(argc, argv); 49 | rclcpp::spin(std::make_shared()); 50 | rclcpp::shutdown(); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /pubsub_cpp/src/pub_diy_msg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rclcpp/rclcpp.hpp" 5 | #include "diy_interface/msg/student.hpp" 6 | #include "diy_interface/msg/sphere.hpp" 7 | 8 | class Publisher : public rclcpp::Node 9 | { 10 | public: 11 | Publisher() : Node("test_pub_diy_msg"), count_(0) { 12 | pub_student_ = this->create_publisher("student_topic", 10); 13 | pub_sphere_ = this->create_publisher("sphere_topic", 10); 14 | timer_ = this->create_wall_timer(std::chrono::seconds(1), std::bind(&Publisher::timer_callback, this)); 15 | } 16 | 17 | private: 18 | void timer_callback() { 19 | auto stu_msg = diy_interface::msg::Student(); 20 | stu_msg.name = students_[count_ % students_.size()].first; 21 | stu_msg.age = students_[count_ % students_.size()].second; 22 | RCLCPP_INFO(this->get_logger(), "publishing student in cpp: %s, %d", stu_msg.name.c_str(), stu_msg.age); 23 | pub_student_->publish(stu_msg); 24 | 25 | auto sphere_msg = diy_interface::msg::Sphere(); 26 | sphere_msg.center.x = std::get<0>(spheres_[count_ % spheres_.size()].first); 27 | sphere_msg.center.y = std::get<1>(spheres_[count_ % spheres_.size()].first); 28 | sphere_msg.center.z = std::get<2>(spheres_[count_ % spheres_.size()].first); 29 | sphere_msg.radius = spheres_[count_ % spheres_.size()].second; 30 | RCLCPP_INFO(this->get_logger(), "publishing sphere in cpp: (%f, %f, %f), %f", 31 | sphere_msg.center.x, sphere_msg.center.y, sphere_msg.center.z, sphere_msg.radius); 32 | pub_sphere_->publish(sphere_msg); 33 | 34 | count_++; 35 | } 36 | 37 | private: 38 | rclcpp::TimerBase::SharedPtr timer_; 39 | rclcpp::Publisher::SharedPtr pub_student_; 40 | rclcpp::Publisher::SharedPtr pub_sphere_; 41 | size_t count_; 42 | 43 | std::vector> students_ = 44 | {{"yi", 32}, {"miao", 18}, {"bao", 3}}; 45 | std::vector, float>> spheres_ = 46 | {{{1.0f, 2.0f, 3.0f}, 4.0f}, {{1.1f, 2.1f, 3.1f}, 4.1f}}; 47 | 48 | }; 49 | 50 | int main(int argc, char * argv[]) { 51 | rclcpp::init(argc, argv); 52 | rclcpp::spin(std::make_shared()); 53 | rclcpp::shutdown(); 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /pubsub_cpp/src/pub_hello_qos.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rclcpp/rclcpp.hpp" 7 | #include "std_msgs/msg/string.hpp" 8 | #include "builtin_interfaces/msg/duration.hpp" 9 | 10 | class Publisher : public rclcpp::Node 11 | { 12 | public: 13 | Publisher() : Node("test_qos_publisher"), count_(0) { 14 | // set qos profile 15 | // set history depth to 10, 10 is also the default value 16 | rclcpp::QoS qos_profile(10); 17 | // RMW_QOS_POLICY_RELIABILITY_RELIABLE(default), RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT 18 | qos_profile.reliability(RMW_QOS_POLICY_RELIABILITY_RELIABLE); 19 | // RMW_QOS_POLICY_DURABILITY_VOLATILE(default) 20 | // RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL(Only works when reliability is RELIABLE and needs history:KEEP_LAST and depth) 21 | qos_profile.durability(RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL); 22 | // history: only works when reliability is RELIABLE 23 | // RMW_QOS_POLICY_HISTORY_KEEP_LAST(default), RMW_QOS_POLICY_HISTORY_KEEP_ALL 24 | qos_profile.history(RMW_QOS_POLICY_HISTORY_KEEP_LAST); 25 | // default is Infinite 26 | qos_profile.lifespan(rclcpp::Duration(5, 0)); 27 | 28 | // default is Infinite 29 | qos_profile.deadline(rclcpp::Duration(5, 0)); 30 | // RMW_QOS_POLICY_LIVELINESS_AUTOMATIC(default), RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC 31 | qos_profile.liveliness(RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC); 32 | // default is Infinite 33 | qos_profile.liveliness_lease_duration(rclcpp::Duration(5, 0)); 34 | 35 | publisher_ = this->create_publisher("hello_topic", qos_profile); 36 | timer_ = this->create_wall_timer(std::chrono::seconds(1), std::bind(&Publisher::timer_callback, this)); 37 | } 38 | 39 | private: 40 | void timer_callback() { 41 | auto msg = std_msgs::msg::String(); 42 | msg.data = "hello, i am fine in cpp! " + std::to_string(count_++); 43 | RCLCPP_INFO(this->get_logger(), "publishing: %s", msg.data.c_str()); 44 | publisher_->publish(msg); 45 | } 46 | 47 | private: 48 | rclcpp::TimerBase::SharedPtr timer_; 49 | rclcpp::Publisher::SharedPtr publisher_; 50 | size_t count_; 51 | }; 52 | 53 | int main(int argc, char * argv[]) { 54 | rclcpp::init(argc, argv); 55 | rclcpp::spin(std::make_shared()); 56 | rclcpp::shutdown(); 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /gazebo_mbot_go_maze/urdf/sensor/laser.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | Gazebo/Grey 36 | 37 | 38 | 39 | 40 | 0 0 0 0 0 0 41 | false 42 | 5.5 43 | 44 | 45 | 46 | 360 47 | 1 48 | -3 49 | 3 50 | 51 | 52 | 53 | 0.10 54 | 6.0 55 | 0.01 56 | 57 | 58 | gaussian 59 | 0.0 60 | 0.01 61 | 62 | 63 | 64 | 65 | / 66 | ~/out:=scan 67 | 68 | sensor_msgs/LaserScan 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /learning_tf2_py/learning_tf2_py/turtle_tf2_broadcaster.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import math 5 | import numpy as np 6 | 7 | import rclpy 8 | from rclpy.node import Node 9 | from tf2_ros import TransformBroadcaster 10 | from turtlesim.msg import Pose 11 | from geometry_msgs.msg import TransformStamped 12 | 13 | class Helper: 14 | # 根据已知的数学公式,将三个欧拉角转换为四元数 15 | def quaternion_from_euler(ai, aj, ak): 16 | ai /= 2.0 17 | aj /= 2.0 18 | ak /= 2.0 19 | ci = math.cos(ai) 20 | si = math.sin(ai) 21 | cj = math.cos(aj) 22 | sj = math.sin(aj) 23 | ck = math.cos(ak) 24 | sk = math.sin(ak) 25 | cc = ci*ck 26 | cs = ci*sk 27 | sc = si*ck 28 | ss = si*sk 29 | 30 | q = np.empty((4, )) 31 | q[0] = cj*sc - sj*cs 32 | q[1] = cj*ss + sj*cc 33 | q[2] = cj*cs - sj*sc 34 | q[3] = cj*cc + sj*ss 35 | 36 | return q 37 | 38 | class TurtleTfBroadcaster(Node): 39 | def __init__(self, name): 40 | super().__init__(name) 41 | 42 | self._turtlename = self.declare_parameter("turtle_name", "turtle1").get_parameter_value().string_value 43 | 44 | self._tf_broadcaster = TransformBroadcaster(self) 45 | 46 | pose_topic = "/" + self._turtlename + "/pose" 47 | self.get_logger().info("subscribe to " + pose_topic) 48 | self._pose_subscription = self.create_subscription(Pose, pose_topic, self.pose_callback, 1) 49 | 50 | self.get_logger().info("start turtle_tf2_broadcaster node !!") 51 | 52 | def pose_callback(self, msg): 53 | tf_stamped = TransformStamped() 54 | 55 | tf_stamped.header.stamp = self.get_clock().now().to_msg() 56 | tf_stamped.header.frame_id = "world" 57 | tf_stamped.child_frame_id = self._turtlename 58 | 59 | tf_stamped.transform.translation.x = msg.x 60 | tf_stamped.transform.translation.y = msg.y 61 | tf_stamped.transform.translation.z = 0.0 62 | 63 | tf_q = Helper.quaternion_from_euler(0, 0, msg.theta) 64 | tf_stamped.transform.rotation.x = tf_q[0] 65 | tf_stamped.transform.rotation.y = tf_q[1] 66 | tf_stamped.transform.rotation.z = tf_q[2] 67 | tf_stamped.transform.rotation.w = tf_q[3] 68 | 69 | self._tf_broadcaster.sendTransform(tf_stamped) 70 | 71 | def main(args=None): 72 | rclpy.init(args=args) 73 | node = TurtleTfBroadcaster("turtle_tf2_broadcaster") 74 | 75 | try: 76 | rclpy.spin(node) 77 | except KeyboardInterrupt: 78 | pass 79 | 80 | rclpy.shutdown() 81 | 82 | # if __name__ == '__main__': 83 | # main() -------------------------------------------------------------------------------- /bag_operator/scripts/bag_echo.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import argparse 6 | import logging 7 | import rosbag2_py 8 | from rclpy.serialization import deserialize_message 9 | from rosidl_runtime_py.utilities import get_message 10 | 11 | logging.basicConfig(level=logging.DEBUG) 12 | 13 | class BagEcho(object): 14 | def __init__(self, bag, topics): 15 | self._bag = bag 16 | self._topics = topics 17 | self._reader = rosbag2_py.SequentialReader() 18 | 19 | def echo_bag(self): 20 | # 以sqlite3格式打开ros2 bag 21 | storage_options = rosbag2_py._storage.StorageOptions(uri=self._bag, storage_id='sqlite3') 22 | converter_options = rosbag2_py._storage.ConverterOptions('', '') 23 | self._reader.open(storage_options, converter_options) 24 | # 设置要读取的topic作为过滤条件,如果没有指定topic,则读取所有topic 25 | if self._topics: 26 | storage_filter = rosbag2_py._storage.StorageFilter(topics=self._topics) 27 | self._reader.set_filter(storage_filter) 28 | # 获取所有话题及其类型,并使用map存储 29 | topic_name2type = {topic_metadata.name: topic_metadata.type for topic_metadata in self._reader.get_all_topics_and_types()} 30 | 31 | # 循环读取消息,并进行个数统计 32 | msg_cnts = {} 33 | while self._reader.has_next(): 34 | (topic_name, data, t) = self._reader.read_next() 35 | 36 | # 统计每个话题的消息数 37 | if topic_name not in msg_cnts: 38 | msg_cnts[topic_name] = 1 39 | else: 40 | msg_cnts[topic_name] += 1 41 | 42 | # 反序列化消息 43 | message_type = get_message(topic_name2type[topic_name]) 44 | msg = deserialize_message(data, message_type) 45 | 46 | # 打印消息内容 47 | print("----------[%s : %s]---------" % (topic_name, topic_name2type[topic_name])) 48 | print(msg) 49 | 50 | # 打印摘要信息 51 | logging.info("----------[rosbag summary]---------") 52 | for topic_name in msg_cnts: 53 | logging.info("topic %s msg cnt is %d" %(topic_name, msg_cnts[topic_name])) 54 | 55 | def main(): 56 | parser = argparse.ArgumentParser(description="echo ros2 bag topic") 57 | parser.add_argument("-b", "--bag", type=str, required=True, help="specify rosbag") 58 | parser.add_argument("-t", "--topics", nargs="+", type=str, help="specify topic") 59 | # extra_args可以让-t指定多个topic,并使用argparse.SUPPRESS隐藏extra_args参数 60 | parser.add_argument('extra_args', nargs='*', help=argparse.SUPPRESS) 61 | args=parser.parse_args() 62 | 63 | if not os.path.isfile(args.bag): 64 | logging.error("%s is not found!" %args.bag) 65 | return 66 | 67 | echo = BagEcho(args.bag, args.topics) 68 | echo.echo_bag() 69 | 70 | if __name__ == "__main__": 71 | main() -------------------------------------------------------------------------------- /webots_demo/webots_demo/mbot_driver.py: -------------------------------------------------------------------------------- 1 | import rclpy 2 | from geometry_msgs.msg import Twist 3 | 4 | HALF_DISTANCE_BETWEEN_WHEELS = 0.045 5 | WHEEL_RADIUS = 0.025 6 | 7 | # MbotDriver 是机器人的控制器程序,他创建了一个 ros2 节点 mbot_driver, 8 | # 订阅 cmd_vel 话题,接收 Twist 消息,然后根据 Twist 消息的线速度和角速度控制机器人的左右轮速度,从而实现机器人的运动控制。 9 | class MbotDriver: 10 | def init(self, webots_node, properties): 11 | # 获取 webots 里的 robot 对象,在本样例就是 my_world.wbt 中的 mbot_car 12 | self._robot = webots_node.robot 13 | 14 | # 获取左右轮的电机对象,并设置电机的目标位置为极大(一直旋转)和速度为 0 15 | self._left_motor = self._robot.getDevice('left wheel motor') 16 | self._right_motor = self._robot.getDevice('right wheel motor') 17 | 18 | self._left_motor.setPosition(float('inf')) 19 | self._left_motor.setVelocity(0) 20 | 21 | self._right_motor.setPosition(float('inf')) 22 | self._right_motor.setVelocity(0) 23 | 24 | self._target_twist = Twist() 25 | 26 | # 创建一个 ros2 节点 mbot_driver,订阅 cmd_vel 话题,用来驱动 mbot_car 27 | # 接收到的 Twist 消息存入 self._target_twist 中,等待 step 函数处理 28 | rclpy.init(args=None) 29 | self._node = rclpy.create_node('mbot_driver') 30 | self._node.create_subscription(Twist, 'cmd_vel', self._cmd_vel_callback, 1) 31 | 32 | def _cmd_vel_callback(self, twist): 33 | self._target_twist = twist 34 | 35 | # step 由 webots_ros2_driver.webots_controller.WebotsController 调用,称之为 simulation step 36 | # 这里可以理解为是机器人控制器的主循环函数,周期调用 37 | def step(self): 38 | # 使用 spin_once 来处理 mbot_driver 的一次事件,这里是一次 cmd_vel 订阅 39 | # 如果没有这个函数,_cmd_vel_callback 是不会被执行的 40 | # 如果事件没来,会立即返回,不会阻塞,确保实时性 41 | rclpy.spin_once(self._node, timeout_sec=0) 42 | 43 | # 这里讲解了 Twist 理解 和 右手定则:https://blog.csdn.net/cy1641395022/article/details/131236155 44 | # 获取机器人的前进速度和旋转速度,根据右手定则: 45 | # 如果机器人向左转(顺时针),angular_speed为负; 46 | # 如果机器人向右转(逆时针),angular_speed为正; 47 | forward_speed = self._target_twist.linear.x 48 | angular_speed = self._target_twist.angular.z 49 | 50 | # 机器人的前进和旋转速度需要转换为左右轮转速,由于机器人是差速驱动,所以需要根据机器人的轮距和轮径来计算左右轮转速 51 | # HALF_DISTANCE_BETWEEN_WHEELS 是机器人的轮距的一半,乘以 angular_speed 就是机器人内外轮线速度的补偿值 52 | # 得到内外轮线速度后,再除以 WHEEL_RADIUS 就是内外轮的转速(角速度乘以旋转半径为线速度) 53 | # 简单的三个场景,可以帮助理解这个公式: 54 | # 第一,控制机器人直线前进(forward_speed 为正,angular_speed 为0),左右轮转速必须相同,且转向相同 55 | # 第二,控制机器人原地顺时针旋转(forward_speed 为0,angular_speed 为负),左右轮转速必须相同,且转向相反 56 | # 第三,控制机器人原地逆时针旋转(forward_speed 为0,angular_speed 为正),左右轮转速必须相同,且转向相反 57 | command_motor_left = (forward_speed - angular_speed * HALF_DISTANCE_BETWEEN_WHEELS) / WHEEL_RADIUS 58 | command_motor_right = (forward_speed + angular_speed * HALF_DISTANCE_BETWEEN_WHEELS) / WHEEL_RADIUS 59 | 60 | # 设置左右轮的目标转速 61 | self._left_motor.setVelocity(command_motor_left) 62 | self._right_motor.setVelocity(command_motor_right) -------------------------------------------------------------------------------- /gazebo_mbot_go_maze/launch/mbot_gazebo_launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from ament_index_python.packages import get_package_share_directory 4 | 5 | 6 | from launch import LaunchDescription 7 | from launch.actions import IncludeLaunchDescription, TimerAction 8 | from launch.launch_description_sources import PythonLaunchDescriptionSource 9 | from launch_ros.actions import Node 10 | import xacro 11 | 12 | def generate_launch_description(): 13 | package_name='gazebo_mbot_go_maze' #<--- CHANGE ME 14 | world_file_path = 'worlds/maze_room.world' 15 | pkg_path = os.path.join(get_package_share_directory(package_name)) 16 | world_path = os.path.join(pkg_path, world_file_path) 17 | rviz_path = os.path.join(pkg_path, 'rviz/mbot_gazebo.rviz') 18 | print(rviz_path) 19 | 20 | # Process the URDF file 21 | pkg_path = os.path.join(get_package_share_directory(package_name)) 22 | xacro_file = os.path.join(pkg_path,'urdf','mbot_base.xacro') 23 | robot_description_config = xacro.process_file(xacro_file) 24 | # Create a robot_state_publisher node 25 | params = {'robot_description': robot_description_config.toxml(), 'use_sim_time': True} 26 | mbot = Node( 27 | package='robot_state_publisher', 28 | executable='robot_state_publisher', 29 | output='screen', 30 | parameters=[params] 31 | ) 32 | 33 | # Include the Gazebo launch file, provided by the gazebo_ros package 34 | gazebo = IncludeLaunchDescription( 35 | PythonLaunchDescriptionSource([os.path.join( 36 | get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py' 37 | )]), launch_arguments={'world':world_path}.items() 38 | ) 39 | 40 | # Pose where we want to spawn the robot 41 | spawn_x_val = '0.0' 42 | spawn_y_val = '0.0' 43 | spawn_z_val = '0.0' 44 | spawn_yaw_val = '0.0' 45 | 46 | # Run the spawner node from the gazebo_ros package. The entity name doesn't really matter if you only have a single robot. 47 | spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py', 48 | arguments=['-topic', 'robot_description', 49 | '-entity', 'mbot', 50 | '-x', spawn_x_val, 51 | '-y', spawn_y_val, 52 | '-z', spawn_z_val, 53 | '-Y', spawn_yaw_val], 54 | output='screen') 55 | 56 | 57 | rviz_node = Node( 58 | package='rviz2', 59 | executable='rviz2', 60 | name='rviz2', 61 | arguments=['-d', rviz_path]) 62 | 63 | # Launch them all! 64 | return LaunchDescription([ 65 | mbot, 66 | gazebo, 67 | spawn_entity, 68 | TimerAction( 69 | period=3.0, 70 | actions=[rviz_node], 71 | ) 72 | ]) 73 | -------------------------------------------------------------------------------- /learning_tf2_py/learning_tf2_py/turtle_tf2_listener.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import math 5 | 6 | import rclpy 7 | from rclpy.node import Node 8 | 9 | from tf2_ros import TransformException 10 | from tf2_ros.buffer import Buffer 11 | from tf2_ros.transform_listener import TransformListener 12 | 13 | from geometry_msgs.msg import Twist 14 | from turtlesim.srv import Spawn 15 | 16 | class TurtleTfListener(Node): 17 | def __init__(self, name): 18 | super().__init__(name) 19 | 20 | 21 | self._target_frame = self.declare_parameter("target_frame", "turtle1").get_parameter_value().string_value 22 | 23 | self._tf_buffer = Buffer() 24 | self._tf_listener = TransformListener(self._tf_buffer, self) 25 | 26 | self._spawn_client = self.create_client(Spawn, "spawn") 27 | self._cmd_publisher = self.create_publisher(Twist, "turtle2/cmd_vel", 10) 28 | 29 | self._turtle_spawning_service_ready = False 30 | self._turtle_spawned = False 31 | 32 | self._timer = self.create_timer(1, self.timer_callback) 33 | 34 | self.get_logger().info("start turtle_tf2_listener node !!") 35 | 36 | def timer_callback(self): 37 | if False == self._turtle_spawning_service_ready: 38 | if False == self._spawn_client.service_is_ready(): 39 | self.get_logger().info('Waiting for the spawn service to be ready') 40 | return 41 | 42 | self._turtle_spawning_service_ready = True 43 | 44 | if False == self._turtle_spawned: 45 | request = Spawn.Request() 46 | request.x = 5.0 47 | request.y = 5.0 48 | request.theta = 0.0 49 | request.name = "turtle2" 50 | 51 | self._spawn_client.call_async(request) 52 | self._turtle_spawned = True 53 | return 54 | 55 | try: 56 | tf_stamped = self._tf_buffer.lookup_transform( 57 | "turtle2", 58 | self._target_frame, 59 | rclpy.time.Time()) 60 | except TransformException as ex: 61 | self.get_logger().info( 62 | f'Could not transform turtle2 to {self._target_frame}: {ex}') 63 | return 64 | 65 | cmd_vel = Twist() 66 | cmd_vel.linear.x = 0.5 * math.sqrt(tf_stamped.transform.translation.x ** 2 + tf_stamped.transform.translation.y ** 2) 67 | cmd_vel.angular.z = 1.0 * math.atan2(tf_stamped.transform.translation.y, tf_stamped.transform.translation.x) 68 | 69 | self.get_logger().info("send cmd_vel to turtle2: linear.x: %f, angular.z: %f" % (cmd_vel.linear.x, cmd_vel.angular.z)) 70 | self._cmd_publisher.publish(cmd_vel) 71 | 72 | def main(args=None): 73 | rclpy.init(args=args) 74 | 75 | node = TurtleTfListener("turtle_tf2_listener") 76 | rclpy.spin(node) 77 | 78 | rclpy.shutdown() 79 | 80 | if __name__ == '__main__': 81 | main() -------------------------------------------------------------------------------- /gazebo_mbot_go_maze/urdf/sensor/camera.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | Gazebo/Grey 38 | 39 | 40 | 41 | 42 | 30.0 43 | 44 | 1.3962634 45 | 46 | 1280 47 | 720 48 | R8G8B8 49 | 50 | 51 | 0.02 52 | 300 53 | 54 | 55 | gaussian 56 | 0.0 57 | 0.007 58 | 59 | 60 | 61 | true 62 | 0.0 63 | /camera_${prefix} 64 | image_raw 65 | camera_info 66 | ${prefix}_camera_link 67 | 0.07 68 | 0.0 69 | 0.0 70 | 0.0 71 | 0.0 72 | 0.0 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /learning_tf2_cpp/launch/turtle_tf2_demo_launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ament_index_python.packages import get_package_share_directory 3 | import launch 4 | from launch_ros.actions import ComposableNodeContainer 5 | from launch_ros.descriptions import ComposableNode 6 | from launch_ros.actions import Node 7 | 8 | def generate_launch_description(): 9 | # 启动turtlesim节点,这个是基础环境 10 | turtlesim_node = Node( 11 | package='turtlesim', 12 | executable='turtlesim_node', 13 | name='turtlesim_node' 14 | ) 15 | # 启动turtle1的tf广播节点,广播turtle1的tf 16 | turtle1_tf_broadcaster = ComposableNodeContainer( 17 | name='turtle1_tf_broadcaster', 18 | namespace='', 19 | package='rclcpp_components', 20 | executable='component_container', 21 | composable_node_descriptions=[ 22 | ComposableNode( 23 | package='learning_tf2_cpp', 24 | plugin='learning_tf2_cpp::TurtleTfBroadcaster', 25 | name='turtle1_tf_bc', 26 | parameters=[{'turtle_name': 'turtle1'}]) 27 | ], 28 | output='screen', 29 | ) 30 | # 启动turtle2的tf广播节点,广播turtle2的tf 31 | turtle2_tf_broadcaster = ComposableNodeContainer( 32 | name='turtle2_tf_broadcaster', 33 | namespace='', 34 | package='rclcpp_components', 35 | executable='component_container', 36 | composable_node_descriptions=[ 37 | ComposableNode( 38 | package='learning_tf2_cpp', 39 | plugin='learning_tf2_cpp::TurtleTfBroadcaster', 40 | name='turtle2_tf_bc', 41 | parameters=[{'turtle_name': 'turtle2'}]) 42 | ], 43 | output='screen', 44 | ) 45 | # 启动rviz2,加载turtlesim的 world 和两个小乌龟坐标系的可视化配置 46 | turtlesim_world_rviz_config = os.path.join( 47 | get_package_share_directory('learning_tf2_cpp'), 48 | 'config', 49 | 'turtle_tf.rviz' 50 | ) 51 | turtlesim_world_rviz_node = Node( 52 | package='rviz2', 53 | executable='rviz2', 54 | name='rviz2', 55 | arguments=['-d', turtlesim_world_rviz_config] 56 | ) 57 | # 启动tf监听节点,监听在 turtle2 坐标系下的 turtle1 的 tf,并转换为 turtle2 的控制指令 58 | turtle2_listen_turtle1 = ComposableNodeContainer( 59 | name='turtle2_listen_turtle1', 60 | namespace='', 61 | package='rclcpp_components', 62 | executable='component_container', 63 | composable_node_descriptions=[ 64 | ComposableNode( 65 | package='learning_tf2_cpp', 66 | plugin='learning_tf2_cpp::TurtleTfListener', 67 | name='turtle_tf_ls', 68 | parameters=[{'target_frame': 'turtle1'}]) 69 | ], 70 | output='screen', 71 | ) 72 | 73 | return launch.LaunchDescription([turtlesim_node, turtle1_tf_broadcaster, turtle2_tf_broadcaster, turtlesim_world_rviz_node, turtle2_listen_turtle1]) 74 | -------------------------------------------------------------------------------- /learning_tf2_cpp/src/turtle_tf_listener.cpp: -------------------------------------------------------------------------------- 1 | #include "learning_tf2_cpp/turtle_tf_listener.hpp" 2 | 3 | #include "rclcpp_components/register_node_macro.hpp" 4 | RCLCPP_COMPONENTS_REGISTER_NODE(learning_tf2_cpp::TurtleTfListener) 5 | 6 | namespace learning_tf2_cpp 7 | { 8 | 9 | TurtleTfListener::TurtleTfListener(const rclcpp::NodeOptions & options) 10 | : Node("turtle_tf_listener", options) { 11 | auto param_desc = rcl_interfaces::msg::ParameterDescriptor{}; 12 | param_desc.description = "This parameter is used to pass in the name of the target turtle"; 13 | target_frame_ = this->declare_parameter("target_frame", "turtle1", param_desc); 14 | 15 | tf_buffer_ = std::make_unique(this->get_clock()); 16 | tf_listener_ = std::make_shared(*tf_buffer_); 17 | 18 | spawn_turtle_client_ = this->create_client("spawn"); 19 | turtle_cmd_pub_ = this->create_publisher("turtle2/cmd_vel", 10); 20 | 21 | timer_ = this->create_wall_timer(std::chrono::seconds(1), std::bind(&TurtleTfListener::on_timer, this)); 22 | 23 | 24 | RCLCPP_INFO(this->get_logger(), "TurtleTfListener has been started"); 25 | } 26 | 27 | // TF 监听器的逻辑是先生成一个小乌龟2,然后定时订阅在小乌龟2坐标系下,目标小乌龟的 TF 信息, 28 | // 拿到 TF 信息后,计算得到小乌龟2的 Twist 的控制命令,然后以 1Hz 的频率发布到小乌龟2的 cmd_vel 话题上。 29 | // Twist 的理解,参考:https://blog.csdn.net/cy1641395022/article/details/131236155 30 | // 计算过程的理解,参考:https://blog.csdn.net/cy1641395022/article/details/131236155 31 | void TurtleTfListener::on_timer() { 32 | if (false == turtle_spawning_service_ready_) { 33 | if (false == spawn_turtle_client_->service_is_ready()) { 34 | RCLCPP_INFO(this->get_logger(), "Waiting for the spawn service to be ready"); 35 | return; 36 | } 37 | turtle_spawning_service_ready_ = true; 38 | } 39 | 40 | if (false == turtle_spawned_) { 41 | auto request = std::make_shared(); 42 | request->x = 2.0; 43 | request->y = 2.0; 44 | request->theta = 0.0; 45 | request->name = "turtle2"; 46 | 47 | using ServiceResponseFuture = rclcpp::Client::SharedFuture; 48 | auto response_received_callback = [this](ServiceResponseFuture future) { 49 | auto result = future.get(); 50 | if (strcmp(result->name.c_str(), "turtle2") == 0) { 51 | turtle_spawned_ = true; 52 | RCLCPP_INFO(this->get_logger(), "Spawn turtle2 successfully"); 53 | } else { 54 | RCLCPP_ERROR(this->get_logger(), "Service callback result mismatch"); 55 | } 56 | }; 57 | auto result = spawn_turtle_client_->async_send_request(request, response_received_callback); 58 | return; 59 | } 60 | 61 | geometry_msgs::msg::TransformStamped tf_stamped; 62 | try { 63 | tf_stamped = tf_buffer_->lookupTransform("turtle2", target_frame_, tf2::TimePointZero); 64 | } catch (tf2::TransformException & ex) { 65 | RCLCPP_ERROR(this->get_logger(), "Could not lookup transform: %s", ex.what()); 66 | return; 67 | } 68 | 69 | geometry_msgs::msg::Twist cmd_vel; 70 | cmd_vel.linear.x = 0.5 * std::sqrt(pow(tf_stamped.transform.translation.x, 2) + pow(tf_stamped.transform.translation.y, 2)); 71 | cmd_vel.angular.z = 1.0 * std::atan2(tf_stamped.transform.translation.y, tf_stamped.transform.translation.x); 72 | 73 | RCLCPP_INFO(this->get_logger(), "send cmd_vel to turtle2: linear.x: %f, angular.z: %f", cmd_vel.linear.x, cmd_vel.angular.z); 74 | turtle_cmd_pub_->publish(cmd_vel); 75 | } 76 | 77 | 78 | } -------------------------------------------------------------------------------- /action_cpp/src/fibonacci_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "rclcpp/rclcpp.hpp" 6 | #include "rclcpp_action/rclcpp_action.hpp" 7 | #include "diy_interface/action/fibonacci.hpp" 8 | namespace action_cpp { 9 | 10 | class FibonacciActionServer : public rclcpp::Node { 11 | public: 12 | using Fibonacci = diy_interface::action::Fibonacci; 13 | using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle; 14 | FibonacciActionServer() : Node("fibonacci_action_server") { 15 | action_server_ = rclcpp_action::create_server( 16 | this, 17 | "fibonacci", 18 | std::bind(&FibonacciActionServer::handle_goal, this, std::placeholders::_1, std::placeholders::_2), 19 | std::bind(&FibonacciActionServer::handle_cancel, this, std::placeholders::_1), 20 | std::bind(&FibonacciActionServer::handle_accepted, this, std::placeholders::_1)); 21 | 22 | RCLCPP_INFO(this->get_logger(), "Fibonacci action server has been started"); 23 | } 24 | 25 | private: 26 | // uuid 参数虽然没有使用,但是必须写上,否则编译器会报错 27 | rclcpp_action::GoalResponse handle_goal(const rclcpp_action::GoalUUID & uuid, 28 | std::shared_ptr goal) { 29 | (void)uuid; 30 | RCLCPP_INFO(this->get_logger(), "Received goal request with order %d", goal->order); 31 | return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE; 32 | } 33 | // goal_handle 参数虽然没有使用,但是必须写上,否则编译器会报错 34 | rclcpp_action::CancelResponse handle_cancel(const std::shared_ptr goal_handle) { 35 | (void)goal_handle; 36 | RCLCPP_INFO(this->get_logger(), "Received cancel request"); 37 | return rclcpp_action::CancelResponse::ACCEPT; 38 | } 39 | 40 | void handle_accepted(const std::shared_ptr goal_handle) { 41 | std::thread{std::bind(&FibonacciActionServer::execute, this, std::placeholders::_1), goal_handle}.detach(); 42 | } 43 | 44 | void execute(const std::shared_ptr goal_handle) { 45 | RCLCPP_INFO(this->get_logger(), "Executing goal"); 46 | rclcpp::Rate loop_rate(1); 47 | const auto goal = goal_handle->get_goal(); 48 | auto result = std::make_shared(); 49 | auto feedback = std::make_shared(); 50 | feedback->partial_sequence.push_back(0); 51 | feedback->partial_sequence.push_back(1); 52 | 53 | for (int i = 1; (i < goal->order) && rclcpp::ok(); ++i) { 54 | if (goal_handle->is_canceling()) { 55 | // 取消任务时,把 feedback 的斐波那契数组保存到 result 的斐波那契数组中 56 | result->sequence = feedback->partial_sequence; 57 | goal_handle->canceled(result); 58 | RCLCPP_INFO(this->get_logger(), "Goal canceled"); 59 | return; 60 | } 61 | feedback->partial_sequence.push_back(feedback->partial_sequence[i] + feedback->partial_sequence[i-1]); 62 | goal_handle->publish_feedback(feedback); 63 | RCLCPP_INFO(this->get_logger(), "publish feedback"); 64 | loop_rate.sleep(); 65 | } 66 | 67 | if (rclcpp::ok()) { 68 | // 任务结束时,把 feedback 的斐波那契数组保存到 result 的斐波那契数组中 69 | result->sequence = feedback->partial_sequence; 70 | goal_handle->succeed(result); 71 | RCLCPP_INFO(this->get_logger(), "Goal succeeded"); 72 | } 73 | } 74 | 75 | private: 76 | rclcpp_action::Server::SharedPtr action_server_; 77 | }; // class FibonacciActionServer 78 | 79 | } // namespace action_cpp 80 | 81 | int main(int argc, char* argv[]) { 82 | rclcpp::init(argc, argv); 83 | 84 | rclcpp::spin(std::make_shared()); 85 | 86 | rclcpp::shutdown(); 87 | 88 | return 0; 89 | } -------------------------------------------------------------------------------- /webots_demo/worlds/my_world.wbt: -------------------------------------------------------------------------------- 1 | #VRML_SIM R2022b utf8 2 | 3 | EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2022b/projects/objects/backgrounds/protos/TexturedBackground.proto" 4 | EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2022b/projects/objects/backgrounds/protos/TexturedBackgroundLight.proto" 5 | EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2022b/projects/objects/floors/protos/CircleArena.proto" 6 | 7 | WorldInfo { 8 | } 9 | Viewpoint { 10 | orientation -0.33185733874619844 -0.09874274160469809 0.9381474178937331 3.686018050088086 11 | position 1.700313773507203 1.0549607538959629 1.4846240848267684 12 | follow "mbot_car" 13 | } 14 | TexturedBackground { 15 | } 16 | TexturedBackgroundLight { 17 | } 18 | CircleArena { 19 | } 20 | Robot { 21 | children [ 22 | HingeJoint { 23 | jointParameters HingeJointParameters { 24 | axis 0 1 0 25 | anchor 0 0 0.025 26 | } 27 | device [ 28 | RotationalMotor { 29 | name "left wheel motor" 30 | } 31 | ] 32 | endPoint Solid { 33 | translation 0 0.045 0.025 34 | children [ 35 | DEF WHEEL Transform { 36 | rotation 1 0 0 1.5707996938995747 37 | children [ 38 | Shape { 39 | appearance PBRAppearance { 40 | baseColor 1 0 0 41 | roughness 1 42 | metalness 0 43 | } 44 | geometry Cylinder { 45 | height 0.01 46 | radius 0.025 47 | } 48 | } 49 | ] 50 | } 51 | ] 52 | name "left wheel" 53 | boundingObject USE WHEEL 54 | physics Physics { 55 | } 56 | } 57 | } 58 | HingeJoint { 59 | jointParameters HingeJointParameters { 60 | axis 0 1 0 61 | anchor 0 0 0.025 62 | } 63 | device [ 64 | RotationalMotor { 65 | name "right wheel motor" 66 | } 67 | ] 68 | endPoint Solid { 69 | translation 0 -0.045 0.025 70 | children [ 71 | USE WHEEL 72 | ] 73 | name "right wheel" 74 | boundingObject USE WHEEL 75 | physics Physics { 76 | } 77 | } 78 | } 79 | Transform { 80 | translation 0 0 0.0415 81 | children [ 82 | Shape { 83 | appearance PBRAppearance { 84 | baseColor 0 0 1 85 | roughness 1 86 | metalness 0 87 | } 88 | geometry DEF BODY Cylinder { 89 | height 0.08 90 | radius 0.045 91 | } 92 | } 93 | ] 94 | } 95 | DistanceSensor { 96 | translation 0.042 0.02 0.063 97 | rotation 0 0 1 0.5236003061004253 98 | children [ 99 | DEF SENSOR Transform { 100 | rotation 0 1 0 1.5708 101 | children [ 102 | Shape { 103 | appearance PBRAppearance { 104 | baseColor 1 1 0 105 | roughness 1 106 | metalness 0 107 | } 108 | geometry Cylinder { 109 | height 0.004 110 | radius 0.008 111 | } 112 | } 113 | ] 114 | } 115 | ] 116 | name "ds0" 117 | lookupTable [ 118 | 0 1020 0 119 | 0.05 1020 0 120 | 0.15 0 0 121 | ] 122 | numberOfRays 2 123 | aperture 1 124 | } 125 | DistanceSensor { 126 | translation 0.042 -0.02 0.063 127 | rotation 0 0 1 -0.5235996938995747 128 | children [ 129 | USE SENSOR 130 | ] 131 | name "ds1" 132 | lookupTable [ 133 | 0 1020 0 134 | 0.05 1020 0 135 | 0.15 0 0 136 | ] 137 | numberOfRays 2 138 | aperture 1 139 | } 140 | ] 141 | boundingObject Transform { 142 | translation 0 0 0.0415 143 | children [ 144 | USE BODY 145 | ] 146 | } 147 | physics Physics { 148 | } 149 | controller "" 150 | name "mbot_car" 151 | } 152 | -------------------------------------------------------------------------------- /launch_example/launch_example/substitution_launch.py: -------------------------------------------------------------------------------- 1 | from launch_ros.actions import Node 2 | 3 | from launch import LaunchDescription 4 | from launch.actions import DeclareLaunchArgument, ExecuteProcess, TimerAction 5 | from launch.conditions import IfCondition 6 | from launch.substitutions import LaunchConfiguration, PythonExpression 7 | # 导入logging模块来获取logger,这是launch原生支持的日志模块 8 | import launch.logging 9 | 10 | def generate_launch_description(): 11 | logger = launch.logging.get_logger('main_substitution_launch_debugger') 12 | # 当由 main_launch.py 启动时,这句会打印两次 13 | # 当由本文件启动时,这句只打印一次,知道就好 14 | logger.info('main_substitution_launch.py is started.') 15 | 16 | # 创建命名空间的配置变量 17 | # 创建是否使用指定红色值的配置变量 18 | # 创建新的红色背景值的配置变量 19 | turtlesim_ns = LaunchConfiguration('turtlesim_ns') 20 | use_provided_red = LaunchConfiguration('use_provided_red') 21 | new_background_r = LaunchConfiguration('new_background_r') 22 | 23 | # Tips:launch 文件申明可传入参数的方法 24 | # 声明命名空间配置, 是否使用指定红色值, 新的红色背景值的启动参数, 分别对应三个配置变量 25 | # 使用 DeclareLaunchArgument 申明的启动参数, 允许从外部为这些参数提供值。 26 | # 在这个例子中, 这三个参数将从 main_launch.py 中传入 27 | turtlesim_ns_launch_arg = DeclareLaunchArgument( 28 | 'turtlesim_ns', 29 | default_value='' 30 | ) 31 | use_provided_red_launch_arg = DeclareLaunchArgument( 32 | 'use_provided_red', 33 | default_value='False' 34 | ) 35 | new_background_r_launch_arg = DeclareLaunchArgument( 36 | 'new_background_r', 37 | default_value='200' 38 | ) 39 | 40 | # 实例化一个Node, 用于启动 turtlesim 节点 41 | turtlesim_node = Node( 42 | package='turtlesim', 43 | namespace=turtlesim_ns, 44 | executable='turtlesim_node', 45 | name='sim' 46 | ) 47 | # Tips:launch 文件中调用命令行方法 48 | # 实例化一个ExecuteProcess, 用于在3秒后生成一个乌龟 49 | spawn_turtle = ExecuteProcess( 50 | cmd=[[ 51 | 'ros2 service call ', 52 | turtlesim_ns, 53 | '/spawn ', 54 | 'turtlesim/srv/Spawn ', 55 | '"{x: 2, y: 2, theta: 0.2}"' 56 | ]], 57 | shell=True 58 | ) 59 | # 实例化三个ExecuteProcess, 用于启动3秒后改变背景颜色为护眼绿 60 | change_background_r = ExecuteProcess( 61 | cmd=[[ 62 | 'ros2 param set ', 63 | turtlesim_ns, 64 | '/sim background_r 199' 65 | ]], # 这个逗号是必须的,不能删除 66 | shell=True 67 | ) 68 | change_background_g = ExecuteProcess( 69 | cmd=[[ 70 | 'ros2 param set ', 71 | turtlesim_ns, 72 | '/sim background_g 237' 73 | ]], 74 | shell=True 75 | ) 76 | change_background_b = ExecuteProcess( 77 | cmd=[[ 78 | 'ros2 param set ', 79 | turtlesim_ns, 80 | '/sim background_b 204' 81 | ]], 82 | shell=True 83 | ) 84 | # 实例化一个条件ExecuteProcess, 如果外部 main_launch.py 传入的新的红色背景值为240且使用指定红色值,则改变背景颜色为240 85 | change_background_r_conditioned = ExecuteProcess( 86 | condition=IfCondition( 87 | PythonExpression([ 88 | new_background_r, 89 | ' == 240', 90 | ' and ', 91 | use_provided_red 92 | ]) 93 | ), 94 | cmd=[[ 95 | 'ros2 param set ', 96 | turtlesim_ns, 97 | '/sim background_r ', 98 | new_background_r 99 | ]], 100 | shell=True 101 | ) 102 | 103 | # 前面都是定义各种变量和实例化各种对象,这里是返回最终的LaunchDescription对象 104 | # 如果launch文件比较复杂,就推荐这种方式,便于修改和抽象,而不是直接把内容在LaunchDescription中展开 105 | return LaunchDescription([ 106 | # 先申明三个启动参数 107 | turtlesim_ns_launch_arg, 108 | use_provided_red_launch_arg, 109 | new_background_r_launch_arg, 110 | # 启动 turtlesim 节点,预留五秒等待时间,不然后面的执行将报错 111 | # 五秒是粗略估计,并不准确,完美的解决方案是 event handler 112 | turtlesim_node, 113 | # 5秒后,调用spawn服务,生成一个乌龟,并把背景色改为护眼绿 114 | TimerAction( 115 | period=5.0, 116 | actions=[spawn_turtle, 117 | change_background_r, 118 | change_background_g, 119 | change_background_b], 120 | ), 121 | # 8秒后,如果main_launch.py传入的参数符合条件,则改变背景颜色的red值 122 | TimerAction( 123 | period=8.0, 124 | actions=[change_background_r_conditioned], 125 | ) 126 | ]) -------------------------------------------------------------------------------- /action_cpp/src/fibonacci_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rclcpp/rclcpp.hpp" 7 | #include "rclcpp_action/rclcpp_action.hpp" 8 | 9 | #include "diy_interface/action/fibonacci.hpp" 10 | 11 | namespace action_cpp { 12 | 13 | class FibonacciActionClient : public rclcpp::Node { 14 | public: 15 | using Fibonacci = diy_interface::action::Fibonacci; 16 | using GoalHandleFibonacci = rclcpp_action::ClientGoalHandle; 17 | 18 | FibonacciActionClient() : Node("fibonacci_action_client") { 19 | client_ = rclcpp_action::create_client(this, "fibonacci"); 20 | timer_ = this->create_wall_timer( 21 | std::chrono::milliseconds(500), 22 | std::bind(&FibonacciActionClient::send_goal, this)); 23 | RCLCPP_INFO(this->get_logger(), "Fibonacci action client has been started"); 24 | } 25 | 26 | void send_goal() { 27 | // 取消定时器,因此只调用一次,发送一次action goal 给 server 28 | this->timer_->cancel(); 29 | 30 | RCLCPP_INFO(this->get_logger(), "waiting for action server"); 31 | 32 | if (!client_->wait_for_action_server()) { 33 | RCLCPP_ERROR(this->get_logger(), "action server not available after waiting"); 34 | rclcpp::shutdown(); 35 | return; 36 | } 37 | 38 | RCLCPP_INFO(this->get_logger(), "action server is available"); 39 | 40 | auto goal_msg = Fibonacci::Goal(); 41 | goal_msg.order = 10; 42 | auto send_goal_options = rclcpp_action::Client::SendGoalOptions(); 43 | send_goal_options.goal_response_callback = std::bind(&FibonacciActionClient::goal_response_callback, this, std::placeholders::_1); 44 | send_goal_options.feedback_callback = std::bind(&FibonacciActionClient::feedback_callback, this, std::placeholders::_1, std::placeholders::_2); 45 | send_goal_options.result_callback = std::bind(&FibonacciActionClient::result_callback, this, std::placeholders::_1); 46 | client_->async_send_goal(goal_msg, send_goal_options); 47 | RCLCPP_INFO(this->get_logger(), "send goal to server, order is %d", goal_msg.order); 48 | } 49 | 50 | private: 51 | void goal_response_callback(const GoalHandleFibonacci::SharedPtr & goal_handle) { 52 | if (!goal_handle) { 53 | RCLCPP_ERROR(this->get_logger(), "goal was rejected by server"); 54 | } else { 55 | RCLCPP_INFO(this->get_logger(), "goal accepted by server, waiting for result"); 56 | } 57 | } 58 | 59 | // 第一个参数虽然没有使用,但是必须写上,否则编译器会报错 60 | void feedback_callback(GoalHandleFibonacci::SharedPtr, 61 | const std::shared_ptr feedback) { 62 | std::stringstream ss; 63 | ss << "next number in sequence received: "; 64 | for (auto number : feedback->partial_sequence) { 65 | ss << number << " "; 66 | } 67 | RCLCPP_INFO(this->get_logger(), ss.str().c_str()); 68 | } 69 | 70 | void result_callback(const GoalHandleFibonacci::WrappedResult & result) { 71 | switch (result.code) { 72 | case rclcpp_action::ResultCode::SUCCEEDED: 73 | break; 74 | case rclcpp_action::ResultCode::ABORTED: 75 | RCLCPP_ERROR(this->get_logger(), "goal was aborted"); 76 | return; 77 | case rclcpp_action::ResultCode::CANCELED: 78 | RCLCPP_ERROR(this->get_logger(), "goal was canceled"); 79 | return; 80 | default: 81 | RCLCPP_ERROR(this->get_logger(), "unknown result code"); 82 | return; 83 | 84 | std::stringstream ss; 85 | ss << "result received: "; 86 | for (auto number : result.result->sequence) { 87 | ss << number << " "; 88 | } 89 | RCLCPP_INFO(this->get_logger(), ss.str().c_str()); 90 | rclcpp::shutdown(); 91 | return; 92 | } 93 | } 94 | 95 | private: 96 | rclcpp_action::Client::SharedPtr client_; 97 | rclcpp::TimerBase::SharedPtr timer_; 98 | 99 | }; // class FibonacciActionClient 100 | 101 | 102 | } // namespace action_cpp 103 | 104 | int main(int argc, char* argv[]) { 105 | rclcpp::init(argc, argv); 106 | 107 | rclcpp::spin(std::make_shared()); 108 | 109 | rclcpp::shutdown(); 110 | 111 | return 0; 112 | } -------------------------------------------------------------------------------- /bag_operator/scripts/bag_filter.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import argparse 6 | import logging 7 | import rosbag2_py 8 | 9 | logging.basicConfig(level=logging.DEBUG) 10 | 11 | class BagFilter(object): 12 | def __init__(self, input_bag, output_dir, start_offset, end_offset, topics): 13 | self._input_bag = input_bag 14 | self._output_dir = output_dir 15 | self._start_offset = start_offset 16 | self._end_offset = end_offset 17 | print("{0} {1}".format(self._start_offset, self._end_offset)) 18 | self._topics = topics 19 | self._reader = rosbag2_py.SequentialReader() 20 | self._writer = rosbag2_py.SequentialWriter() 21 | 22 | 23 | def filter_bag(self): 24 | # 以sqlite3格式打开ros2 bag 25 | in_storage_options = rosbag2_py._storage.StorageOptions(uri=self._input_bag, storage_id='sqlite3') 26 | self._reader.open(in_storage_options, rosbag2_py._storage.ConverterOptions('', '')) 27 | # 设置要读取的topic作为过滤条件,如果没有指定topic,则读取所有topic 28 | if self._topics: 29 | storage_filter = rosbag2_py._storage.StorageFilter(topics=self._topics) 30 | self._reader.set_filter(storage_filter) 31 | 32 | # 以sqlite3格式创建ros2 bag 33 | out_storage_options = rosbag2_py._storage.StorageOptions(uri=self._output_dir, storage_id='sqlite3') 34 | self._writer.open(out_storage_options, rosbag2_py._storage.ConverterOptions('', '')) 35 | 36 | # 在 writer 中注册输入bag中所有的topic,为写入做准备 37 | for topic_metadata in self._reader.get_all_topics_and_types(): 38 | # print(topic_metadata.name) 39 | topic_info = rosbag2_py._storage.TopicMetadata( 40 | name = topic_metadata.name, 41 | type = topic_metadata.type, 42 | serialization_format='cdr') 43 | self._writer.create_topic(topic_info) 44 | 45 | # 获取开始和结束时间:从 datatime.datetime 和 datetime.timedelta 转换为 ns 46 | in_metadata = rosbag2_py.Info().read_metadata(self._input_bag, 'sqlite3') 47 | bag_start_time_ns = int(in_metadata.starting_time.timestamp()* 1e9) 48 | bag_end_time_ns = bag_start_time_ns + int(in_metadata.duration.days * 24 * 60 * 60 * 1e9 + in_metadata.duration.seconds * 1e9 + in_metadata.duration.microseconds * 1e3) 49 | cut_start_time_ns = int(bag_start_time_ns + self._start_offset * 1e9) 50 | cut_end_time_ns = int(bag_end_time_ns - self._end_offset * 1e9) 51 | 52 | # 循环读取消息,判断时间范围后,并写入新bag 53 | while self._reader.has_next(): 54 | (topic_name, data, t) = self._reader.read_next() 55 | if cut_start_time_ns <= t <= cut_end_time_ns: 56 | self._writer.write(topic_name, data, t) 57 | 58 | # 获取输出bag的topic列表和meta信息 59 | out_reader = rosbag2_py.SequentialReader() 60 | output_bag = os.path.join(self._output_dir, os.path.basename(self._output_dir) + "_0.db3") 61 | db3_storage_options = rosbag2_py._storage.StorageOptions(uri=output_bag, storage_id='sqlite3') 62 | out_reader.open(db3_storage_options, rosbag2_py._storage.ConverterOptions('', '')) 63 | out_topic_list = [topic_metadata.name for topic_metadata in out_reader.get_all_topics_and_types()] 64 | out_metadata = rosbag2_py.Info().read_metadata(output_bag, 'sqlite3') 65 | 66 | # 打印摘要信息 67 | logging.info("------------[%s summary]------------" %self._output_dir) 68 | logging.info("time span %s [origin %s]" %(out_metadata.duration, in_metadata.duration)) 69 | logging.info("topic list %s" %out_topic_list) 70 | 71 | def main(): 72 | parser = argparse.ArgumentParser(description="filter ros2 bag depends time offset and topics") 73 | parser.add_argument("-i", "--input_bag", type=str, required=True, help="specify input rosbag") 74 | parser.add_argument("-o", "--output_dir", type=str, required=True, help="specify output rosbag") 75 | parser.add_argument("-s", "--start_offset_sec", type=int, default=0, help="specify start offset time") 76 | parser.add_argument("-e", "--end_offset_sec", type=int, default=0, help="specify end offset time") 77 | parser.add_argument("-t", "--topics", nargs="+", type=str, help="specify topic") 78 | parser.add_argument('extra_args', nargs='*', help=argparse.SUPPRESS) 79 | args=parser.parse_args() 80 | 81 | if not os.path.isfile(args.input_bag): 82 | logging.error("%s is no found!" %args.input_bag) 83 | return 84 | 85 | filter = BagFilter(args.input_bag, args.output_dir, args.start_offset_sec, args.end_offset_sec, args.topics) 86 | filter.filter_bag() 87 | 88 | if __name__ == "__main__": 89 | main() --------------------------------------------------------------------------------