diff --git a/src/elephant_robotics/agv_pro_gazebo/CMakeLists.txt b/src/elephant_robotics/agv_pro_gazebo/CMakeLists.txt index 3c89a58..50de585 100644 --- a/src/elephant_robotics/agv_pro_gazebo/CMakeLists.txt +++ b/src/elephant_robotics/agv_pro_gazebo/CMakeLists.txt @@ -14,7 +14,7 @@ if(BUILD_TESTING) ament_lint_auto_find_test_dependencies() endif() -install(DIRECTORY meshes urdf launch rviz config +install(DIRECTORY meshes urdf launch rviz config worlds DESTINATION share/${PROJECT_NAME} ) diff --git a/src/elephant_robotics/agv_pro_gazebo/config/agv_control copy.yaml b/src/elephant_robotics/agv_pro_gazebo/config/agv_control copy.yaml deleted file mode 100644 index 5cd5e9b..0000000 --- a/src/elephant_robotics/agv_pro_gazebo/config/agv_control copy.yaml +++ /dev/null @@ -1,23 +0,0 @@ -controller_manager: - ros__parameters: - update_rate: 100 - - joint_state_broadcaster: - type: joint_state_broadcaster/JointStateBroadcaster - - diff_drive_controller: - type: diff_drive_controller/DiffDriveController - left_wheel_names: ["left_front_wheel_joint", "left_rear_wheel_joint"] - right_wheel_names: ["right_front_wheel_joint", "right_rear_wheel_joint"] - - wheel_separation: 0.36 - wheel_radius: 0.05 - - base_frame_id: base_link - use_stamped_vel: false - publish_rate: 50 - - enable_odom_tf: true - odom_frame_id: odom - pose_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03] - twist_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03] \ No newline at end of file diff --git a/src/elephant_robotics/agv_pro_gazebo/config/agv_control.yaml b/src/elephant_robotics/agv_pro_gazebo/config/agv_control.yaml index 41c0814..867cc69 100644 --- a/src/elephant_robotics/agv_pro_gazebo/config/agv_control.yaml +++ b/src/elephant_robotics/agv_pro_gazebo/config/agv_control.yaml @@ -4,25 +4,36 @@ controller_manager: use_sim_time: true # 使用仿真时间 # 定义关节状态广播器 - fishbot_joint_state_broadcaster: + joint_state_broadcaster: type: joint_state_broadcaster/JointStateBroadcaster - use_sim_time: true - # 定义全向驱动控制器 - fishbot_omni_drive_controller: - type: omni_drive_controller/OmniDriveController + # 定义麦克纳姆轮驱动控制器 + mecanum_drive_controller: + type: mecanum_drive_controller/MecanumDriveController -# 四轮全向控制器配置 -fishbot_omni_drive_controller: +# 麦克纳姆四轮驱动控制器配置 +mecanum_drive_controller: ros__parameters: - front_left_wheel_joint: front_left_wheel_joint - front_right_wheel_joint: front_right_wheel_joint - rear_left_wheel_joint: rear_left_wheel_joint - rear_right_wheel_joint: rear_right_wheel_joint - wheel_separation: 0.36 # 轮距 - wheel_diameter: 0.1 # 轮子直径 - publish_rate: 50.0 # 发布频率 - odom_frame_id: odom + reference_timeout: 0.5 + + # 命令关节 (velocity command interface) + front_left_wheel_command_joint_name: left_front_wheel_joint + front_right_wheel_command_joint_name: right_front_wheel_joint + rear_left_wheel_command_joint_name: left_rear_wheel_joint + rear_right_wheel_command_joint_name: right_rear_wheel_joint + + kinematics: + base_frame_offset: + x: 0.0 + y: 0.0 + theta: 0.0 + wheels_radius: 0.05 # 轮子半径 + # lx + ly : 底盘中心到轮子在 X 与 Y 方向投影之和 + sum_of_robot_center_projection_on_X_Y_axis: 0.35 + base_frame_id: base_link + odom_frame_id: odom + enable_odom_tf: true + pose_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03] twist_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03] diff --git a/src/elephant_robotics/agv_pro_gazebo/launch/agv_pro_gazebo.launch.py b/src/elephant_robotics/agv_pro_gazebo/launch/agv_pro_gazebo.launch.py index 44e953e..e6c01f6 100644 --- a/src/elephant_robotics/agv_pro_gazebo/launch/agv_pro_gazebo.launch.py +++ b/src/elephant_robotics/agv_pro_gazebo/launch/agv_pro_gazebo.launch.py @@ -1,65 +1,145 @@ import os from launch import LaunchDescription -from launch.actions import IncludeLaunchDescription +from launch.actions import ( + IncludeLaunchDescription, + DeclareLaunchArgument, + RegisterEventHandler, + TimerAction, +) +from launch.conditions import IfCondition +from launch.event_handlers import OnProcessExit from launch.launch_description_sources import PythonLaunchDescriptionSource -from launch.substitutions import Command +from launch.substitutions import Command, LaunchConfiguration, PythonExpression from launch_ros.actions import Node from launch_ros.parameter_descriptions import ParameterValue from ament_index_python.packages import get_package_share_directory -def generate_launch_description(): - pkg_name = 'agv_pro_gazebo' - pkg_dir = get_package_share_directory(pkg_name) - xacro_file = os.path.join(pkg_dir, 'urdf', 'agv_pro.xacro') - world_file = os.path.join(pkg_dir, 'worlds', 'empty.world') - rviz_config = os.path.join(pkg_dir, 'rviz', 'agvpro_display.rviz') - robot_description_content = ParameterValue( - Command(['xacro ', xacro_file]), - value_type=str +def generate_launch_description(): + pkg_gazebo = get_package_share_directory('agv_pro_gazebo') + pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim') + + xacro_file = os.path.join(pkg_gazebo, 'urdf', 'agv_pro.xacro') + world_file = os.path.join(pkg_gazebo, 'worlds', 'empty.world') + rviz_config = os.path.join(pkg_gazebo, 'rviz', 'agvpro_display.rviz') + + use_sim_time = LaunchConfiguration('use_sim_time') + use_rviz = LaunchConfiguration('use_rviz') + headless = LaunchConfiguration('headless') + + robot_description = { + 'robot_description': ParameterValue( + Command(['xacro ', xacro_file]), value_type=str + ), + 'use_sim_time': use_sim_time, + } + + # Start gz-sim (Gazebo Harmonic) with the world. + # '-s' (server only) is added when headless:=true. + gz_args = PythonExpression([ + "'-r -v4 -s ' + ", repr(world_file), + " if '", headless, "' == 'true' ", + "else '-r -v4 ' + ", repr(world_file), + ]) + gz_sim = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py') + ), + launch_arguments={'gz_args': gz_args}.items(), + ) + + # Publish the robot description (also consumed by gz_ros2_control) + robot_state_publisher = Node( + package='robot_state_publisher', + executable='robot_state_publisher', + name='robot_state_publisher', + output='screen', + parameters=[robot_description], + ) + + # Spawn the robot into gz-sim from the robot_description topic. + # Delayed so robot_state_publisher has latched /robot_description before the + # gz_ros2_control plugin (loaded on spawn) reads it — avoids a startup race + # where the in-sim controller_manager sees no tag. + spawn_entity = Node( + package='ros_gz_sim', + executable='create', + arguments=['-topic', 'robot_description', '-name', 'agv_pro', '-z', '0.1'], + output='screen', + ) + delayed_spawn = TimerAction(period=3.0, actions=[spawn_entity]) + + # Bridge the simulation clock so ROS nodes get /clock + clock_bridge = Node( + package='ros_gz_bridge', + executable='parameter_bridge', + arguments=['/clock@rosgraph_msgs/msg/Clock[gz.msgs.Clock'], + output='screen', + ) + + # Controllers (controller_manager runs inside the gz_ros2_control plugin) + joint_state_broadcaster_spawner = Node( + package='controller_manager', + executable='spawner', + arguments=[ + 'joint_state_broadcaster', + '--controller-manager', '/controller_manager', + ], + output='screen', + ) + + mecanum_drive_controller_spawner = Node( + package='controller_manager', + executable='spawner', + arguments=[ + 'mecanum_drive_controller', + '--controller-manager', '/controller_manager', + ], + output='screen', + ) + + rviz = Node( + package='rviz2', + executable='rviz2', + name='rviz2', + arguments=['-d', rviz_config], + parameters=[{'use_sim_time': use_sim_time}], + condition=IfCondition(use_rviz), + output='screen', ) - robot_description = {'robot_description': robot_description_content} return LaunchDescription([ - # Launch Gazebo - IncludeLaunchDescription( - PythonLaunchDescriptionSource( - os.path.join(get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py') - ), - launch_arguments={'world': world_file}.items() + DeclareLaunchArgument( + 'use_sim_time', + default_value='true', + description='Use the Gazebo simulation clock', ), - - # Spawn robot into Gazebo - Node( - package='gazebo_ros', - executable='spawn_entity.py', - arguments=['-topic', 'robot_description', - '-entity', 'agv_pro'], - output='screen' + DeclareLaunchArgument( + 'use_rviz', + default_value='true', + description='Launch RViz2', ), - - # State publisher - Node( - package='robot_state_publisher', - executable='robot_state_publisher', - name='robot_state_publisher', - output='screen', - parameters=[robot_description] + DeclareLaunchArgument( + 'headless', + default_value='false', + description='Run gz-sim without the GUI (server only)', ), - - Node( - package='joint_state_publisher', - executable='joint_state_publisher', - name='joint_state_publisher', - output='screen', + gz_sim, + robot_state_publisher, + clock_bridge, + delayed_spawn, + # Load controllers only after the robot has been spawned + RegisterEventHandler( + OnProcessExit( + target_action=spawn_entity, + on_exit=[joint_state_broadcaster_spawner], + ) ), - - # Optional: RViz - Node( - package='rviz2', - executable='rviz2', - name='rviz2', - output='screen', - arguments=['-d', rviz_config], + RegisterEventHandler( + OnProcessExit( + target_action=joint_state_broadcaster_spawner, + on_exit=[mecanum_drive_controller_spawner], + ) ), + rviz, ]) diff --git a/src/elephant_robotics/agv_pro_gazebo/launch/agv_pro_gazebo.launchcopy.py b/src/elephant_robotics/agv_pro_gazebo/launch/agv_pro_gazebo.launchcopy.py deleted file mode 100644 index 8d85560..0000000 --- a/src/elephant_robotics/agv_pro_gazebo/launch/agv_pro_gazebo.launchcopy.py +++ /dev/null @@ -1,71 +0,0 @@ -import os -from launch import LaunchDescription -from launch.actions import IncludeLaunchDescription, ExecuteProcess -from launch.launch_description_sources import PythonLaunchDescriptionSource -from launch.substitutions import Command, LaunchConfiguration, PathJoinSubstitution -from launch_ros.actions import Node -from ament_index_python.packages import get_package_share_directory - -def generate_launch_description(): - pkg_name = 'agv_pro_description' - - # Paths - pkg_dir = get_package_share_directory(pkg_name) - xacro_file = os.path.join(pkg_dir, 'urdf', 'agv_pro.xacro') - world_file = os.path.join(pkg_dir, 'worlds', 'empty.world') # 创建一个空 world 即可 - rviz_config = os.path.join(pkg_dir, 'rviz', 'agvpro_display.rviz') - - robot_description_content = Command(['xacro ', xacro_file]) - robot_description = {'robot_description': robot_description_content} - - return LaunchDescription([ - - # Start Gazebo with empty world - IncludeLaunchDescription( - PythonLaunchDescriptionSource( - [os.path.join(get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')] - ), - launch_arguments={'world': world_file}.items() - ), - - # Spawn robot into Gazebo - Node( - package='gazebo_ros', - executable='spawn_entity.py', - arguments=['-topic', 'robot_description', - '-entity', 'agv_pro'], - output='screen' - ), - - # Robot state publisher - Node( - package='robot_state_publisher', - executable='robot_state_publisher', - name='robot_state_publisher', - output='screen', - parameters=[robot_description] - ), - - # Optionally publish joint states if not using controllers - Node( - package='joint_state_publisher', - executable='joint_state_publisher', - name='joint_state_publisher', - output='screen', - ), - Node( - package='controller_manager', - executable='spawner', - arguments=['joint_state_broadcaster'], - output='screen', - ), - - # RViz (optional, visualize TF & model) - Node( - package='rviz2', - executable='rviz2', - name='rviz2', - output='screen', - arguments=['-d', rviz_config], - ), - ]) \ No newline at end of file diff --git a/src/elephant_robotics/agv_pro_gazebo/launch/teleop_launch.py b/src/elephant_robotics/agv_pro_gazebo/launch/teleop_launch.py index e18c7c5..7df0262 100644 --- a/src/elephant_robotics/agv_pro_gazebo/launch/teleop_launch.py +++ b/src/elephant_robotics/agv_pro_gazebo/launch/teleop_launch.py @@ -2,6 +2,7 @@ import os from launch import LaunchDescription from launch_ros.actions import Node + def generate_launch_description(): return LaunchDescription([ Node( @@ -10,8 +11,14 @@ def generate_launch_description(): name='teleop_keyboard', output='screen', prefix='xterm -e', # 或 'gnome-terminal --' 替换为你的终端命令 + # mecanum_drive_controller expects a stamped reference; teleop must + # publish geometry_msgs/TwistStamped with a fresh timestamp. + parameters=[{ + 'stamped': True, + 'frame_id': 'base_link', + }], remappings=[ - ('/cmd_vel', '/diff_drive_controller/cmd_vel_unstamped') + ('/cmd_vel', '/mecanum_drive_controller/reference'), ] ) ]) diff --git a/src/elephant_robotics/agv_pro_gazebo/package.xml b/src/elephant_robotics/agv_pro_gazebo/package.xml index d284abc..70c0819 100644 --- a/src/elephant_robotics/agv_pro_gazebo/package.xml +++ b/src/elephant_robotics/agv_pro_gazebo/package.xml @@ -12,8 +12,12 @@ ament_cmake xacro - - gazebo_ros_pkgs + + + ros_gz_sim + ros_gz_bridge + gz_ros2_control + robot_state_publisher joint_state_publisher geometry_msgs @@ -24,9 +28,8 @@ ros2_control controller_manager joint_state_broadcaster - diff_drive_controller + mecanum_drive_controller teleop_twist_keyboard - ament_cmake ament_lint_auto ament_lint_common diff --git a/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro copy.xacro b/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro copy.xacro deleted file mode 100644 index 399d262..0000000 --- a/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro copy.xacro +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Gazebo/White - 1.0 - 1.0 - 100000.0 - 1.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gazebo_ros2_control/GazeboSystem - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro.xacro b/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro.xacro index 4f03099..e72d45e 100644 --- a/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro.xacro +++ b/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro.xacro @@ -85,8 +85,6 @@ - - diff --git a/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro1.xacro b/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro1.xacro deleted file mode 100644 index eac1eed..0000000 --- a/src/elephant_robotics/agv_pro_gazebo/urdf/agv_pro1.xacro +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - transmission_interface/SimpleTransmission - - 1 - - - hardware_interface/VelocityJointInterface - - - - - 0.8 - 0.8 - 100000.0 - 1.0 - Gazebo/Grey - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/elephant_robotics/agv_pro_gazebo/urdf/parts/wheel_macro.xacro b/src/elephant_robotics/agv_pro_gazebo/urdf/parts/wheel_macro.xacro index 2343129..a5559dd 100644 --- a/src/elephant_robotics/agv_pro_gazebo/urdf/parts/wheel_macro.xacro +++ b/src/elephant_robotics/agv_pro_gazebo/urdf/parts/wheel_macro.xacro @@ -51,7 +51,13 @@ 0.8 100000.0 1.0 - Gazebo/Black + + + 0.1 0.1 0.1 1 + 0.1 0.1 0.1 1 + 0.1 0.1 0.1 1 + + diff --git a/src/elephant_robotics/agv_pro_gazebo/urdf/ros2_controller.xacro b/src/elephant_robotics/agv_pro_gazebo/urdf/ros2_controller.xacro index eb33690..553763b 100644 --- a/src/elephant_robotics/agv_pro_gazebo/urdf/ros2_controller.xacro +++ b/src/elephant_robotics/agv_pro_gazebo/urdf/ros2_controller.xacro @@ -1,55 +1,42 @@ - + + - gazebo_ros2_control/GazeboSystem + gz_ros2_control/GazeboSimSystem - - - - - - - - - + + + + + - - - - - - - + + + + - - - - - - - + + + + - - - - - - - + + + + + + - + $(find agv_pro_gazebo)/config/agv_control.yaml - - /omni_drive_controller/cmd_vel:=/cmd_vel - /omni_drive_controller/odom:=/odom - diff --git a/src/elephant_robotics/agv_pro_gazebo/worlds/empty.world b/src/elephant_robotics/agv_pro_gazebo/worlds/empty.world index a36bb5e..51b5afe 100644 --- a/src/elephant_robotics/agv_pro_gazebo/worlds/empty.world +++ b/src/elephant_robotics/agv_pro_gazebo/worlds/empty.world @@ -1,11 +1,69 @@ - + - - model://ground_plane - - - model://sun - + + + + + + + + + + ogre2 + + + + 0.001 + 1.0 + + + + + true + 0 0 10 0 0 0 + 0.8 0.8 0.8 1 + 0.2 0.2 0.2 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + + + + true + + + + + 0 0 1 + 100 100 + + + + + + + 0 0 1 + 100 100 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + \ No newline at end of file