ROS2笔记-2:第一个在Gazebo中能动的例子
第一个在Gazebo中能动的例子
- 写在前面
- X-windows 与cursor
- Simple ROS2 Robot
- Project Structure
- Features
- Dependencies
- Installation
- Usage
- Robot Description
- Movement Pattern
- Customization
- 解释
- 运行的效果
- 启动
- 控制机器人移动
- 代码
写在前面
第一个在Gazebo中能动的例子 是指对我来说。在Gazebo中显示,第二个要求是能动。
这个目标对我来说并不容易。可能是我没有装实体机的原因。
如果在MobaStrem中,当然不需要考虑X-windows的问题,但如果在cursor中,就是一个大困难。
X-windows 与cursor
在学习新技术时,我一般需要cursor.
怎么说呢,我不想看书。不是我不想看,一般来说,也没有有书可以看。
再者,人脑容量是有限的,我们需要用一种哲学模式,来描述世界,我们需要在学习一种技术之前,利用哲学窠臼,来思考,如果是我们自己来实现,应当如何做。
所以,我一般都是放弃深度思考,反复与cursor磨合,看它如何进展和不断地犯错,来思考。
但是对X-windows的支持,cursor做得不好。这样一来,我就无法搞清楚是vmware带来的问题还是cursor的问题。
虽然,用手工来执行,也是一个方法,但那并不是个好主意。
所以,想来想去想了一晚上,才想到直接装到ubuntu上。真的是,这么个简单的答案,我一直没想到。
在ubuntu上,我又来到基本的目标,就是机器人能动。
# 部分笔记
因为ubuntu 的桌面,这几年没怎么用。
所以,也不想装输入法,就英文吧。蹩脚,乱,是难免的。
Simple ROS2 Robot
A simple differential drive robot implementation in ROS2 Humble with Gazebo simulation. This project serves as a learning platform for ROS2 and Gazebo integration.
Project Structure
simple_robot_ws/
├── src/
│ └── simple_robot/
│ ├── simple_robot/
│ │ ├── launch/
│ │ │ └── robot_gazebo.launch.py
│ │ ├── robot.urdf.xacro
│ │ └── square_movement.py
│ ├── package.xml
│ └── setup.py
Features
- Simple differential drive robot with two wheels
- Gazebo simulation integration
- Square movement pattern demonstration
- ROS2 Humble compatible
Dependencies
- ROS2 Humble
- Gazebo
- Python 3.10
- Required ROS2 packages:
- gazebo_ros_pkgs
- gazebo_ros2_control
- robot_state_publisher
- xacro
Installation
- Clone this repository into your ROS2 workspace:
cd ~/ros2_ws/src
git clone <repository-url> simple_robot
- Install dependencies:
sudo apt-get update
sudo apt-get install -y ros-humble-gazebo-ros-pkgs ros-humble-gazebo-ros2-control ros-humble-robot-state-publisher ros-humble-xacro
- Build the package:
cd ~/ros2_ws
colcon build --symlink-install
Usage
- Source the workspace:
source install/setup.bash
- Launch the robot in Gazebo:
ros2 launch simple_robot robot_gazebo.launch.py
- In a new terminal, run the square movement node:
source install/setup.bash
ros2 run simple_robot square_movement
Robot Description
The robot consists of:
- A blue rectangular base (0.3m x 0.3m x 0.1m)
- Two black wheels (radius: 0.05m, width: 0.04m)
- Differential drive control system
Movement Pattern
The robot follows a square pattern:
- Moves forward for 5 seconds at 0.2 m/s
- Turns 90 degrees at 0.5 rad/s
- Repeats the pattern
Customization
You can modify:
- Robot dimensions in
robot.urdf.xacro
- Movement speed and pattern in
square_movement.py
- Launch parameters in
robot_gazebo.launch.py
后面我会把这个代码放到github.
解释
the main source code files in detail to help you understand ROS2 concepts:
- First, let’s look at the URDF file (
robot.urdf.xacro
):
Read file: /data/myrobot/simple_robot_ws/src/simple_robot/simple_robot/robot.urdf.xacro
Let me explain the key components of the URDF file:
- Properties and Parameters:
<xacro:property name="PI" value="3.1415926535897931"/>
<xacro:property name="robot_width" value="0.3"/>
- These are reusable variables that define robot dimensions
- Makes it easy to modify robot size by changing one value
- Links (Physical parts of the robot):
<link name="base_link">
<visual>...</visual>
<collision>...</collision>
<inertial>...</inertial>
</link>
visual
: Defines how the robot looks in simulationcollision
: Defines collision geometry for physicsinertial
: Defines mass and inertia properties
- Joints (Connections between links):
<joint name="base_right_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 ${-(robot_width/2 + wheel_width/2)} 0" rpy="${PI/2} 0 0"/>
<axis xyz="0 0 1"/>
</joint>
type="continuous"
: Allows unlimited rotation (for wheels)parent
andchild
: Defines which links are connectedorigin
: Position and orientation of the jointaxis
: Axis of rotation
- Gazebo Plugin (Simulation interface):
<gazebo>
<plugin name="differential_drive" filename="libgazebo_ros_diff_drive.so">
<left_joint>base_left_wheel_joint</left_joint>
<right_joint>base_right_wheel_joint</right_joint>
...
</plugin>
</gazebo>
- Connects ROS2 to Gazebo simulation
- Handles differential drive control
- Publishes odometry information
Now, let’s look at the Python node that controls the robot:
Read file: /data/myrobot/simple_robot_ws/src/simple_robot/simple_robot/simple_robot/square_movement.py
Let me explain the Python node:
- Node Initialization:
def __init__(self):
super().__init__('square_movement')
self.publisher = self.create_publisher(Twist, '/cmd_vel', 10)
self.timer = self.create_timer(0.1, self.timer_callback)
- Creates a ROS2 node named ‘square_movement’
- Creates a publisher for Twist messages on ‘/cmd_vel’ topic
- Sets up a timer that calls
timer_callback
every 0.1 seconds
- Movement Control:
def timer_callback(self):
current_time = self.get_clock().now()
elapsed_time = (current_time - self.state_start_time).nanoseconds / 1e9
msg = Twist()
if self.state == 'forward':
msg.linear.x = 0.2 # Move forward at 0.2 m/s
msg.angular.z = 0.0
if elapsed_time >= 5.0: # After 5 seconds
self.state = 'turn'
elif self.state == 'turn':
msg.linear.x = 0.0
msg.angular.z = 0.5 # Turn at 0.5 rad/s
if elapsed_time >= 3.14: # After ~90 degrees
self.state = 'forward'
- Uses a state machine to control robot movement
linear.x
: Forward/backward velocityangular.z
: Rotational velocity- Switches between forward and turning states
- Main Function:
def main(args=None):
rclpy.init(args=args)
node = SquareMovement()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
- Initializes ROS2
- Creates and runs the node
- Handles cleanup on shutdown
Finally, let’s look at the launch file:
Read file: /data/myrobot/simple_robot_ws/src/simple_robot/simple_robot/launch/robot_gazebo.launch.py
The launch file is responsible for starting all necessary components:
- URDF Processing:
xacro_file = os.path.join(pkg_dir, 'robot.urdf.xacro')
robot_description_config = xacro.process_file(xacro_file)
robot_description = {'robot_description': robot_description_config.toxml()}
- Loads and processes the URDF file
- Converts Xacro macros into XML
- Gazebo Launch:
gazebo_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')]),
)
- Starts the Gazebo simulator
- Robot State Publisher:
robot_state_publisher = Node(
package='robot_state_publisher',
executable='robot_state_publisher',
output='screen',
parameters=[robot_description]
)
- Publishes robot joint states
- Required for visualization and control
- Robot Spawning:
spawn_entity = Node(
package='gazebo_ros',
executable='spawn_entity.py',
arguments=['-entity', 'simple_robot',
'-topic', 'robot_description'],
output='screen'
)
- Spawns the robot in Gazebo
- Uses the processed URDF description
Key ROS2 Concepts Demonstrated:
- Nodes: Independent processes (square_movement.py)
- Topics: Communication channels (‘/cmd_vel’)
- Messages: Data structures (Twist)
- Launch System: Starting multiple nodes
- URDF/Xacro: Robot description
- Gazebo Integration: Simulation
- Parameters: Configuration values
- Publishers/Subscribers: Communication pattern
运行的效果
启动
root@ros:/data/myrobot/simple_robot_ws# source install/setup.bash && ros2 launch simple_robot robot_gazebo.launch.py
[INFO] [launch]: All log files can be found below /root/.ros/log/2025-04-06-12-30-45-332217-ros-4626
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [gzserver-1]: process started with pid [4634]
[INFO] [gzclient-2]: process started with pid [4636]
[INFO] [robot_state_publisher-3]: process started with pid [4638]
[INFO] [spawn_entity.py-4]: process started with pid [4640]
[robot_state_publisher-3] [WARN] [1743913845.758133319] [kdl_parser]: The root link base_link has an inertia specified in the URDF, but KDL does not support a root link with an inertia. As a workaround, you can add an extra dummy link to your URDF.
[robot_state_publisher-3] [INFO] [1743913845.758202925] [robot_state_publisher]: got segment base_link
[robot_state_publisher-3] [INFO] [1743913845.758239006] [robot_state_publisher]: got segment left_wheel
[robot_state_publisher-3] [INFO] [1743913845.758242357] [robot_state_publisher]: got segment right_wheel
[spawn_entity.py-4] [INFO] [1743913845.891193009] [spawn_entity]: Spawn Entity started
[spawn_entity.py-4] [INFO] [1743913845.891440305] [spawn_entity]: Loading entity published on topic robot_description
[spawn_entity.py-4] [INFO] [1743913845.892783074] [spawn_entity]: Waiting for entity xml on robot_description
[spawn_entity.py-4] [INFO] [1743913846.020159987] [spawn_entity]: Waiting for service /spawn_entity, timeout = 30
[spawn_entity.py-4] [INFO] [1743913846.020361422] [spawn_entity]: Waiting for service /spawn_entity
[spawn_entity.py-4] [INFO] [1743913847.038242167] [spawn_entity]: Calling service /spawn_entity
[spawn_entity.py-4] [INFO] [1743913847.248558627] [spawn_entity]: Spawn status: SpawnEntity: Successfully spawned entity [simple_robot]
[gzserver-1] [INFO] [1743913847.262162662] [differential_drive]: Wheel pair 1 separation set to [0.340000m]
[gzserver-1] [INFO] [1743913847.262435027] [differential_drive]: Wheel pair 1 diameter set to [0.100000m]
[gzserver-1] [INFO] [1743913847.263072041] [differential_drive]: Subscribed to [/cmd_vel]
[gzserver-1] [INFO] [1743913847.264434814] [differential_drive]: Advertise odometry on [/odom]
[gzserver-1] [INFO] [1743913847.266079557] [differential_drive]: Publishing odom transforms between [odom] and [base_link]
[gzserver-1] [INFO] [1743913847.266098937] [differential_drive]: Publishing wheel transforms between [base_link], [base_left_wheel_joint] and [base_right_wheel_joint]
[INFO] [spawn_entity.py-4]: process has finished cleanly [pid 4640]
[gzclient-2] context mismatch in svga_surface_destroy
[gzclient-2] context mismatch in svga_surface_destroy
^C[WARNING] [launch]: user interrupted with ctrl-c (SIGINT)
[robot_state_publisher-3] [INFO] [1743917858.696625720] [rclcpp]: signal_handler(signum=2)
[gzclient-2] context mismatch in svga_surface_destroy
[gzclient-2] context mismatch in svga_surface_destroy
[INFO] [robot_state_publisher-3]: process has finished cleanly [pid 4638]
[INFO] [gzclient-2]: process has finished cleanly [pid 4636]
[INFO] [gzserver-1]: process has finished cleanly [pid 4634]
root@ros:/data/myrobot/simple_robot_ws# source install/setup.bash && ros2 launch simple_robot robot_gazebo.launch.py
[INFO] [launch]: All log files can be found below /root/.ros/log/2025-04-06-13-37-49-581935-ros-21692
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [gzserver-1]: process started with pid [21693]
[INFO] [gzclient-2]: process started with pid [21695]
[INFO] [robot_state_publisher-3]: process started with pid [21697]
[INFO] [spawn_entity.py-4]: process started with pid [21699]
[robot_state_publisher-3] [WARN] [1743917869.961730595] [kdl_parser]: The root link base_link has an inertia specified in the URDF, but KDL does not support a root link with an inertia. As a workaround, you can add an extra dummy link to your URDF.
[robot_state_publisher-3] [INFO] [1743917869.961810285] [robot_state_publisher]: got segment base_link
[robot_state_publisher-3] [INFO] [1743917869.961840435] [robot_state_publisher]: got segment left_wheel
[robot_state_publisher-3] [INFO] [1743917869.961843738] [robot_state_publisher]: got segment right_wheel
[spawn_entity.py-4] [INFO] [1743917870.115293166] [spawn_entity]: Spawn Entity started
[spawn_entity.py-4] [INFO] [1743917870.115563623] [spawn_entity]: Loading entity published on topic robot_description
[spawn_entity.py-4] [INFO] [1743917870.127828694] [spawn_entity]: Waiting for entity xml on robot_description
[spawn_entity.py-4] [INFO] [1743917870.140340287] [spawn_entity]: Waiting for service /spawn_entity, timeout = 30
[spawn_entity.py-4] [INFO] [1743917870.140550074] [spawn_entity]: Waiting for service /spawn_entity
[spawn_entity.py-4] [INFO] [1743917871.185531000] [spawn_entity]: Calling service /spawn_entity
[spawn_entity.py-4] [INFO] [1743917871.393789340] [spawn_entity]: Spawn status: SpawnEntity: Successfully spawned entity [simple_robot]
[gzserver-1] [INFO] [1743917871.415619114] [differential_drive]: Wheel pair 1 separation set to [0.340000m]
[gzserver-1] [INFO] [1743917871.416094928] [differential_drive]: Wheel pair 1 diameter set to [0.100000m]
[gzserver-1] [INFO] [1743917871.416994931] [differential_drive]: Subscribed to [/cmd_vel]
[gzserver-1] [INFO] [1743917871.418813122] [differential_drive]: Advertise odometry on [/odom]
[gzserver-1] [INFO] [1743917871.421652281] [differential_drive]: Publishing odom transforms between [odom] and [base_link]
[gzserver-1] [INFO] [1743917871.421705231] [differential_drive]: Publishing wheel transforms between [base_link], [base_left_wheel_joint] and [base_right_wheel_joint]
[INFO] [spawn_entity.py-4]: process has finished cleanly [pid 21699]
[gzclient-2] context mismatch in svga_surface_destroy
[gzclient-2] context mismatch in svga_surface_destroy
控制机器人移动
root@ros:/data/myrobot/simple_robot_ws# cd /data/myrobot/simple_robot_ws && source install/setup.bash && ros2 run simple_robot square_movement
代码
https://download.csdn.net/download/haoyujie/90571841
不需要积分。
突然懒病就犯了。不想传到github去了。