Skip to content

Commit edb011a

Browse files
[Example 11] Carlike Robot using Bicycle Steering Controller (ros-controls#316)
Co-authored-by: Christoph Froehlich <[email protected]>
1 parent c810999 commit edb011a

File tree

25 files changed

+1879
-2
lines changed

25 files changed

+1879
-2
lines changed

.github/workflows/ci-ros-lint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ jobs:
3030
ros2_control_demo_example_8
3131
ros2_control_demo_example_9
3232
ros2_control_demo_example_10
33+
ros2_control_demo_example_11
3334
ros2_control_demo_example_12
3435
ros2_control_demo_example_14
3536

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ The following examples are part of this demo repository:
6060

6161
*RRBot* with GPIO interfaces.
6262

63-
* Example 11: "Car-like robot using steering controller library (tba.)"
63+
* Example 11: ["Car-like robot using steering controller library"](example_11)
6464

6565
* Example 12: ["Controller chaining"](example_12)
6666

doc/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ Example 9: "Gazebo Classic"
7070
Example 10: "GPIO interfaces"
7171
Industrial robot with GPIO interfaces
7272

73-
Example 11: "Car-like robot using steering controller library (tba.)"
73+
Example 11: "CarlikeBot"
74+
*CarlikeBot* with a bicycle steering controller
7475

7576
Example 12: "Controller chaining"
7677
The example shows a simple chainable controller and its integration to form a controller chain to control the joints of *RRBot*.
@@ -270,5 +271,6 @@ Examples
270271
Example 8: Using transmissions <../example_8/doc/userdoc.rst>
271272
Example 9: Gazebo classic <../example_9/doc/userdoc.rst>
272273
Example 10: Industrial robot with GPIO interfaces <../example_10/doc/userdoc.rst>
274+
Example 11: CarlikeBot <../example_11/doc/userdoc.rst>
273275
Example 12: Controller chaining <../example_12/doc/userdoc.rst>
274276
Example 14: Modular robots with actuators not providing states <../example_14/doc/userdoc.rst>

example_11/CMakeLists.txt

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(ros2_control_demo_example_11 LANGUAGES CXX)
3+
4+
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
5+
add_compile_options(-Wall -Wextra)
6+
endif()
7+
8+
# find dependencies
9+
set(THIS_PACKAGE_INCLUDE_DEPENDS
10+
hardware_interface
11+
pluginlib
12+
rclcpp
13+
rclcpp_lifecycle
14+
)
15+
16+
# find dependencies
17+
find_package(ament_cmake REQUIRED)
18+
foreach(Dependency IN ITEMS ${THIS_PACKAGE_INCLUDE_DEPENDS})
19+
find_package(${Dependency} REQUIRED)
20+
endforeach()
21+
22+
23+
## COMPILE
24+
add_library(
25+
ros2_control_demo_example_11
26+
SHARED
27+
hardware/carlikebot_system.cpp
28+
)
29+
target_compile_features(ros2_control_demo_example_11 PUBLIC cxx_std_17)
30+
target_include_directories(ros2_control_demo_example_11 PUBLIC
31+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/hardware/include>
32+
$<INSTALL_INTERFACE:include/ros2_control_demo_example_11>
33+
)
34+
ament_target_dependencies(
35+
ros2_control_demo_example_11 PUBLIC
36+
${THIS_PACKAGE_INCLUDE_DEPENDS}
37+
)
38+
39+
# Causes the visibility macros to use dllexport rather than dllimport,
40+
# which is appropriate when building the dll but not consuming it.
41+
target_compile_definitions(${PROJECT_NAME} PRIVATE "ROS2_CONTROL_DEMO_EXAMPLE_11_BUILDING_DLL")
42+
43+
# Export hardware plugins
44+
pluginlib_export_plugin_description_file(hardware_interface ros2_control_demo_example_11.xml)
45+
46+
# INSTALL
47+
install(
48+
DIRECTORY hardware/include/
49+
DESTINATION include/ros2_control_demo_example_11
50+
)
51+
install(
52+
DIRECTORY description/launch description/ros2_control description/urdf
53+
DESTINATION share/ros2_control_demo_example_11
54+
)
55+
install(
56+
DIRECTORY bringup/launch bringup/config
57+
DESTINATION share/ros2_control_demo_example_11
58+
)
59+
install(TARGETS ros2_control_demo_example_11
60+
EXPORT export_ros2_control_demo_example_11
61+
ARCHIVE DESTINATION lib
62+
LIBRARY DESTINATION lib
63+
RUNTIME DESTINATION bin
64+
)
65+
66+
if(BUILD_TESTING)
67+
find_package(ament_cmake_pytest REQUIRED)
68+
69+
ament_add_pytest_test(example_11_urdf_xacro test/test_urdf_xacro.py)
70+
ament_add_pytest_test(view_example_11_launch test/test_view_robot_launch.py)
71+
endif()
72+
73+
## EXPORTS
74+
ament_export_targets(export_ros2_control_demo_example_11 HAS_LIBRARY_TARGET)
75+
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})
76+
ament_package()

