├── LICENSE
├── README.ja.md
├── README.md
├── docs
├── mrp.png
└── whill_auto_stop_node_graph.png
└── whill_auto_stop
├── CMakeLists.txt
├── README.md
├── config
├── VLP16-velodyne_driver_node-params.yaml
├── VLP16-velodyne_transform_node-params.yaml
└── auto_stop_area.yaml
├── launch
├── bringup_launch.py
└── velodyne_launch.py
├── package.xml
├── rviz
└── debug.rviz
└── src
├── laserscan_filter_node.cpp
└── twist_filter_node.cpp
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 WHILL, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.ja.md:
--------------------------------------------------------------------------------
1 | # ros2_whill_applications
2 |
3 | WHILLの[電動モビリティプラットフォーム](https://whill-mrp.notion.site/WHILL-f975baf4015e4eebbb243a7d331efb0a)用ROS 2ドライバである[whill (whill-labs/ros2_whill)](https://github.com/whill-labs/ros2_whill/)を使ったアプリケーション実装例です。
4 |
5 | 
6 |
7 | 電動モビリティプラットフォーム以外にセンサ等の準備が必要になるサンプルもあります。
8 |
9 | ## Examples
10 |
11 | ### whill_auto_stop
12 |
13 | * 動作確認済みディストリビューション:Jazzy
14 | * 追加ハードウェア:あり
15 |
16 | TwistメッセージをSubscribeして走行します。その際、周囲の障害物に近づき過ぎたら停止するサンプルです。
17 |
18 | ロボット台車にOuster(旧Velodyne)社製 VLP-16を搭載しています。
19 |
20 | 詳細は[whill_auto_stop/README.md](whill_auto_stop/README.md)を参照ください。
21 |
22 | ## Usage
23 |
24 | ### 1. ROS 2のインストール
25 |
26 |
27 | #### 公式ドキュメントに沿って進める方法
28 |
29 | https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html を参考に、ROS 2 Jazzyをインストールします。
30 |
31 | また、 https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Colcon-Tutorial.html を参考にビルドツールであるcolconをインストールします。
32 |
33 | #### インストールスクリプトを使って進める方法
34 |
35 | 有志が公開する(非公式の)インストールスクリプトでもインストールできます。
36 | その場合は下記のコマンドでROS 2 Jazzyをインストールします。
37 |
38 | ```sh
39 | git clone https://github.com/Tiryoh/ros2_setup_scripts_ubuntu.git
40 | cd ros2_setup_scripts_ubuntu
41 | ./ros2-jazzy-desktop-main.sh
42 | ```
43 |
44 | ### 2. WHILLパッケージのインストール
45 |
46 | `$HOME/ros2_ws`を使う場合、下記のコマンドでインストールできます。
47 |
48 | ```sh
49 | # ダウンロード
50 | cd ~/ros2_ws/src
51 | git clone -b $ROS_DISTRO https://github.com/whill-labs/ros2_whill_interfaces.git
52 | git clone -b $ROS_DISTRO https://github.com/whill-labs/ros2_whill.git
53 | git clone https://github.com/whill-labs/ros2_whill_applications.git
54 | # ビルド
55 | cd ~/ros2_ws
56 | colcon build
57 | source install/setup.bash # zshの場合はsetup.zsh
58 | ```
59 |
60 | ### 3. 各デバイスを接続する
61 |
62 | PCとロボット台車、LiDAR等を接続します。
63 |
64 | ### 4. launchファイルを起動する
65 |
66 | whill_auto_stopの場合は以下のコマンドを実行します。
67 |
68 | ```
69 | ros2 launch whill_auto_stop bringup_launch.py
70 | ```
71 |
72 | 詳細は[whill_auto_stop/README.md](whill_auto_stop/README.md)を参照ください。
73 |
74 | ## Contact
75 |
76 | Email: `mrp.contact[at]whill.inc`
77 |
78 | WHILLの電動モビリティプラットフォームについては下記サイトをご覧ください。
79 |
80 | [電動モビリティプラットフォーム](https://whill-mrp.notion.site/WHILL-f975baf4015e4eebbb243a7d331efb0a)
81 |
82 | ## LICENSE
83 |
84 | Copyright (c) 2024 WHILL, Inc.
85 |
86 | MITライセンスで公開しています。詳細は[LICENSE](./LICENSE)をご参照ください。
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | README.ja.md
--------------------------------------------------------------------------------
/docs/mrp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whill-labs/ros2_whill_applications/1d8336219c7e54371f19e5f8ddc1520d7912210b/docs/mrp.png
--------------------------------------------------------------------------------
/docs/whill_auto_stop_node_graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whill-labs/ros2_whill_applications/1d8336219c7e54371f19e5f8ddc1520d7912210b/docs/whill_auto_stop_node_graph.png
--------------------------------------------------------------------------------
/whill_auto_stop/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.8)
2 | project(whill_auto_stop)
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(sensor_msgs REQUIRED)
13 | find_package(std_msgs REQUIRED)
14 | find_package(tf2 REQUIRED)
15 | find_package(tf2_geometry_msgs REQUIRED)
16 | find_package(tf2_ros REQUIRED)
17 |
18 | add_executable(twist_filter_node src/twist_filter_node.cpp)
19 | ament_target_dependencies(twist_filter_node
20 | geometry_msgs
21 | rclcpp
22 | std_msgs
23 | )
24 | install(TARGETS twist_filter_node
25 | DESTINATION lib/${PROJECT_NAME}
26 | )
27 |
28 | add_executable(laserscan_filter_node src/laserscan_filter_node.cpp)
29 | ament_target_dependencies(laserscan_filter_node
30 | geometry_msgs
31 | rclcpp
32 | sensor_msgs
33 | std_msgs
34 | tf2
35 | tf2_geometry_msgs
36 | tf2_ros
37 | )
38 | install(TARGETS laserscan_filter_node
39 | DESTINATION lib/${PROJECT_NAME}
40 | )
41 |
42 | install(DIRECTORY launch config rviz
43 | DESTINATION share/${PROJECT_NAME})
44 |
45 | if(BUILD_TESTING)
46 | find_package(ament_lint_auto REQUIRED)
47 | set(ament_cmake_copyright_FOUND TRUE)
48 | set(ament_cmake_cpplint_FOUND TRUE)
49 |
50 | # uncurstifyの代わりにclang-formatを使う
51 | find_package(ament_cmake_clang_format REQUIRED)
52 | set(ament_cmake_uncrustify_FOUND TRUE)
53 |
54 | ament_lint_auto_find_test_dependencies()
55 | endif()
56 |
57 | ament_package()
58 |
--------------------------------------------------------------------------------
/whill_auto_stop/README.md:
--------------------------------------------------------------------------------
1 | # whill_auto_stop
2 |
3 | * 動作確認済みディストリビューション:Jazzy
4 | * 追加ハードウェア:あり
5 |
6 | TwistメッセージをSubscribeして走行します。その際、周囲の障害物に近づき過ぎたら停止するサンプルです。
7 |
8 | ロボット台車にOuster(旧Velodyne)社製 VLP-16を搭載しています。
9 |
10 | https://github.com/user-attachments/assets/d6be0824-2cd3-4a8c-8105-cd8a80746ce9
11 |
12 | ## ノード構成
13 |
14 | 
15 |
16 | ## 使用方法
17 |
18 | VLP-16の設定を必要に応じて変更します
19 |
20 | * `config/VLP16-velodyne_driver_node-params.yaml`
21 | * `config/VLP16-velodyne_transform_node-params.yaml`
22 |
23 | `bringup_launch.py`を起動します
24 |
25 | ```
26 | ros2 launch whill_auto_stop bringup_launch.py
27 | ```
28 |
--------------------------------------------------------------------------------
/whill_auto_stop/config/VLP16-velodyne_driver_node-params.yaml:
--------------------------------------------------------------------------------
1 | velodyne_driver_node:
2 | ros__parameters:
3 | device_ip: 192.168.67.202
4 | gps_time: false
5 | time_offset: 0.0
6 | enabled: true
7 | read_once: false
8 | read_fast: false
9 | repeat_delay: 0.0
10 | frame_id: velodyne
11 | model: VLP16
12 | rpm: 600.0
13 | port: 2268
14 | timestamp_first_packet: false
15 |
--------------------------------------------------------------------------------
/whill_auto_stop/config/VLP16-velodyne_transform_node-params.yaml:
--------------------------------------------------------------------------------
1 | velodyne_transform_node:
2 | ros__parameters:
3 | calibration: VLP16db.yaml
4 | model: VLP16
5 | min_range: 0.4
6 | max_range: 130.0
7 | view_direction: 0.0
8 | fixed_frame: ""
9 | target_frame: ""
10 | organize_cloud: true
11 |
--------------------------------------------------------------------------------
/whill_auto_stop/config/auto_stop_area.yaml:
--------------------------------------------------------------------------------
1 | /**/laserscan_filter_node:
2 | ros__parameters:
3 | reference_link: base_link
4 | forward:
5 | x_min: -0.3
6 | x_max: 1.0
7 | y_min: -0.5
8 | y_max: 0.5
9 | backward:
10 | x_min: -0.6
11 | x_max: 0.8
12 | y_min: -0.5
13 | y_max: 0.5
14 |
--------------------------------------------------------------------------------
/whill_auto_stop/launch/bringup_launch.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from ament_index_python.packages import get_package_share_directory
4 | from launch import LaunchDescription
5 | from launch.actions import DeclareLaunchArgument
6 | from launch.actions import IncludeLaunchDescription
7 | from launch.conditions import IfCondition
8 | from launch.launch_description_sources import PythonLaunchDescriptionSource
9 | from launch.substitutions import LaunchConfiguration
10 | from launch_ros.actions import Node
11 |
12 |
13 | def generate_launch_description():
14 | declare_arg_rviz = DeclareLaunchArgument(
15 | 'rviz', default_value='true', description='Set true to launch RViz'
16 | )
17 |
18 | whill_auto_stop_share_dir = get_package_share_directory(
19 | 'whill_auto_stop')
20 |
21 | whill_driver_launch = IncludeLaunchDescription(
22 | PythonLaunchDescriptionSource(
23 | [
24 | os.path.join(
25 | get_package_share_directory('whill_bringup'), 'launch',
26 | 'whill_launch.py'),
27 | ]
28 | ),
29 | )
30 |
31 | teleop_launch = IncludeLaunchDescription(
32 | PythonLaunchDescriptionSource(
33 | [
34 | os.path.join(
35 | get_package_share_directory('teleop_twist_joy'), 'launch',
36 | 'teleop-launch.py'),
37 | ]
38 | ),
39 | launch_arguments={
40 | 'joy_config': 'xbox',
41 | 'joy_vel': 'auto_stop/cmd_vel',
42 | }.items()
43 | )
44 |
45 | velodyne_launch = IncludeLaunchDescription(
46 | PythonLaunchDescriptionSource(
47 | [
48 | os.path.join(
49 | whill_auto_stop_share_dir, 'launch',
50 | 'velodyne_launch.py'),
51 | ]
52 | ),
53 | )
54 |
55 | laserscan_params_file = os.path.join(
56 | whill_auto_stop_share_dir, 'config', 'auto_stop_area.yaml')
57 | print(laserscan_params_file)
58 | laserscan_filter_node = Node(
59 | package='whill_auto_stop',
60 | executable='laserscan_filter_node',
61 | output='log',
62 | namespace='auto_stop',
63 | parameters=[laserscan_params_file],
64 | remappings=[
65 | ('scan', '/scan'),
66 | ],
67 | )
68 |
69 | twist_filter_node = Node(
70 | package='whill_auto_stop',
71 | executable='twist_filter_node',
72 | output='both',
73 | namespace='auto_stop',
74 | parameters=[{'negative_logic': True}],
75 | remappings=[
76 | ('enable', 'scan_in_range'),
77 | ('output_twist', '/whill/controller/cmd_vel'),
78 | ('input_twist', 'cmd_vel'),
79 | ],
80 | )
81 |
82 | rviz_node = Node(
83 | package='rviz2',
84 | executable='rviz2',
85 | output='screen',
86 | arguments=['-d', os.path.join(
87 | whill_auto_stop_share_dir, 'rviz', 'debug.rviz')],
88 | condition=IfCondition(LaunchConfiguration('rviz'))
89 | )
90 |
91 | ld = LaunchDescription()
92 |
93 | ld.add_action(declare_arg_rviz)
94 | ld.add_action(teleop_launch)
95 | ld.add_action(velodyne_launch)
96 | ld.add_action(whill_driver_launch)
97 | ld.add_action(laserscan_filter_node)
98 | ld.add_action(twist_filter_node)
99 | ld.add_action(rviz_node)
100 |
101 | return ld
102 |
--------------------------------------------------------------------------------
/whill_auto_stop/launch/velodyne_launch.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import yaml
4 |
5 | from ament_index_python.packages import get_package_share_directory
6 | import launch
7 | from launch import LaunchDescription
8 | from launch.actions import RegisterEventHandler, EmitEvent, IncludeLaunchDescription
9 | from launch.event_handlers import OnProcessExit
10 | from launch.launch_description_sources import PythonLaunchDescriptionSource
11 | from launch_ros.actions import Node
12 |
13 |
14 | def generate_launch_description():
15 | whill_auto_stop_share_dir = get_package_share_directory(
16 | 'whill_auto_stop')
17 |
18 | driver_params_file = os.path.join(
19 | whill_auto_stop_share_dir, 'config', 'VLP16-velodyne_driver_node-params.yaml')
20 | velodyne_driver_node = Node(
21 | package='velodyne_driver',
22 | executable='velodyne_driver_node',
23 | output='both',
24 | parameters=[driver_params_file]
25 | )
26 |
27 | convert_share_dir = get_package_share_directory(
28 | 'velodyne_pointcloud')
29 | convert_params_file = os.path.join(
30 | whill_auto_stop_share_dir, 'config', 'VLP16-velodyne_transform_node-params.yaml')
31 | with open(convert_params_file, 'r') as f:
32 | convert_params = yaml.safe_load(f)['velodyne_transform_node']['ros__parameters']
33 | convert_params['calibration'] = os.path.join(
34 | convert_share_dir, 'params', 'VLP16db.yaml')
35 | velodyne_transform_node = Node(
36 | package='velodyne_pointcloud',
37 | executable='velodyne_transform_node',
38 | output='both',
39 | parameters=[convert_params]
40 | )
41 |
42 | laserscan_share_dir = get_package_share_directory(
43 | 'velodyne_laserscan')
44 | laserscan_params_file = os.path.join(
45 | laserscan_share_dir, 'config', 'default-velodyne_laserscan_node-params.yaml')
46 | velodyne_laserscan_node = Node(
47 | package='velodyne_laserscan',
48 | executable='velodyne_laserscan_node',
49 | output='both',
50 | parameters=[laserscan_params_file]
51 | )
52 |
53 | display_robot_launch = IncludeLaunchDescription(
54 | PythonLaunchDescriptionSource(
55 | [
56 | os.path.join(get_package_share_directory('whill_description'), 'launch',
57 | 'description_launch.py'),
58 | ]
59 | ),
60 | )
61 |
62 | static_transform_publisher_node = Node(
63 | package='tf2_ros',
64 | executable='static_transform_publisher',
65 | output='screen',
66 | arguments=['0.18', '0', '0.35', '0', '3.14', '3.14', 'base_link', 'velodyne'],
67 | )
68 |
69 | event_handler = RegisterEventHandler(
70 | event_handler=OnProcessExit(
71 | target_action=velodyne_driver_node,
72 | on_exit=[EmitEvent(
73 | event=launch.events.Shutdown())],
74 | )
75 | )
76 |
77 | ld = LaunchDescription()
78 |
79 | ld.add_action(velodyne_driver_node)
80 | ld.add_action(velodyne_transform_node)
81 | ld.add_action(velodyne_laserscan_node)
82 |
83 | ld.add_action(display_robot_launch)
84 | ld.add_action(static_transform_publisher_node)
85 |
86 | ld.add_action(event_handler)
87 |
88 | return ld
89 |
--------------------------------------------------------------------------------
/whill_auto_stop/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | whill_auto_stop
5 | 0.0.0
6 | Example of implementation of "auto stop" to stop driving when an obstacle is approaching
7 | Daisuke Sato
8 | George Mandokoro
9 | MIT
10 |
11 | ament_cmake
12 | rclcpp
13 | geometry_msgs
14 | std_msgs
15 | sensor_msgs
16 | tf2
17 | tf2_geometry_msgs
18 | tf2_ros
19 | velodyne_driver
20 | velodyne_laserscan
21 | velodyne_pointcloud
22 |
23 | ament_lint_auto
24 | ament_lint_common
25 | ament_cmake_clang_format
26 |
27 |
28 | ament_cmake
29 |
30 |
31 |
--------------------------------------------------------------------------------
/whill_auto_stop/rviz/debug.rviz:
--------------------------------------------------------------------------------
1 | Panels:
2 | - Class: rviz_common/Displays
3 | Help Height: 78
4 | Name: Displays
5 | Property Tree Widget:
6 | Expanded:
7 | - /Global Options1
8 | - /Status1
9 | Splitter Ratio: 0.5
10 | Tree Height: 555
11 | - Class: rviz_common/Selection
12 | Name: Selection
13 | - Class: rviz_common/Tool Properties
14 | Expanded:
15 | - /2D Goal Pose1
16 | - /Publish Point1
17 | Name: Tool Properties
18 | Splitter Ratio: 0.5886790156364441
19 | - Class: rviz_common/Views
20 | Expanded:
21 | - /Current View1
22 | Name: Views
23 | Splitter Ratio: 0.5
24 | - Class: rviz_common/Time
25 | Experimental: false
26 | Name: Time
27 | SyncMode: 0
28 | SyncSource: AutostopLaserScan
29 | Visualization Manager:
30 | Class: ""
31 | Displays:
32 | - Alpha: 0.5
33 | Cell Size: 1
34 | Class: rviz_default_plugins/Grid
35 | Color: 160; 160; 164
36 | Enabled: true
37 | Line Style:
38 | Line Width: 0.029999999329447746
39 | Value: Lines
40 | Name: Grid
41 | Normal Cell Count: 0
42 | Offset:
43 | X: 0
44 | Y: 0
45 | Z: 0
46 | Plane: XY
47 | Plane Cell Count: 10
48 | Reference Frame:
49 | Value: true
50 | - Alpha: 1
51 | Class: rviz_default_plugins/RobotModel
52 | Collision Enabled: false
53 | Description File: ""
54 | Description Source: Topic
55 | Description Topic:
56 | Depth: 5
57 | Durability Policy: Volatile
58 | History Policy: Keep Last
59 | Reliability Policy: Reliable
60 | Value: /robot_description
61 | Enabled: true
62 | Links:
63 | All Links Enabled: true
64 | Expand Joint Details: false
65 | Expand Link Details: false
66 | Expand Tree: false
67 | Link Tree Style: Links in Alphabetic Order
68 | backrest:
69 | Alpha: 1
70 | Show Axes: false
71 | Show Trail: false
72 | Value: true
73 | base_floor:
74 | Alpha: 1
75 | Show Axes: false
76 | Show Trail: false
77 | Value: true
78 | base_link:
79 | Alpha: 1
80 | Show Axes: false
81 | Show Trail: false
82 | Value: true
83 | left_arm:
84 | Alpha: 1
85 | Show Axes: false
86 | Show Trail: false
87 | Value: true
88 | left_front_wheel:
89 | Alpha: 1
90 | Show Axes: false
91 | Show Trail: false
92 | Value: true
93 | left_sensor_arm:
94 | Alpha: 1
95 | Show Axes: false
96 | Show Trail: false
97 | Value: true
98 | left_wheel:
99 | Alpha: 1
100 | Show Axes: false
101 | Show Trail: false
102 | Value: true
103 | right_arm:
104 | Alpha: 1
105 | Show Axes: false
106 | Show Trail: false
107 | Value: true
108 | right_front_wheel:
109 | Alpha: 1
110 | Show Axes: false
111 | Show Trail: false
112 | Value: true
113 | right_sensor_arm:
114 | Alpha: 1
115 | Show Axes: false
116 | Show Trail: false
117 | Value: true
118 | right_wheel:
119 | Alpha: 1
120 | Show Axes: false
121 | Show Trail: false
122 | Value: true
123 | seat:
124 | Alpha: 1
125 | Show Axes: false
126 | Show Trail: false
127 | Value: true
128 | Mass Properties:
129 | Inertia: false
130 | Mass: false
131 | Name: RobotModel
132 | TF Prefix: ""
133 | Update Interval: 0
134 | Value: true
135 | Visual Enabled: true
136 | - Class: rviz_default_plugins/TF
137 | Enabled: true
138 | Filter (blacklist): ""
139 | Filter (whitelist): ""
140 | Frame Timeout: 15
141 | Frames:
142 | All Enabled: true
143 | backrest:
144 | Value: true
145 | base_floor:
146 | Value: true
147 | base_link:
148 | Value: true
149 | left_arm:
150 | Value: true
151 | left_front_wheel:
152 | Value: true
153 | left_sensor_arm:
154 | Value: true
155 | left_wheel:
156 | Value: true
157 | right_arm:
158 | Value: true
159 | right_front_wheel:
160 | Value: true
161 | right_sensor_arm:
162 | Value: true
163 | right_wheel:
164 | Value: true
165 | seat:
166 | Value: true
167 | velodyne:
168 | Value: true
169 | Marker Scale: 1
170 | Name: TF
171 | Show Arrows: true
172 | Show Axes: true
173 | Show Names: false
174 | Tree:
175 | base_link:
176 | base_floor:
177 | backrest:
178 | {}
179 | left_front_wheel:
180 | {}
181 | left_wheel:
182 | {}
183 | right_front_wheel:
184 | {}
185 | right_wheel:
186 | {}
187 | seat:
188 | left_arm:
189 | {}
190 | left_sensor_arm:
191 | {}
192 | right_arm:
193 | {}
194 | right_sensor_arm:
195 | {}
196 | velodyne:
197 | {}
198 | Update Interval: 0
199 | Value: true
200 | - Alpha: 1
201 | Autocompute Intensity Bounds: true
202 | Autocompute Value Bounds:
203 | Max Value: 10
204 | Min Value: -10
205 | Value: true
206 | Axis: Z
207 | Channel Name: intensity
208 | Class: rviz_default_plugins/LaserScan
209 | Color: 255; 255; 255
210 | Color Transformer: Intensity
211 | Decay Time: 0
212 | Enabled: true
213 | Invert Rainbow: false
214 | Max Color: 255; 255; 255
215 | Max Intensity: -999999
216 | Min Color: 255; 0; 0
217 | Min Intensity: 999999
218 | Name: AutostopLaserScan
219 | Position Transformer: XYZ
220 | Selectable: true
221 | Size (Pixels): 3
222 | Size (m): 0.10000000149011612
223 | Style: Flat Squares
224 | Topic:
225 | Depth: 5
226 | Durability Policy: Volatile
227 | Filter size: 10
228 | History Policy: Keep Last
229 | Reliability Policy: Reliable
230 | Value: /auto_stop/detected_points
231 | Use Fixed Frame: true
232 | Use rainbow: false
233 | Value: true
234 | - Alpha: 1
235 | Class: rviz_default_plugins/Polygon
236 | Color: 25; 255; 0
237 | Enabled: true
238 | Name: Polygon
239 | Topic:
240 | Depth: 5
241 | Durability Policy: Volatile
242 | Filter size: 10
243 | History Policy: Keep Last
244 | Reliability Policy: Reliable
245 | Value: /auto_stop/scan_range_polygon
246 | Value: true
247 | - Alpha: 1
248 | Autocompute Intensity Bounds: true
249 | Autocompute Value Bounds:
250 | Max Value: 10
251 | Min Value: -10
252 | Value: true
253 | Axis: Z
254 | Channel Name: intensity
255 | Class: rviz_default_plugins/LaserScan
256 | Color: 255; 255; 255
257 | Color Transformer: Intensity
258 | Decay Time: 0
259 | Enabled: true
260 | Invert Rainbow: false
261 | Max Color: 255; 255; 255
262 | Max Intensity: 224
263 | Min Color: 0; 0; 0
264 | Min Intensity: 1
265 | Name: LaserScan
266 | Position Transformer: XYZ
267 | Selectable: true
268 | Size (Pixels): 3
269 | Size (m): 0.009999999776482582
270 | Style: Flat Squares
271 | Topic:
272 | Depth: 5
273 | Durability Policy: Volatile
274 | Filter size: 10
275 | History Policy: Keep Last
276 | Reliability Policy: Reliable
277 | Value: /scan
278 | Use Fixed Frame: true
279 | Use rainbow: true
280 | Value: true
281 | - Alpha: 1
282 | Autocompute Intensity Bounds: true
283 | Autocompute Value Bounds:
284 | Max Value: 10
285 | Min Value: -10
286 | Value: true
287 | Axis: Z
288 | Channel Name: intensity
289 | Class: rviz_default_plugins/PointCloud2
290 | Color: 255; 255; 255
291 | Color Transformer: Intensity
292 | Decay Time: 0
293 | Enabled: false
294 | Invert Rainbow: false
295 | Max Color: 255; 255; 255
296 | Max Intensity: 173
297 | Min Color: 0; 0; 0
298 | Min Intensity: 0
299 | Name: PointCloud2
300 | Position Transformer: XYZ
301 | Selectable: true
302 | Size (Pixels): 3
303 | Size (m): 0.009999999776482582
304 | Style: Flat Squares
305 | Topic:
306 | Depth: 5
307 | Durability Policy: Volatile
308 | History Policy: Keep Last
309 | Reliability Policy: Reliable
310 | Value: /velodyne_points
311 | Use Fixed Frame: true
312 | Use rainbow: true
313 | Value: false
314 | Enabled: true
315 | Global Options:
316 | Background Color: 48; 48; 48
317 | Fixed Frame: base_floor
318 | Frame Rate: 30
319 | Name: root
320 | Tools:
321 | - Class: rviz_default_plugins/Interact
322 | Hide Inactive Objects: true
323 | - Class: rviz_default_plugins/MoveCamera
324 | - Class: rviz_default_plugins/Select
325 | - Class: rviz_default_plugins/FocusCamera
326 | - Class: rviz_default_plugins/Measure
327 | Line color: 128; 128; 0
328 | - Class: rviz_default_plugins/SetInitialPose
329 | Covariance x: 0.25
330 | Covariance y: 0.25
331 | Covariance yaw: 0.06853891909122467
332 | Topic:
333 | Depth: 5
334 | Durability Policy: Volatile
335 | History Policy: Keep Last
336 | Reliability Policy: Reliable
337 | Value: /initialpose
338 | - Class: rviz_default_plugins/SetGoal
339 | Topic:
340 | Depth: 5
341 | Durability Policy: Volatile
342 | History Policy: Keep Last
343 | Reliability Policy: Reliable
344 | Value: /goal_pose
345 | - Class: rviz_default_plugins/PublishPoint
346 | Single click: true
347 | Topic:
348 | Depth: 5
349 | Durability Policy: Volatile
350 | History Policy: Keep Last
351 | Reliability Policy: Reliable
352 | Value: /clicked_point
353 | Transformation:
354 | Current:
355 | Class: rviz_default_plugins/TF
356 | Value: true
357 | Views:
358 | Current:
359 | Class: rviz_default_plugins/Orbit
360 | Distance: 6.196164608001709
361 | Enable Stereo Rendering:
362 | Stereo Eye Separation: 0.05999999865889549
363 | Stereo Focal Distance: 1
364 | Swap Stereo Eyes: false
365 | Value: false
366 | Focal Point:
367 | X: 0.381662517786026
368 | Y: -0.3795689344406128
369 | Z: 0.043379202485084534
370 | Focal Shape Fixed Size: true
371 | Focal Shape Size: 0.05000000074505806
372 | Invert Z Axis: false
373 | Name: Current View
374 | Near Clip Distance: 0.009999999776482582
375 | Pitch: 1.4697964191436768
376 | Target Frame:
377 | Value: Orbit (rviz)
378 | Yaw: 3.010402202606201
379 | Saved: ~
380 | Window Geometry:
381 | Displays:
382 | collapsed: false
383 | Height: 846
384 | Hide Left Dock: false
385 | Hide Right Dock: true
386 | QMainWindow State: 000000ff00000000fd000000040000000000000156000002b4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000002b4000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002b4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003b000002b4000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b00000025300fffffffb0000000800540069006d0065010000000000000450000000000000000000000354000002b400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
387 | Selection:
388 | collapsed: false
389 | Time:
390 | collapsed: false
391 | Tool Properties:
392 | collapsed: false
393 | Views:
394 | collapsed: true
395 | Width: 1200
396 | X: 60
397 | Y: 249
398 |
--------------------------------------------------------------------------------
/whill_auto_stop/src/laserscan_filter_node.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024 WHILL, Inc.
2 | // Released under the MIT license
3 | // https://opensource.org/licenses/mit-license.php
4 |
5 | #include
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | class LaserScanFilterNode : public rclcpp::Node {
20 | public:
21 | LaserScanFilterNode() : Node("laserscan_filter_node"), tf_buffer_(std::make_shared(RCL_ROS_TIME)), tf_listener_(tf_buffer_) {
22 | // Declare and get parameters
23 | this->declare_parameter("forward.x_min", -1.0);
24 | this->declare_parameter("forward.x_max", 1.0);
25 | this->declare_parameter("forward.y_min", -1.0);
26 | this->declare_parameter("forward.y_max", 1.0);
27 | this->declare_parameter("backward.x_min", -1.0);
28 | this->declare_parameter("backward.x_max", 1.0);
29 | this->declare_parameter("backward.y_min", -1.0);
30 | this->declare_parameter("backward.y_max", 1.0);
31 | this->declare_parameter("reference_link", "base_link");
32 |
33 | this->get_parameter("reference_link", reference_link_);
34 | this->get_parameter("forward.x_min", forward_x_min_);
35 | this->get_parameter("forward.x_max", forward_x_max_);
36 | this->get_parameter("forward.y_min", forward_y_min_);
37 | this->get_parameter("forward.y_max", forward_y_max_);
38 | this->get_parameter("backward.x_min", backward_x_min_);
39 | this->get_parameter("backward.x_max", backward_x_max_);
40 | this->get_parameter("backward.y_min", backward_y_min_);
41 | this->get_parameter("backward.y_max", backward_y_max_);
42 |
43 | // Subscriber for LaserScan messages
44 | laser_scan_subscriber_ = this->create_subscription(
45 | "scan", 10,
46 | std::bind(&LaserScanFilterNode::laserScanCallback, this, std::placeholders::_1));
47 |
48 | // Subscriber for velocity messages
49 | velocity_subscriber_ = this->create_subscription(
50 | "cmd_vel", 10,
51 | std::bind(&LaserScanFilterNode::velocityCallback, this, std::placeholders::_1));
52 |
53 | // Publisher for Bool messages
54 | bool_publisher_ = this->create_publisher("scan_in_range", 10);
55 |
56 | // Publisher for detected points
57 | detected_points_publisher_ = this->create_publisher("detected_points", 10);
58 |
59 | // Publisher for polygon visualization
60 | polygon_publisher_ = this->create_publisher("scan_range_polygon", 10);
61 |
62 | RCLCPP_INFO(this->get_logger(), "Laser Scan Filter Node has been started.");
63 | RCLCPP_INFO(this->get_logger(), "Reference link is set to: %s", reference_link_.c_str());
64 |
65 | }
66 |
67 | private:
68 | double getYawFromQuaternion(const geometry_msgs::msg::Quaternion &quat_msg)
69 | {
70 | tf2::Quaternion quat;
71 | tf2::fromMsg(quat_msg, quat);
72 |
73 | double roll, pitch, yaw;
74 | tf2::Matrix3x3(quat).getRPY(roll, pitch, yaw);
75 |
76 | return yaw;
77 | }
78 |
79 | void velocityCallback(const geometry_msgs::msg::Twist::SharedPtr msg) {
80 | // Check the linear x velocity to determine forward or bakward direction
81 | is_forward_ = (msg->linear.x >= 0);
82 | linear_x_ = msg->linear.x;
83 | RCLCPP_DEBUG(this->get_logger(), "Direction: %s", is_forward_ ? "Forward" : "Backward");
84 | }
85 |
86 | void laserScanCallback(const sensor_msgs::msg::LaserScan::SharedPtr msg) {
87 | bool in_range = false;
88 |
89 | // Select appropriate bounds based on direction
90 | double x_min = is_forward_ ? forward_x_min_ : backward_x_min_ + linear_x_;
91 | double x_max = is_forward_ ? forward_x_max_ + linear_x_ : backward_x_max_;
92 | double y_min = is_forward_ ? forward_y_min_ : backward_y_min_;
93 | double y_max = is_forward_ ? forward_y_max_ : backward_y_max_;
94 |
95 | publishPolygon(x_min, x_max, y_min, y_max);
96 |
97 | geometry_msgs::msg::TransformStamped transform_stamped;
98 | try {
99 | transform_stamped = tf_buffer_.lookupTransform(reference_link_, msg->header.frame_id, tf2::TimePointZero);
100 | } catch (tf2::TransformException &ex) {
101 | RCLCPP_WARN(this->get_logger(), "Could not transform %s to %s: %s", msg->header.frame_id.c_str(), reference_link_.c_str(), ex.what());
102 | return;
103 | }
104 |
105 | auto detected_points_msg = std::make_shared();
106 | *detected_points_msg = *msg;
107 | detected_points_msg->ranges.clear();
108 | detected_points_msg->intensities.clear();
109 |
110 | // Iterate over the LaserScan ranges
111 | for (size_t i = 0; i < msg->ranges.size(); ++i) {
112 | // Skip invalid ranges
113 | if (std::isnan(msg->ranges[i]) || std::isinf(msg->ranges[i])) {
114 | detected_points_msg->ranges.push_back(std::numeric_limits::quiet_NaN());
115 | detected_points_msg->intensities.push_back(0.0);
116 | continue;
117 | }
118 |
119 | // Compute angle and position in local frame
120 | double angle = msg->angle_min + i * msg->angle_increment;
121 | double x_local = msg->ranges[i] * std::cos(angle);
122 | double y_local = msg->ranges[i] * std::sin(angle);
123 |
124 | // Get yaw angle from quaternion
125 | double yaw = getYawFromQuaternion(transform_stamped.transform.rotation);
126 |
127 | // Transform to reference frame
128 | double x_ref = transform_stamped.transform.translation.x +
129 | x_local * std::cos(yaw) - y_local * std::sin(yaw);
130 | double y_ref = transform_stamped.transform.translation.y +
131 | x_local * std::sin(yaw) + y_local * std::cos(yaw);
132 |
133 | // Check if the point is within the defined range
134 | if (x_ref >= x_min && x_ref <= x_max && y_ref >= y_min && y_ref <= y_max) {
135 | in_range = true;
136 | detected_points_msg->ranges.push_back(msg->ranges[i]);
137 | detected_points_msg->intensities.push_back(msg->intensities[i]);
138 | } else {
139 | detected_points_msg->ranges.push_back(std::numeric_limits::quiet_NaN());
140 | detected_points_msg->intensities.push_back(0.0);
141 | }
142 | }
143 |
144 | // Publish the result
145 | std_msgs::msg::Bool bool_msg;
146 | bool_msg.data = in_range;
147 | bool_publisher_->publish(bool_msg);
148 |
149 | detected_points_publisher_->publish(*detected_points_msg);
150 |
151 | RCLCPP_INFO(this->get_logger(), "Scan in range: %s", in_range ? "True" : "False");
152 | }
153 |
154 | void publishPolygon(double x_min, double x_max, double y_min, double y_max) {
155 | auto polygon_msg = geometry_msgs::msg::PolygonStamped();
156 | polygon_msg.header.frame_id = reference_link_;
157 | polygon_msg.header.stamp = this->now();
158 |
159 | geometry_msgs::msg::Point32 p1, p2, p3, p4;
160 |
161 | // Define the corners of the rectangle
162 | p1.x = x_min; p1.y = y_min; p1.z = 0.0;
163 | p2.x = x_max; p2.y = y_min; p2.z = 0.0;
164 | p3.x = x_max; p3.y = y_max; p3.z = 0.0;
165 | p4.x = x_min; p4.y = y_max; p4.z = 0.0;
166 |
167 | polygon_msg.polygon.points.push_back(p1);
168 | polygon_msg.polygon.points.push_back(p2);
169 | polygon_msg.polygon.points.push_back(p3);
170 | polygon_msg.polygon.points.push_back(p4);
171 | polygon_msg.polygon.points.push_back(p1); // Close the loop
172 |
173 | polygon_publisher_->publish(polygon_msg);
174 |
175 | RCLCPP_DEBUG(this->get_logger(), "Published scan range polygon.");
176 | }
177 |
178 | rclcpp::Subscription::SharedPtr laser_scan_subscriber_;
179 | rclcpp::Subscription::SharedPtr velocity_subscriber_;
180 | rclcpp::Publisher::SharedPtr bool_publisher_;
181 | rclcpp::Publisher::SharedPtr detected_points_publisher_;
182 | rclcpp::Publisher::SharedPtr polygon_publisher_;
183 |
184 | tf2_ros::Buffer tf_buffer_;
185 | tf2_ros::TransformListener tf_listener_;
186 |
187 | bool is_forward_;
188 | double linear_x_;
189 | double forward_x_min_, forward_x_max_, forward_y_min_, forward_y_max_;
190 | double backward_x_min_, backward_x_max_, backward_y_min_, backward_y_max_;
191 | std::string reference_link_;
192 | };
193 |
194 | int main(int argc, char **argv) {
195 | rclcpp::init(argc, argv);
196 | rclcpp::spin(std::make_shared());
197 | rclcpp::shutdown();
198 | return 0;
199 | }
200 |
--------------------------------------------------------------------------------
/whill_auto_stop/src/twist_filter_node.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024 WHILL, Inc.
2 | // Released under the MIT license
3 | // https://opensource.org/licenses/mit-license.php
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | class TwistFilterNode : public rclcpp::Node {
10 | public:
11 | TwistFilterNode() : Node("twist_filter_node"), enable_publish_(false), negative_logic_(false) {
12 | // Declare and get negative_logic parameter
13 | this->declare_parameter("negative_logic", false);
14 | this->get_parameter("negative_logic", negative_logic_);
15 |
16 | // Subscriber for Twist messages
17 | twist_subscriber_ = this->create_subscription(
18 | "input_twist", 10,
19 | std::bind(&TwistFilterNode::twistCallback, this, std::placeholders::_1));
20 |
21 | // Subscriber for bool messages
22 | bool_subscriber_ = this->create_subscription(
23 | "enable", 10,
24 | std::bind(&TwistFilterNode::boolCallback, this, std::placeholders::_1));
25 |
26 | // Publisher for filtered Twist messages
27 | twist_publisher_ = this->create_publisher("output_twist", 10);
28 |
29 | RCLCPP_INFO(this->get_logger(), "Twist Filter Node has been started.");
30 | RCLCPP_INFO(this->get_logger(), "Negative logic is %s", negative_logic_ ? "enabled" : "disabled");
31 | }
32 |
33 | private:
34 | void twistCallback(const geometry_msgs::msg::Twist::SharedPtr msg) {
35 | if ((enable_publish_ && !negative_logic_) || (!enable_publish_ && negative_logic_)) {
36 | twist_publisher_->publish(*msg);
37 | RCLCPP_INFO(this->get_logger(), "Publishing Twist message.");
38 | } else {
39 | RCLCPP_INFO(this->get_logger(), "Publishing disabled, Twist message discarded.");
40 | }
41 | }
42 |
43 | void boolCallback(const std_msgs::msg::Bool::SharedPtr msg) {
44 | enable_publish_ = msg->data;
45 | RCLCPP_INFO(this->get_logger(), "Enable flag set to: %s", negative_logic_ ? (enable_publish_ ? "False" : "True") : (enable_publish_ ? "True" : "False"));
46 | }
47 |
48 | rclcpp::Subscription::SharedPtr twist_subscriber_;
49 | rclcpp::Subscription::SharedPtr bool_subscriber_;
50 | rclcpp::Publisher::SharedPtr twist_publisher_;
51 |
52 | bool enable_publish_;
53 | bool negative_logic_;
54 | };
55 |
56 | int main(int argc, char **argv) {
57 | rclcpp::init(argc, argv);
58 | rclcpp::spin(std::make_shared());
59 | rclcpp::shutdown();
60 | return 0;
61 | }
62 |
--------------------------------------------------------------------------------