├── .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()
--------------------------------------------------------------------------------