example_11/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# ros2_control_demo_example_11
2+
3+
*CarlikeBot*, or ''Carlike Mobile Robot'', is a simple mobile base with bicycle drive.
4+
The robot has two wheels in the front that steer the robot and two wheels in the back that power the robot forward and backwards. However, since each pair of wheels (steering and traction) are controlled by one interface, a bicycle steering model is used.
5+
6+
Find the documentation in [doc/userdoc.rst](doc/userdoc.rst) or on [control.ros.org](https://control.ros.org/master/doc/ros2_control_demos/example_11/doc/userdoc.html).
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
controller_manager:
2+
ros__parameters:
3+
update_rate: 10 # Hz
4+
5+
joint_state_broadcaster:
6+
type: joint_state_broadcaster/JointStateBroadcaster
7+
8+
bicycle_steering_controller:
9+
type: bicycle_steering_controller/BicycleSteeringController
10+
11+
12+
bicycle_steering_controller:
13+
ros__parameters:
14+
wheelbase: 0.325
15+
front_wheel_radius: 0.05
16+
rear_wheel_radius: 0.05
17+
front_steering: true
18+
reference_timeout: 2.0
19+
rear_wheels_names: ['virtual_rear_wheel_joint']
20+
front_wheels_names: ['virtual_front_wheel_joint']
21+
open_loop: false
22+
velocity_rolling_window_size: 10
23+
base_frame_id: base_link
24+
odom_frame_id: odom
25+
enable_odom_tf: true
26+
twist_covariance_diagonal: [0.0, 7.0, 14.0, 21.0, 28.0, 35.0]
27+
pose_covariance_diagonal: [0.0, 7.0, 14.0, 21.0, 28.0, 35.0]
28+
position_feedback: false
29+
use_stamped_vel: true
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Copyright 2020 ros2_control Development Team
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 launch import LaunchDescription
16+
from launch.actions import DeclareLaunchArgument, RegisterEventHandler
17+
from launch.conditions import IfCondition, UnlessCondition
18+
from launch.event_handlers import OnProcessExit
19+
from launch.substitutions import Command, FindExecutable, PathJoinSubstitution, LaunchConfiguration
20+
21+
from launch_ros.actions import Node
22+
from launch_ros.substitutions import FindPackageShare
23+
24+
25+
def generate_launch_description():
26+
# Declare arguments
27+
declared_arguments = []
28+
declared_arguments.append(
29+
DeclareLaunchArgument(
30+
"gui",
31+
default_value="true",
32+
description="Start RViz2 automatically with this launch file.",
33+
)
34+
)
35+
declared_arguments.append(
36+
DeclareLaunchArgument(
37+
"remap_odometry_tf",
38+
default_value="false",
39+
description="Remap odometry TF from the steering controller to the TF tree.",
40+
)
41+
)
42+
43+
# Initialize Arguments
44+
gui = LaunchConfiguration("gui")
45+
remap_odometry_tf = LaunchConfiguration("remap_odometry_tf")
46+
47+
# Get URDF via xacro
48+
robot_description_content = Command(
49+
[
50+
PathJoinSubstitution([FindExecutable(name="xacro")]),
51+
" ",
52+
PathJoinSubstitution(
53+
[FindPackageShare("ros2_control_demo_example_11"), "urdf", "carlikebot.urdf.xacro"]
54+
),
55+
]
56+
)
57+
robot_description = {"robot_description": robot_description_content}
58+
59+
robot_controllers = PathJoinSubstitution(
60+
[
61+
FindPackageShare("ros2_control_demo_example_11"),
62+
"config",
63+
"carlikebot_controllers.yaml",
64+
]
65+
)
66+
rviz_config_file = PathJoinSubstitution(
67+
[
68+
FindPackageShare("ros2_control_demo_description"),
69+
"carlikebot/rviz",
70+
"carlikebot.rviz",
71+
]
72+
)
73+
74+
# the steering controller libraries by default publish odometry on a separate topic than /tf
75+
control_node_remapped = Node(
76+
package="controller_manager",
77+
executable="ros2_control_node",
78+
parameters=[robot_controllers],
79+
output="both",
80+
remappings=[
81+
("~/robot_description", "/robot_description"),
82+
("/bicycle_steering_controller/tf_odometry", "/tf"),
83+
],
84+
condition=IfCondition(remap_odometry_tf),
85+
)
86+
control_node = Node(
87+
package="controller_manager",
88+
executable="ros2_control_node",
89+
parameters=[robot_controllers],
90+
output="both",
91+
remappings=[
92+
("~/robot_description", "/robot_description"),
93+
],
94+
condition=UnlessCondition(remap_odometry_tf),
95+
)
96+
robot_state_pub_bicycle_node = Node(
97+
package="robot_state_publisher",
98+
executable="robot_state_publisher",
99+
output="both",
100+
parameters=[robot_description],
101+
remappings=[
102+
("~/robot_description", "/robot_description"),
103+
],
104+
)
105+
rviz_node = Node(
106+
package="rviz2",
107+
executable="rviz2",
108+
name="rviz2",
109+
output="log",
110+
arguments=["-d", rviz_config_file],
111+
condition=IfCondition(gui),
112+
)
113+
114+
joint_state_broadcaster_spawner = Node(
115+
package="controller_manager",
116+
executable="spawner",
117+
arguments=["joint_state_broadcaster", "--controller-manager", "/controller_manager"],
118+
)
119+
120+
robot_bicycle_controller_spawner = Node(
121+
package="controller_manager",
122+
executable="spawner",
123+
arguments=["bicycle_steering_controller", "--controller-manager", "/controller_manager"],
124+
)
125+
126+
# Delay rviz start after `joint_state_broadcaster`
127+
delay_rviz_after_joint_state_broadcaster_spawner = RegisterEventHandler(
128+
event_handler=OnProcessExit(
129+
target_action=joint_state_broadcaster_spawner,
130+
on_exit=[rviz_node],
131+
)
132+
)
133+
134+
# Delay start of robot_controller after `joint_state_broadcaster`
135+
delay_robot_controller_spawner_after_joint_state_broadcaster_spawner = RegisterEventHandler(
136+
event_handler=OnProcessExit(
137+
target_action=joint_state_broadcaster_spawner,
138+
on_exit=[robot_bicycle_controller_spawner],
139+
)
140+
)
141+
142+
nodes = [
143+
control_node,
144+
control_node_remapped,
145+
robot_state_pub_bicycle_node,
146+
joint_state_broadcaster_spawner,
147+
delay_rviz_after_joint_state_broadcaster_spawner,
148+
delay_robot_controller_spawner_after_joint_state_broadcaster_spawner,
149+
]
150+
151+
return LaunchDescription(declared_arguments + nodes)

0 commit comments

Comments
 (0)