ros进阶——ros中快捷的函数调用


这里整理了几个非常好用的ros工具,可以用来快速实现强化学习的环境,包括对urdf,对gazebo中的控制器,对gazebo本身,对launch文件,对节点,对模型等等

ros_gazebo.py

可以设置gazebo中的各种目标参数,尤其是可以将gazebo的仿真速度加快

#!/usr/bin/env python

import rospy
import rospkg
import os
import subprocess
import time
import xacro
from rospy.service import ServiceException

from gazebo_msgs.srv import GetPhysicsProperties, SetPhysicsProperties, SetPhysicsPropertiesRequest
from gazebo_msgs.srv import DeleteModel, SpawnModel
from gazebo_msgs.srv import DeleteModelRequest, SpawnModelRequest
from gazebo_msgs.srv import GetModelState, SetModelState
from gazebo_msgs.srv import GetModelStateRequest, SetModelStateRequest
from gazebo_msgs.msg import ODEPhysics, ModelState
from geometry_msgs.msg import Vector3
from std_srvs.srv import Empty
from std_msgs.msg import Header
from geometry_msgs.msg import Pose, Point, Quaternion, Twist


def launch_Gazebo(paused=False, use_sim_time=True, gui=True, recording=False, debug=False, verbose=False, output='screen',
                  custom_world_path=None, custom_world_pkg=None, custom_world_name=None, respawn_gazebo=False,
                  pub_clock_frequency=100, server_required=False, gui_required=False, launch_new_term=True) -> bool:
    """
    使用 ROS 网络启动 Gazebo。

    :param paused: 如果为 True,则以暂停状态启动 gzserver。
    :type paused: bool

    :param use_sim_time: 如果为 True,则使用仿真时间。
    :type use_sim_time: bool

    :param gui: 如果为 True,则启动 Gazebo 的 GUI(gzclient)。
    :type gui: bool

    :param recording: 如果为 True,则记录 Gazebo 的数据。
    :type recording: bool

    :param debug: 如果为 True,则使用调试配置。
    :type debug: bool

    :param verbose: 如果为 True,则打印调试信息。
    :type verbose: bool

    :param output: 选择 Gazebo 的输出方式(screen 或 log)。
    :type output: str [screen, log]

    :param custom_world_path: 如果不为 None,则使用此世界文件路径。
    :type custom_world_path: str

    :param custom_world_pkg: 如果 custom_world_path 为 None,则从此包中使用世界文件,具体文件名由 custom_world_name 指定。
    :type custom_world_pkg: str

    :param custom_world_name: 如果 custom_world_path 为 None,则使用 custom_world_pkg 中的此世界文件。
    :type custom_world_name: str

    :param respawn_gazebo: 如果为 True,则在 Gazebo 被杀死时重新启动, 默认值为 False。
    :type respawn_gazebo: bool

    :param pub_clock_frequency: 时钟发布器的频率(以 Hz 为单位)。
    :type pub_clock_frequency: int

    :param server_required: 如果为 True,则启动文件将等待 gzserver 运行。
    :type server_required: bool

    :param gui_required: 如果为 True,则启动文件将等待 gzclient 运行。
    :type gui_required: bool

    :param launch_new_term: 在新终端(Xterm)中启动 Gazebo 节点。
    :type launch_new_term: bool

    :return: 如果启动成功,则返回 True,否则返回 False。
    :rtype: bool
    """

    rospack = rospkg.RosPack()
    try:
        rospack.get_path('gazebo_ros')
    except rospkg.common.ResourceNotFound:
        rospy.logerr("未找到 gazebo_ros 包")
        return False

    term_command = "roslaunch gazebo_ros empty_world.launch "

    # 初始化世界时暂停
    term_command += " paused:=" + str(paused)

    # 使用仿真时间
    term_command += " use_sim_time:=" + str(use_sim_time)

    # 启用/禁用 GUI
    term_command += " gui:=" + str(gui)

    # 启用/禁用录制
    term_command += " recording:=" + str(recording)

    # 启用/禁用调试
    term_command += " debug:=" + str(debug)

    # 启用/禁用详细信息
    term_command += " verbose:=" + str(verbose)

    # 选择输出类型(screen 或 log)
    term_command += " output:=" + str(output)

    # 选择世界文件
    if custom_world_path is not None:
        term_command += " world_name:=" + str(custom_world_path)
    elif custom_world_pkg is not None and custom_world_name is not None:
        try:
            world_pkg_path = rospack.get_path(custom_world_pkg)
        except rospkg.common.ResourceNotFound:
            rospy.logwarn("未找到包含世界文件的包")

        world_file_path = world_pkg_path + "/worlds/" + custom_world_name
        term_command += " world_name:=" + str(world_file_path)

    # 启用 Gazebo 的重新启动
    term_command += " respawn_gazebo:=" + str(respawn_gazebo)

    # 设置 gazebo_ros 发布频率
    term_command += " pub_clock_frequency:=" + str(pub_clock_frequency)

    # 设置是否需要 Gazebo 服务器
    term_command += " server_required:=" + str(server_required)

    # 设置是否需要 GUI
    term_command += " gui_required:=" + str(gui_required)

    print(term_command)

    # 执行命令
    if launch_new_term:
        term_command = "xterm -e ' " + term_command + "'"

    subprocess.Popen(term_command, shell=True)
    time.sleep(5.0)

    rospy.wait_for_service('/gazebo/pause_physics')

    return True


def close_Gazebo() -> bool:
    """
    Function to close gazebo if its running.

    :return: True if gazebo was closed, False otherwise.
    :rtype: bool
    """

    term_command = "rosnode kill /gazebo /gazebo_gui"
    subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()
    time.sleep(0.5)

    term_command = "killall -9 gzserver gzclient"
    subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()

    return True

def gazebo_set_max_update_rate(max_update_rate) -> bool:
    """
    Function to set the max update rate for gazebo in real time factor: 1 is real time, 10 is 10 times real time.

    :param max_update_rate: the max update rate for gazebo in real time factor.
    :type max_update_rate: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/get_physics_properties")
    rospy.wait_for_service("/gazebo/set_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    orig_physics = client_get_physics()

    new_physics = SetPhysicsPropertiesRequest(  time_step=orig_physics.time_step,
                                                max_update_rate=((1.0/orig_physics.time_step)*max_update_rate),
                                                gravity=orig_physics.gravity,
                                                ode_config=orig_physics.ode_config)
    
    client_set_physics = rospy.ServiceProxy("/gazebo/set_physics_properties", SetPhysicsProperties)
    result_gaz_upd = client_set_physics(new_physics)
    rospy.logdebug("Gazebo physics was succesful: " + str(result_gaz_upd))

    return result_gaz_upd.success

def gazebo_get_max_update_rate() -> float:
    """
    Function to get the current max update rate.

    :return: the max update rate.
    :rtype: float
    """

    rospy.wait_for_service("/gazebo/get_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    physics = client_get_physics()

    return physics.max_update_rate

def gazebo_set_time_step(new_time_step) -> bool:
    """
    Function to set the time step for gazebo.

    :param new_time_step: the new time step.
    :type new_time_step: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """
    
    rospy.wait_for_service("/gazebo/get_physics_properties")
    rospy.wait_for_service("/gazebo/set_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    orig_physics = client_get_physics()

    max_update_rate = orig_physics.max_update_rate / (1.0/orig_physics.time_step)

    new_physics = SetPhysicsPropertiesRequest(  time_step=new_time_step,
                                                max_update_rate=((1.0/new_time_step)*max_update_rate),
                                                gravity=orig_physics.gravity,
                                                ode_config=orig_physics.ode_config)
    
    client_set_physics = rospy.ServiceProxy("/gazebo/set_physics_properties", SetPhysicsProperties)
    result_gaz_upd = client_set_physics(new_physics)
    rospy.logdebug("Gazebo physics was succesful: " + str(result_gaz_upd))

    return result_gaz_upd.success

def gazebo_get_time_step() -> float:
    """
    Function to get the current time step for gazebo.

    :return: the time step.
    :rtype: float
    """

    rospy.wait_for_service("/gazebo/get_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    physics = client_get_physics()

    return physics.time_step

def gazebo_set_gravity(x, y, z) -> bool:
    """
    Function to set the gravity for gazebo.

    :param x: the x component of the gravity vector.
    :type x: float

    :param y: the y component of the gravity vector.
    :type y: float

    :param z: the z component of the gravity vector.
    :type z: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/get_physics_properties")
    rospy.wait_for_service("/gazebo/set_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    orig_physics = client_get_physics()

    gravity = Vector3()
    gravity.x = x
    gravity.y = y
    gravity.z = z

    new_physics = SetPhysicsPropertiesRequest(  time_step=orig_physics.time_step,
                                                max_update_rate=orig_physics.max_update_rate,
                                                gravity=gravity,
                                                ode_config=orig_physics.ode_config)
    
    client_set_physics = rospy.ServiceProxy("/gazebo/set_physics_properties", SetPhysicsProperties)
    result_gaz_upd = client_set_physics(new_physics)
    rospy.logdebug("Gazebo physics was succesful: " + str(result_gaz_upd))

    return result_gaz_upd.success

def gazebo_get_gravity() -> Vector3:
    """
    Function to get the current gravity vector for gazebo.

    :return: the gravity vector.
    :rtype: Vector3
    """

    rospy.wait_for_service("/gazebo/get_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    physics = client_get_physics()

    return physics.gravity

def gazebo_set_ODE_physics( auto_disable_bodies, sor_pgs_precon_iters, sor_pgs_iters, sor_pgs_w, sor_pgs_rms_error_tol,
                            contact_surface_layer, contact_max_correcting_vel, cfm, erp, max_contacts) -> bool:
    """
    Function to set the ODE physics for gazebo.

    :return: True if the command was sent and False otherwise.
    """

    rospy.wait_for_service("/gazebo/get_physics_properties")
    rospy.wait_for_service("/gazebo/set_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    orig_physics = client_get_physics()

    ode_config = ODEPhysics()
    ode_config.auto_disable_bodies = auto_disable_bodies
    ode_config.sor_pgs_precon_iters = sor_pgs_precon_iters
    ode_config.sor_pgs_iters = sor_pgs_iters
    ode_config.sor_pgs_w = sor_pgs_w
    ode_config.sor_pgs_rms_error_tol = sor_pgs_rms_error_tol
    ode_config.contact_surface_layer = contact_surface_layer
    ode_config.contact_max_correcting_vel = contact_max_correcting_vel
    ode_config.cfm = cfm
    ode_config.erp = erp
    ode_config.max_contacts = max_contacts

    new_physics = SetPhysicsPropertiesRequest(  time_step=orig_physics.time_step,
                                                max_update_rate=orig_physics.max_update_rate,
                                                gravity=orig_physics.gravity,
                                                ode_config=orig_physics.ode_config)
    
    client_set_physics = rospy.ServiceProxy("/gazebo/set_physics_properties", SetPhysicsProperties)
    result_gaz_upd = client_set_physics(new_physics)
    rospy.logdebug("Gazebo physics was succesful: " + str(result_gaz_upd))

    return result_gaz_upd.success

def gazebo_get_ODE_physics() -> ODEPhysics:
    """
    Function to get the current ODE physics for gazebo.

    :return: the ODE physics.
    :rtype: ODEPhysics
    """

    rospy.wait_for_service("/gazebo/get_physics_properties")
    client_get_physics = rospy.ServiceProxy("/gazebo/get_physics_properties", GetPhysicsProperties)
    physics = client_get_physics()

    return physics.ode_config

def gazebo_set_default_properties() -> bool:
    """
    Function to set the default gazebo properties.

    :return: True if the command was sent and False otherwise.
    """

    counter_sucess = 0

    if gazebo_set_time_step(0.001):
        counter_sucess += 1
    if gazebo_set_max_update_rate(1.0):
        counter_sucess += 1
    if gazebo_set_gravity(0.0, 0.0, -9.81):
        counter_sucess += 1
    if gazebo_set_ODE_physics(False, 0, 50, 1.3, 0.0, 0.001, 0.0, 0.0, 0.2, 20):
        counter_sucess += 1

    if counter_sucess == 4:
        return True
    else:
        return False

def gazebo_reset_sim(retries=5) -> bool:
    """
    Function to reset the simulation, which reset models to original poses AND reset the simulation time.

    :param retries: The number of times to retry the service call.
    :type retries: int

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/reset_simulation")
    client_srv = rospy.ServiceProxy("/gazebo/reset_simulation", Empty)

    for retry in range(retries):
        try:
            client_srv()
            return True
        except rospy.ServiceException as e:
            print ("/gazebo/reset_simulation service call failed")
        
    return False

def gazebo_reset_world(retries=5) -> bool:
    """
    Function to reset the world, which reset models to original poses WITHOUT resetting the simulation time.

    :param retries: The number of times to retry the service call.
    :type retries: int

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/reset_world")
    client_srv = rospy.ServiceProxy("/gazebo/reset_world", Empty)

    for retry in range(retries):
        try:
            client_srv()
            return True
        except rospy.ServiceException as e:
            print ("/gazebo/reset_world service call failed")
        
    return False

def gazebo_pause_physics(retries=5) -> bool:
    """
    Function to pause the physics in the simulation.

    :param retries: The number of times to retry the service call.
    :type retries: int

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/pause_physics")
    client_srv = rospy.ServiceProxy("/gazebo/pause_physics", Empty)

    for retry in range(retries):
        try:
            client_srv()
            return True
        except rospy.ServiceException as e:
            print ("/gazebo/pause_physics service call failed")
        
    return False

def gazebo_unpause_physics(retries=5) -> bool:
    """
    Function to unpause the physics in the simulation.

    :param retries: The number of times to retry the service call.
    :type retries: int

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/unpause_physics")
    client_srv = rospy.ServiceProxy("/gazebo/unpause_physics", Empty)
    
    for retry in range(retries):
        try:
            client_srv()
            return True
        except rospy.ServiceException as e:
            print ("/gazebo/pause_physics service call failed")
        
    return False

def gazebo_step_physics(steps=1) -> bool:
    """
    Function to step the physics in the simulation.

    :param steps: The number of times to step the simulation.
    :type steps: int

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """
    rospy.wait_for_service("/gazebo/pause_physics")

    term_command = "gz world -m " + str(steps)
    subprocess.Popen(term_command, shell=True).wait()
    return True

def gazebo_delete_model(model_name) -> bool:
    """
    Function to delete a model from the simulation.

    :param model_name: The name of the model to delete.
    :type model_name: str

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/delete_model")
    client_srv = rospy.ServiceProxy("/gazebo/delete_model", DeleteModel)

    srv_model = DeleteModelRequest(model_name=model_name)

    result = client_srv(srv_model)

    return result.success

def gazebo_spawn_urdf_path( model_path, model_name="robot1", robot_namespace="/", reference_frame="world",
                            pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                            ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a URDF file.

    :param model_path: The path to the URDF file.
    :type model_path: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: [True if the command was sent and False otherwise, Status message].
    :rtype: [bool, str]
    """
    
    rospy.wait_for_service("/gazebo/spawn_urdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_urdf_model", SpawnModel)

    if os.path.exists(model_path) is False:
        print("Error: model path does not exist")
        return False

    model = xacro.process_file(model_path)
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success, result.status_message
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_spawn_urdf_pkg(  pkg_name, file_name, file_folder="/urdf", model_name="robot1", robot_namespace="/", reference_frame="world",
                            pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                            ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a URDF file.

    :param pkg_name: Name of the package to import the URDF file from.
    :type pkg_name: str

    :param file_name: Name of the URDF file to import.
    :type file_name: str

    :param file_folder: Folder where the URDF file is located. Defaults to "/urdf".
    :type file_folder: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: [True if the command was sent and False otherwise, Status message].
    :rtype: [bool, str]
    """
    
    rospy.wait_for_service("/gazebo/spawn_urdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_urdf_model", SpawnModel)

    rospack = rospkg.RosPack()
    try:
        pkg_path = rospack.get_path(pkg_name)
        rospy.logdebug("Package FOUND...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("Package NOT FOUND")
        return False

    file_path = pkg_path + file_folder + "/" + file_name

    if os.path.exists(file_path) is False:
        print("Error: model path does not exist")
        return False

    model = xacro.process_file(file_path)
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success, result.status_message
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_spawn_urdf_string(   model_string, model_name="robot1", robot_namespace="/", reference_frame="world",
                                pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                                ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a URDF file.

    :param model_string: URDF string to import.
    :type model_string: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used.
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: [True if the command was sent and False otherwise, Status message].
    :rtype: [bool, str]
    """
    
    rospy.wait_for_service("/gazebo/spawn_urdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_urdf_model", SpawnModel)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success, result.status_message
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_spawn_urdf_param(    param_name, model_name="robot1", robot_namespace="/", reference_frame="world",
                                pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                                ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a URDF in the param server.

    :param param_name: Name of model to spawn
    :type param_name: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used.
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: [True if the command was sent and False otherwise, Status message].
    :rtype: [bool, str]
    """

    rospy.wait_for_service("/gazebo/spawn_urdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_urdf_model", SpawnModel)

    final_param_name = robot_namespace + "/" + param_name

    if rospy.has_param(final_param_name) is False:
        print("Error: Parameter " + final_param_name +" does not exist")
        return False

    model_string = rospy.get_param(final_param_name)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success , result.status_message
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_spawn_sdf_path( model_path, model_name="robot1", robot_namespace="/", reference_frame="world",
                            pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                            ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a SDF file.

    :param model_path: The path to the SDF file.
    :type model_path: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """
    
    rospy.wait_for_service("/gazebo/spawn_sdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_sdf_model", SpawnModel)

    if os.path.exists(model_path) is False:
        print("Error: model path does not exist")
        return False

    model = xacro.process_file(model_path)
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_spawn_sdf_pkg(  pkg_name, file_name, file_folder="/sdf", model_name="robot1", robot_namespace="/", reference_frame="world",
                            pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                            ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a SDF file.

    :param pkg_name: Name of the package to import the SDF file from.
    :type pkg_name: str

    :param file_name: Name of the SDF file to import.
    :type file_name: str

    :param file_folder: Folder where the SDF file is located. Default is "/sdf".
    :type file_folder: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """
    
    rospy.wait_for_service("/gazebo/spawn_sdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_sdf_model", SpawnModel)

    rospack = rospkg.RosPack()
    try:
        pkg_path = rospack.get_path(pkg_name)
        rospy.logdebug("Package FOUND...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("Package NOT FOUND")
        return False

    file_path = pkg_path + file_folder + "/" + file_name

    if os.path.exists(file_path) is False:
        print("Error: model path does not exist")
        return False

    model = xacro.process_file(file_path)
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_spawn_sdf_string(   model_string, model_name="robot1", robot_namespace="/", reference_frame="world",
                                pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                                ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a SDF file.

    :param model_string: SDF string to import.
    :type model_string: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used.
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """
    
    rospy.wait_for_service("/gazebo/spawn_sdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_sdf_model", SpawnModel)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_spawn_sdf_param(    param_name, model_name="robot1", robot_namespace="/", reference_frame="world",
                                pos_x=0.0, pos_y=0.0, pos_z=0.0, 
                                ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=1.0) -> bool:
    """
    Function to spawn a model from a SDF in the param server.

    :param param_name: Name of model to spawn
    :type param_name: str

    :param model_name: Name of model to spawn
    :type model_name: str

    :param robot_namespace: change ROS namespace of gazebo-plugins.
    :type robot_namespace: str

    :param reference_frame: Name of the model/body where initial pose is defined. If left empty or specified as "world", gazebo world frame is used.
    :type reference_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/spawn_sdf_model")
    client_srv = rospy.ServiceProxy("/gazebo/spawn_sdf_model", SpawnModel)

    final_param_name = robot_namespace + "/" + param_name

    if rospy.has_param(final_param_name) is False:
        print("Error: Parameter " + final_param_name +" does not exist")
        return False

    model_string = rospy.get_param(final_param_name)

    srv_model = SpawnModelRequest(  model_name=model_name,
                                    model_xml=model_string,
                                    robot_namespace=robot_namespace,
                                    initial_pose=Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z),
                                                        orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w)),
                                    reference_frame=reference_frame)
    
    try:
        result = client_srv(srv_model)
        return result.success
    except ServiceException:
        print("Error: Package used in model was not found, source the workspace in all terminals.")
        return False

def gazebo_get_model_state(model_name, relative_entity_name="world"):
    """
    Function to get the state of a model.

    :param model_name: Name of model to get the state of.
    :type model_name: str

    :param relative_entity_name: Return pose and twist relative to this entity (an entity can be a model, body, or geom).
    :type relative_entity_name: str

    :return: The header of the message, the pose of the model, the twist of the model, and success.
    """

    rospy.wait_for_service("/gazebo/get_model_state")
    client_srv = rospy.ServiceProxy("/gazebo/get_model_state", GetModelState)

    srv_msg = GetModelStateRequest(model_name=model_name, relative_entity_name=relative_entity_name)

    try:
        result = client_srv(srv_msg)
        return result.header, result.pose, result.twist, result.success
    except ServiceException:
        print("Error processing the request")
        return Header(), Pose(), Twist(), False

def gazebo_set_model_state(model_name, ref_frame="world", pos_x=0.0, pos_y=0.0, pos_z=0.0, ori_x=0.0, ori_y=0.0, ori_z=0.0, ori_w=0.0,
                            lin_vel_x=0.0, lin_vel_y=0.0, lin_vel_z=0.0, ang_vel_x=0.0, ang_vel_y=0.0, ang_vel_z=0.0, sleep_time=0.05) -> bool:
    """
    Function to set the model name in gazebo.

    :param model_name: Name of model to set.
    :type model_name: str

    :param ref_frame: Reference frame of model.
    :type ref_frame: str

    :param pos_x: x position of model in model's reference frame
    :type pos_x: float
    :param pos_y: y position of model in model's reference frame
    :type pos_y: float
    :param pos_z: z position of model in model's reference frame
    :type pos_z: float

    :param ori_x: X part of Quaternion of model orientation in model's reference frame.
    :type ori_x: float
    :param ori_y: Y part of Quaternion of model orientation in model's reference frame.
    :type ori_y: float
    :param ori_z: Z part of Quaternion of model orientation in model's reference frame.
    :type ori_z: float
    :param ori_w: W part of Quaternion of model orientation in model's reference frame.
    :type ori_w: float

    :param lin_vel_x: X part of linear velocity of model in model's reference frame.
    :type lin_vel_x: float
    :param lin_vel_y: Y part of linear velocity of model in model's reference frame.
    :type lin_vel_y: float
    :param lin_vel_z: Z part of linear velocity of model in model's reference frame.
    :type lin_vel_z: float

    :param ang_vel_x: X part of angular velocity of model in model's reference frame.
    :type ang_vel_x: float
    :param ang_vel_y: Y part of angular velocity of model in model's reference frame.
    :type ang_vel_y: float
    :param ang_vel_z: Z part of angular velocity of model in model's reference frame.
    :type ang_vel_z: float

    :param sleep_time: Time to sleep bewteen sending request and getting response.
    :type sleep_time: float

    :return: True if the command was sent and False otherwise.
    :rtype: bool
    """

    rospy.wait_for_service("/gazebo/set_model_state")
    client_srv = rospy.ServiceProxy("/gazebo/set_model_state", SetModelState)

    msg_pose = Pose(  position=Point(x=pos_x, y=pos_y, z=pos_z), orientation=Quaternion(x=ori_x, y=ori_y, z=ori_z, w=ori_w))
    msg_twist = Twist(  linear=Vector3(x=lin_vel_x, y=lin_vel_y, z=lin_vel_z), angular=Vector3(x=ang_vel_x, y=ang_vel_y, z=ang_vel_z))

    srv_msg = ModelState(model_name=model_name, pose=msg_pose, twist=msg_twist, reference_frame=ref_frame)

    srv_request = SetModelStateRequest(model_state=srv_msg)

    try:
        result = client_srv(srv_request)
        time.sleep(sleep_time)
        return result.success
    except ServiceException:
        print("Error processing the request")
        return False

加速gazebo仿真环境的使用方式:

#!/usr/bin/env python
# coding: utf-8

import rospy
from ros_gazebo import gazebo_set_max_update_rate

def main():
    # 初始化 ROS 节点
    rospy.init_node('speed_up_gazebo', anonymous=True)

    # 设置最大更新速率
    max_update_rate = 5

    try:
        # 调用函数设置最大更新速率
        success = gazebo_set_max_update_rate(max_update_rate)
        if success:
            rospy.loginfo(f"成功将 Gazebo 的最大更新速率设置为 {max_update_rate}")
        else:
            rospy.logerr("设置 Gazebo 最大更新速率失败")
    except rospy.ServiceException as e:
        rospy.logerr(f"服务调用失败: {e}")

if __name__ == '__main__':
    main()

可以看到加速了5倍:
在这里插入图片描述
也可以通过它来用xterm启动自己的仿真环境,示例:

#!/usr/bin/env python
# coding: utf-8

import rospy
import ros_gazebo
import ros_node
from ros_gazebo import gazebo_set_max_update_rate


def main():
    ros_node.ros_kill_all_processes()

    ros_gazebo.launch_Gazebo(paused=True, gui=True)

    # 初始化 ROS 节点
    rospy.init_node('speed_up_gazebo', anonymous=True)

if __name__ == '__main__':
    main()
    

在这里插入图片描述

ros_urdf.py:

可以用来加载我们的模型的urdf

#!/bin/python3

import rospy
import rospkg
import os
import xacro

def urdf_load_from_pkg(pkg_name, model_name, param_name, folder="/urdf", ns=None, args_xacro=None) -> bool:
    """
    从 ROS 包中加载 URDF 文件到参数服务器。

    :param pkg_name: ROS 包的名称。
    :type pkg_name: str

    :param model_name: 模型文件的名称。
    :type model_name: str

    :param param_name: 参数的名称。
    :type param_name: str

    :param folder: 模型所在的文件夹。默认为 "/urdf"
    :type folder: str

    :param ns: 参数的命名空间。
    :type ns: str

    :param args_xacro: xacro 参数列表,例如:['arg1:=True','arg2:=10.0']
    :type args_xacro: str 列表

    :return: 如果 URDF 文件已加载,则返回 True,否则返回 False。
    :rtype: bool
    """

    rospack = rospkg.RosPack()
    try:
        pkg_path = rospack.get_path(pkg_name)
        rospy.logdebug("找到包...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("未找到包")
        return False

    file_path = pkg_path + folder + "/" + model_name

    if os.path.exists(file_path) is False:
        print("错误:模型路径不存在")
        return False

    list_args = [file_path] 
    if args_xacro is not None:
        list_args = list_args + args_xacro

    opts, input_file_name = xacro.process_args(list_args)
    model = xacro.process_file(input_file_name, **vars(opts))
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)
    
    if ns is not None and ns != "/":
        final_param_name = ns + "/" + param_name
    else:
        final_param_name = param_name

    rospy.set_param(final_param_name, model_string)
    return True

def urdf_load_from_path(model_path, param_name, ns=None, args_xacro=None) -> bool:
    """
    从文件路径加载 URDF 文件到参数服务器。

    :param model_path: 模型文件的路径。
    :type model_path: str

    :param param_name: 参数的名称。
    :type param_name: str

    :param ns: 参数的命名空间。
    :type ns: str

    :param args_xacro: xacro 参数列表,例如:['arg1:=True','arg2:=10.0']
    :type args_xacro: str 列表

    :return: 如果 URDF 文件已加载,则返回 True,否则返回 False。
    :rtype: bool
    """

    if os.path.exists(model_path) is False:
        print("错误:模型路径不存在")
        return False

    list_args = [model_path] 
    if args_xacro is not None:
        list_args = list_args + args_xacro

    opts, input_file_name = xacro.process_args(list_args)
    model = xacro.process_file(input_file_name, **vars(opts))
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)

    if ns is not None and ns != "/":
        final_param_name = ns + "/" + param_name
    else:
        final_param_name = param_name

    rospy.set_param(final_param_name, model_string)
    return True

def urdf_parse_from_pkg(pkg_name, model_name, folder="/urdf", args_xacro=None) -> str:
    """
    从 ROS 包中解析 URDF 文件并返回 URDF 字符串。

    :param pkg_name: ROS 包的名称。
    :type pkg_name: str

    :param model_name: 模型文件的名称。
    :type model_name: str

    :param folder: 模型所在的文件夹。默认为 "/urdf"
    :type folder: str

    :param args_xacro: xacro 参数列表,例如:['arg1:=True','arg2:=10.0']
    :type args_xacro: str 列表

    :return: URDF 字符串,如果未找到包或文件,则返回 None。
    :rtype: str
    """
    rospack = rospkg.RosPack()
    try:
        pkg_path = rospack.get_path(pkg_name)
        rospy.logdebug("找到包...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("未找到包")
        return None

    file_path = pkg_path + folder + "/" + model_name

    if os.path.exists(file_path) is False:
        print("错误:模型路径不存在")
        return None

    list_args = [file_path] 
    if args_xacro is not None:
        list_args = list_args + args_xacro

    opts, input_file_name = xacro.process_args(list_args)
    model = xacro.process_file(input_file_name, **vars(opts))
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)

    return model_string

def urdf_parse_from_path(model_path, args_xacro=None) -> str:
    """
    从文件路径解析 URDF 文件并返回 URDF 字符串。

    :param model_path: 模型文件的路径。
    :type model_path: str

    :param args_xacro: xacro 参数列表,例如:['arg1:=True','arg2:=10.0']
    :type args_xacro: str 列表

    :return: URDF 字符串,如果未找到文件,则返回 None。
    :rtype: str
    """

    if os.path.exists(model_path) is False:
        print("错误:模型路径不存在")
        return None

    list_args = [model_path] 
    if args_xacro is not None:
        list_args = list_args + args_xacro

    opts, input_file_name = xacro.process_args(list_args)
    model = xacro.process_file(input_file_name, **vars(opts))
    encoding = {}
    model_string = model.toprettyxml(indent='  ', **encoding)

    return model_string

例如结合ros_gazebo:

    # 生成箱子
    UnitBox = ros_urdf.urdf_parse_from_pkg("kobuki_maze_rl", "model.sdf", folder="/worlds/Box")
    # 放置到某个位置
    ros_gazebo.gazebo_spawn_sdf_string(UnitBox, model_name="box1", pos_x= -2.5, pos_y=-5.0)

ros_param.py:

参数文件的快捷加载,可以通过功能包或者路径的形式去加载配置yaml文件

#!/bin/python3

import rospy
import rospkg
import os
import rosparam

def ros_load_yaml_from_pkg(pkg_name, file_name, ns='/') -> bool:
    """
    从包中获取 YAML 文件并将其加载到 ROS 参数服务器中。

    :param pkg_name: 包的名称。
    :type  pkg_name: str

    :param file_name: 文件的名称。
    :type  file_name: str

    :param ns: 要加载参数的命名空间。
    :type  ns: str

    :return: 如果文件已加载,则返回 True,否则返回 False。
    :rtype: bool
    """

    rospack = rospkg.RosPack()
    try:
        pkg_path = rospack.get_path(pkg_name)
        rospy.logdebug("找到包...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("未找到包")
        return False

    file_path = pkg_path + "/config/" + file_name
    if os.path.exists(pkg_path + "/config/" + file_name) is False:
        print("配置文件 " + file_name + " 在 " + file_path + " 中不存在")
        return False

    paramlist = rosparam.load_file(file_path)
    
    for params, namespace in paramlist:
        rosparam.upload_params(ns, params)

    return True

def ros_load_yaml_from_path(file_path, ns='/') -> bool:
    """
    从路径中获取 YAML 文件并将其加载到 ROS 参数服务器中。

    :param file_path: 文件的路径。
    :type  file_path: str

    :param ns: 要加载参数的命名空间。
    :type  ns: str

    :return: 如果文件已加载,则返回 True,否则返回 False。
    :rtype: bool
    """

    if os.path.exists(file_path) is False:
        print("配置文件 " + file_path + " 不存在")
        return False

    paramlist = rosparam.load_file(file_path)
    
    for params, namespace in paramlist:
        rosparam.upload_params(ns, params)

    return True

ros_node.py:

#!/bin/python3

import subprocess
import time

import rospkg
import rospy

"""
与 ROS 节点处理相关的函数。
"""


def ros_node_from_pkg(
    pkg_name,
    node_name,
    launch_master=False,
    launch_master_term=True,
    launch_new_term=True,
    name=None,
    ns="/",
    output="log",
) -> bool:
    """
    从包中启动 ROS 节点的函数。

    :param pkg_name: 要从中启动节点的包的名称。
    :type pkg_name: str

    :param node_name: 要启动的节点的名称。
    :type node_name: str

    :param launch_master: 如果 ROSMASTER 没有运行,则启动它。
    :type launch_master: bool

    :param launch_master_term: 如果启动 ROSMASTER,则在外部终端中启动。
    :type launch_master_term: bool

    :param launch_new_term: 是否在新终端(Xterm)中启动进程。
    :type launch_new_term: bool

    :param name: 要启动的节点的名称。
    :type name: str

    :param ns: 要启动的节点的命名空间。
    :type ns: str

    :param output: 输出目标,可以是 log、screen 或 None。
    :type output: str

    :return: 如果节点已启动,则返回 True,否则返回 False。
    :rtype: bool
    """

    rospack = rospkg.RosPack()
    try:
        rospack.get_path(pkg_name)
        rospy.logdebug("找到包...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("未找到包")
        return False

    if launch_master:
        print("启动 Master")
        try:
            rospy.get_master().getPid()
        except ConnectionRefusedError:
            print("Master 未运行")
            if launch_master_term:
                subprocess.Popen("xterm -e 'roscore' ", shell=True)
            else:
                subprocess.Popen("roscore", shell=True)
            time.sleep(5.0)
        else:
            print("Master 正在运行")

    try:
        rospy.get_master().getPid()
    except ConnectionRefusedError:
        print("Master 未运行")
        return False
    else:
        print("Master 正在运行")

    term_command = "rosrun " + pkg_name + " " + node_name

    if name is not None:
        term_command += " __name:=" + str(name)

    term_command += " __ns:=" + str(ns)
    term_command += " __log:=" + str(output)

    if launch_new_term:
        term_command = "xterm -e ' " + term_command + "'"

    subprocess.Popen(term_command, shell=True)
    time.sleep(5.0)

    return True


def ros_kill_node(node_name) -> bool:
    """
    杀死 ROS 节点的函数。

    :param node_name: 要杀死的节点的名称。
    :type node_name: str

    :return: 如果节点被杀死,则返回 True,否则返回 False。
    :rtype: bool
    """

    term_command = "rosnode kill " + node_name
    subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()
    return True


def ros_kill_all_nodes() -> bool:
    """
    杀死所有正在运行的 ROS 节点的函数。

    :return: 如果所有节点被杀死,则返回 True,否则返回 False。
    :rtype: bool
    """

    term_command = "rosnode kill -a"
    subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()
    return True


def ros_kill_master() -> bool:
    """
    杀死 ROS master 的函数。

    :return: 如果 master 被杀死,则返回 True,否则返回 False。
    :rtype: bool
    """

    try:
        rospy.get_master().getPid()
    except ConnectionRefusedError:
        print("Master 未运行")
        return True
    else:
        print("Master 正在运行")
        term_command = "rosnode kill -a"
        subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()
        time.sleep(0.5)
        term_command = "killall -9 rosout roslaunch rosmaster nodelet"
        subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()

        return True


def ros_kill_all_processes() -> bool:
    """
    函数用于杀死所有正在运行的与ROS相关的进程。

    :return: 如果所有进程都被杀死,则返回True,否则返回False。
    :rtype: bool
    """

    # 定义要终止的进程命令
    term_command = "killall -9 rosout roslaunch rosmaster gzserver nodelet robot_state_publisher gzclient xterm"
    # 使用subprocess.Popen执行命令,并等待命令执行完成
    subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()
    # 返回True表示所有进程已被杀死
    return True

ros_launch.py:

#!/bin/python3

import rospy
import rospkg
import os
import subprocess
import time

def ros_launch_from_pkg(pkg_name, launch_file, args=None, launch_new_term=True) -> bool:
    """
    从包中执行 roslaunch 文件的函数。
    :param pkg_name: 包含 launch 文件的包的名称。
    :type pkg_name: str
    
    :param launch_file: launch 文件的名称。
    :type launch_file: str
    
    :param args: 要传递给 launch 文件的参数。
    :type args: str 列表

    :param launch_new_term: 是否在新终端(Xterm)中启动进程。
    :type launch_new_term: bool

    :return: 如果 launch 文件已执行,则返回 True。
    :rtype: bool
    """

    rospack = rospkg.RosPack()
    try:
        pkg_path = rospack.get_path(pkg_name)
        rospy.logdebug("找到包...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("未找到包")
        return False

    file_path = pkg_path + "/launch/" + launch_file
    if os.path.exists(pkg_path + "/launch/" + launch_file) is False:
        print("launch 文件 " + launch_file + " 在 " + file_path + " 中不存在")
        return False

    term_command = "roslaunch " + pkg_name + " " + launch_file

    if args is not None:
        for arg in args:
            term_command += " " + arg

    if launch_new_term:
        term_command = "xterm -e ' " + term_command + "'"
    
    subprocess.Popen(term_command, shell=True)
    time.sleep(5.0)

    return True

def ros_launch_from_path(launch_file_path, args=None, launch_new_term=True) -> bool:
    """
    从路径中执行 roslaunch 文件的函数。
    :param launch_file_path: launch 文件的路径。
    :type launch_file_path: str

    :param args: 要传递给 launch 文件的参数。
    :type args: str 列表

    :param launch_new_term: 是否在新终端(Xterm)中启动进程。
    :type launch_new_term: bool

    :return: 如果 launch 文件已执行,则返回 True。
    :rtype: bool
    """

    if os.path.exists(launch_file_path) is False:
        print("launch 文件 " + launch_file_path + " 不存在")
        return False

    term_command = "roslaunch " + launch_file_path

    if args is not None:
        for arg in args:
            term_command += " " + arg

    if launch_new_term:
        term_command = "xterm -e ' " + term_command + "'"
    
    subprocess.Popen(term_command, shell=True)
    time.sleep(5.0)

    return True

def ros_kill_launch_process() -> bool:
    """
    杀死所有 roslaunch 进程的函数。

    :return: 如果 roslaunch 进程被杀死,则返回 True。
    :rtype: bool
    """
    term_command = "killall -9 roslaunch"
    subprocess.Popen("xterm -e ' " + term_command + "'", shell=True).wait()
    return True

加载模型

ros_spawn.py:

#!/bin/python3

import rospy
import time
from frobs_rl.common import ros_gazebo
from frobs_rl.common import ros_controllers
from frobs_rl.common import ros_node
from frobs_rl.common import ros_params
from frobs_rl.common import ros_urdf

def init_robot_state_pub(namespace="/", max_pub_freq=None, launch_new_term=False) -> bool:
    """
    初始化机器人状态发布器的函数。

    :param namespace: 机器人的命名空间。
    :type namespace: str

    :param max_pub_freq: 发布器的最大发布频率。
    :type max_pub_freq: float

    :param launch_new_term: 是否在新终端(Xterm)中启动进程。
    :type launch_new_term: bool

    :return: 如果发布器已初始化,则返回 True。
    :rtype: bool
    """

    if max_pub_freq is not None:
        if namespace != "/":
            rospy.set_param(namespace + "/rob_st_pub/publish_frequency", max_pub_freq)
        else:
            rospy.set_param("/rob_st_pub/publish_frequency", max_pub_freq)
            
    return ros_node.ros_node_from_pkg("robot_state_publisher", "robot_state_publisher", launch_new_term=launch_new_term, name="rob_st_pub", ns=namespace)


def spawn_model_in_gazebo(  pkg_name, model_urdf_file, 
                            controllers_file, controllers_list=[],
                            model_urdf_folder="/urdf", ns="/", args_xacro=None, max_pub_freq=None, rob_st_term=False,
                            gazebo_name="robot1", gaz_ref_frame="world", 
                            pos_x=0.0, pos_y=0.0, pos_z=0.0, ori_w=0.0, ori_x=0.0, ori_y=0.0, ori_z=0.0):
    """
    在 Gazebo 中生成模型的函数。

    :param pkg_name: 模型所在的包名。
    :type pkg_name: str

    :param model_urdf_file: 模型的 URDF 文件名。
    :type model_urdf_file: str

    :param controllers_file: 控制器文件的名称。如果为 None,则不会加载任何控制器。
    :type controllers_file: str

    :param controllers_list: 要加载的控制器列表。
    :type controllers_list: list

    :param model_urdf_folder: 模型 URDF 文件所在的文件夹。默认为 "/urdf"。
    :type model_urdf_folder: str

    :param ns: 模型的命名空间。默认为 "/"。
    :type ns: str

    :param args_xacro: 要传递给 xacro 的参数。
    :type args_xacro: list

    :param max_pub_freq: 机器人状态发布器的最大发布频率。
    :type max_pub_freq: float

    :param rob_st_term: 是否在新终端(Xterm)中启动机器人状态发布器。
    :type rob_st_term: bool

    :param gazebo_name: Gazebo 模型的名称。
    :type gazebo_name: str

    :param gaz_ref_frame: Gazebo 模型的参考框架。
    :type gaz_ref_frame: str

    :param pos_x: Gazebo 模型的 X 位置。
    :param pos_y: Gazebo 模型的 Y 位置。
    :param pos_z: Gazebo 模型的 Z 位置。
    :type pos_x: float
    :type pos_y: float
    :type pos_z: float

    :param ori_w: Gazebo 模型的 W 方向。
    :param ori_x: Gazebo 模型的 X 方向。
    :param ori_y: Gazebo 模型的 Y 方向。
    :param ori_z: Gazebo 模型的 Z 方向。
    :type ori_w: float
    :type ori_x: float
    :type ori_y: float
    :type ori_z: float

    :return: 如果模型已生成,则返回 True。
    :rtype: bool
    """

    # 将模型 URDF 加载到参数服务器中
    if ros_urdf.urdf_load_from_pkg(pkg_name, model_urdf_file, "robot_description", folder=model_urdf_folder, ns=ns, args_xacro=args_xacro):
        rospy.logwarn("URDF 文件加载成功")
    else:
        rospy.logwarn("加载 URDF 文件时出错")
        return False
    
    time.sleep(0.1)

    # 初始化机器人状态发布器
    if init_robot_state_pub(namespace=ns, max_pub_freq=max_pub_freq, launch_new_term=rob_st_term):
        rospy.logwarn("机器人状态发布器初始化成功")
    else:
        rospy.logwarn("初始化机器人状态发布器时出错")
        return False

    time.sleep(0.1)

    # 在 Gazebo 中生成模型
    result_spawn, message = ros_gazebo.gazebo_spawn_urdf_param("robot_description", model_name=gazebo_name, robot_namespace=ns, reference_frame=gaz_ref_frame,
                                        pos_x=pos_x, pos_y=pos_y, pos_z=pos_z, ori_w=ori_w, ori_x=ori_x, ori_y=ori_y, ori_z=ori_z,)
    if result_spawn:
        rospy.logwarn("模型生成成功")
    else:
        rospy.logwarn("生成模型时出错")
        rospy.logwarn(message)
        return False

    time.sleep(0.1)

    if controllers_file is not None:
        # 从 YAML 文件中将机器人控制器加载到参数服务器中
        if ros_params.ros_load_yaml_from_pkg(pkg_name, controllers_file, ns=ns):
            rospy.logwarn("机器人控制器加载成功")
        else:
            rospy.logwarn("加载机器人控制器时出错")
            return False

        time.sleep(0.1)

        # 生成控制器
        if ros_controllers.spawn_controllers_srv(controllers_list, ns=ns):
            rospy.logwarn("控制器生成成功")
        else:
            rospy.logwarn("生成控制器时出错")
            return False
    
    return True

ros_controller.py

管理ros中的控制器

#!/usr/bin/env python

import rospy
from controller_manager_msgs.srv import *

def load_controller_srv(controller_name, ns=None, max_retries=5) -> bool:
    """
    在命名空间中加载控制器的服务函数。

    :param controller_name: 要加载的控制器名称
    :type controller_name: 字符串

    :param ns: 命名空间
    :type ns: 字符串

    :param max_retries: 加载控制器的最大重试次数。
    :type max_retries: 整数

    :return: 如果控制器加载成功,则返回 True。
    :rtype: 布尔值
    """

    if ns is not None:
        srv_name = ns + '/controller_manager/load_controller'
    else:
        srv_name = '/controller_manager/load_controller'

    rospy.wait_for_service(srv_name)
    client_srv = rospy.ServiceProxy(srv_name, LoadController)
    
    try: 
        for ii in range(max_retries):
            srv_request = LoadControllerRequest(name=controller_name)
            resp1 = client_srv(srv_request)
            if resp1.ok:
                return True
            
        if resp1.ok is False:
            print("控制器 " + controller_name + " 无法加载。")
        
        return resp1.ok
    
    except rospy.ServiceException as exc:
        print("服务未处理请求: " + str(exc))
        return False

def load_controller_list_srv(controller_list,ns=None, max_retries=5) -> None:
    """
    在命名空间中加载控制器列表的服务函数。

    :param controller_list: 要加载的控制器列表
    :type controller_list: 字符串列表

    :param ns: 命名空间
    :type ns: 字符串

    :param max_retries: 加载控制器的最大重试次数。
    :type max_retries: 整数
    """

    for controller in controller_list:
        load_controller_srv(controller, ns=ns, max_retries=max_retries)

def unload_controller_srv(controller_name,ns=None, max_retries=5) -> bool:
    """
    在命名空间中卸载控制器的服务函数。

    :param controller_name: 要卸载的控制器名称
    :type controller_name: 字符串

    :param ns: 命名空间
    :type ns: 字符串

    :param max_retries: 卸载控制器的最大重试次数。
    :type max_retries: 整数

    :return: 如果控制器卸载成功,则返回 True。
    :rtype: 布尔值
    """

    if ns is not None:
        srv_name = ns + '/controller_manager/unload_controller'
    else:
        srv_name = '/controller_manager/unload_controller'

    rospy.wait_for_service(srv_name)
    client_srv = rospy.ServiceProxy(srv_name, UnloadController)
    
    try: 
        for ii in range(max_retries):
            srv_request = UnloadControllerRequest(name=controller_name)
            resp1 = client_srv(srv_request)
            if resp1.ok:
                return True

        if resp1.ok is False:
            print("控制器 " + controller_name + " 无法卸载。")    
        
        return resp1.ok

    except rospy.ServiceException as exc:
        print("服务未处理请求: " + str(exc))
        return False

def unload_controller_list_srv(controller_list,ns=None, max_retries=5) -> None:
    """
    在命名空间中卸载控制器列表的服务函数。

    :param controller_list: 要卸载的控制器列表
    :type controller_list: 字符串列表

    :param ns: 命名空间
    :type ns: 字符串

    :param max_retries: 卸载控制器的最大重试次数。
    :type max_retries: 整数
    """
    for controller in controller_list:
        unload_controller_srv(controller, ns=ns, max_retries=max_retries)

def switch_controllers_srv( start_controllers, stop_controllers, ns=None, 
                            strictness=1, start_asap=False, timeout=3.0, max_retries=5) -> bool:
    """
    在命名空间中切换控制器的服务函数。

    :param start_controllers: 要启动的控制器列表
    :type start_controllers: 字符串列表

    :param stop_controllers: 要停止的控制器列表
    :type stop_controllers: 字符串列表

    :param ns: 命名空间
    :type ns: 字符串

    :param strictness: 控制器管理器的严格性:BEST_EFFORT 或 STRICT (1 和 2,分别)。
    :type strictness: 整数

    :param start_asap: 一旦硬件依赖项准备就绪,立即启动控制器,否则等待所有接口准备就绪。
    :type start_asap: 布尔值

    :param timeout: 在中止挂起的控制器之前等待的超时时间(以秒为单位)。零表示无限。
    :type timeout: 浮点数

    :param max_retries: 切换控制器的最大重试次数。
    :type max_retries: 整数

    :return: 如果操作成功,则返回 True。
    :rtype: 布尔值
    """

    if ns is not None:
        srv_name = ns + '/controller_manager/switch_controller'
    else:
        srv_name = '/controller_manager/switch_controller'

    rospy.wait_for_service(srv_name)
    client_srv = rospy.ServiceProxy(srv_name, SwitchController)
    
    try: 
        for ii in range(max_retries):
            srv_request = SwitchControllerRequest(  start_controllers=start_controllers,stop_controllers=stop_controllers,
                                                    strictness=strictness,start_asap=start_asap,timeout=timeout)
            resp1 = client_srv(srv_request)
            if resp1.ok:
                return True
        
        if resp1.ok is False:
            print("控制器无法切换。")

        return resp1.ok
    except rospy.ServiceException as exc:
        print("服务未处理请求: " + str(exc))
        return False

def start_controllers_srv(start_controllers, ns=None, strictness=1, start_asap=False, timeout=3.0) -> bool:
    """
    在命名空间中启动控制器的服务函数。

    :param start_controllers: 要启动的控制器列表
    :type start_controllers: 字符串列表

    :param ns: 命名空间
    :type ns: 字符串

    :param strictness: 控制器管理器的严格性:BEST_EFFORT 或 STRICT (1 和 2,分别)。
    :type strictness: 整数

    :param start_asap: 一旦硬件依赖项准备就绪,立即启动控制器,否则等待所有接口准备就绪。
    :type start_asap: 布尔值

    :param timeout: 在中止挂起的控制器之前等待的超时时间(以秒为单位)。零表示无限。
    :type timeout: 浮点数

    :return: 如果操作成功,则返回 True。
    :rtype: 布尔值
    """

    return switch_controllers_srv(start_controllers, [], ns=ns, strictness=strictness, start_asap=start_asap, timeout=timeout)

def stop_controllers_srv(stop_controllers, ns=None, strictness=1, start_asap=False, timeout=3.0) -> bool:
    """
    在命名空间中停止控制器的服务函数。

    :param stop_controllers: 要停止的控制器列表
    :type stop_controllers: 字符串列表

    :param ns: 命名空间
    :type ns: 字符串

    :param strictness: 控制器管理器的严格性:BEST_EFFORT 或 STRICT (1 和 2,分别)。
    :type strictness: 整数

    :param start_asap: 一旦硬件依赖项准备就绪,立即启动控制器,否则等待所有接口准备就绪。
    :type start_asap: 布尔值

    :param timeout: 在中止挂起的控制器之前等待的超时时间(以秒为单位)。零表示无限。
    :type timeout: 浮点数

    :return: 如果操作成功,则返回 True。
    :rtype: 布尔值
    """

    return switch_controllers_srv([], stop_controllers, ns=ns, strictness=strictness, start_asap=start_asap, timeout=timeout)

def reset_controllers_srv(reset_controllers, max_retries=10, ns=None, strictness=1, start_asap=False, timeout=3.0) -> bool:
    """
    在命名空间中重置控制器的服务函数。

    :param reset_controllers: 要重置的控制器列表
    :type reset_controllers: 字符串列表

    :param max_retries: 在放弃之前重置控制器的最大重试次数。
    :type max_retries: 整数

    :param ns: 命名空间
    :type ns: 字符串

    :param strictness: 控制器管理器的严格性:BEST_EFFORT 或 STRICT (1 和 2,分别)。
    :type strictness: 整数

    :param start_asap: 一旦硬件依赖项准备就绪,立即启动控制器,否则等待所有接口准备就绪。
    :type start_asap: 布尔值

    :param timeout: 在中止挂起的控制器之前等待的超时时间(以秒为单位)。零表示无限。
    :type timeout: 浮点数

    :return: 如果操作成功,则返回 True。
    :rtype: 布尔值
    """

    done_switch_off = False
    for ii in range(max_retries):
        done_switch_off = stop_controllers_srv(reset_controllers, ns=ns, strictness=strictness, start_asap=start_asap, timeout=timeout)
        if done_switch_off:
            break
    
    if not done_switch_off:
        return False

    done_switch_on = False
    for ii in range(max_retries):
        done_switch_on = start_controllers_srv(reset_controllers, ns=ns, strictness=strictness, start_asap=start_asap, timeout=timeout)
        if done_switch_on:
            break

    if not done_switch_on:
        return False
    
    return True

def spawn_controllers_srv(spawn_controllers, ns=None, strictness=1, start_asap=False, timeout=3.0) -> bool:
    """
    在命名空间中生成控制器的服务函数。

    :param spawn_controllers: 要生成的控制器列表
    :type spawn_controllers: 字符串列表

    :param ns: 命名空间
    :type ns: 字符串

    :param strictness: 控制器管理器的严格性:BEST_EFFORT 或 STRICT (1 和 2,分别)。
    :type strictness: 整数

    :param start_asap: 一旦硬件依赖项准备就绪,立即启动控制器,否则等待所有接口准备就绪。
    :type start_asap: 布尔值

    :param timeout: 在中止挂起的控制器之前等待的超时时间(以秒为单位)。零表示无限。
    :type timeout: 浮点数

    :return: 如果操作成功,则返回 True。
    :rtype: 布尔值
    """

    load_controller_list_srv(spawn_controllers, ns=ns)

    return start_controllers_srv(spawn_controllers, ns=ns, strictness=strictness, start_asap=start_asap, timeout=timeout)

def kill_controllers_srv(kill_controllers, ns=None, strictness=1, start_asap=False, timeout=3.0) -> bool:
    """
    在命名空间中杀死控制器的服务函数。

    :param kill_controllers: 要杀死的控制器列表
    :type kill_controllers: 字符串列表

    :param ns: 命名空间
    :type ns: 字符串

    :param strictness: 控制器管理器的严格性:BEST_EFFORT 或 STRICT (1 和 2,分别)。
    :type strictness: 整数

    :param start_asap: 一旦硬件依赖项准备就绪,立即启动控制器,否则等待所有接口准备就绪。
    :type start_asap: 布尔值

    :param timeout: 在中止挂起的控制器之前等待的超时时间(以秒为单位)。零表示无限。
    :type timeout: 浮点数

    :return: 如果操作成功,则返回 True。
    :rtype: 布尔值
    """

    res = stop_controllers_srv(kill_controllers, ns=ns, strictness=strictness, start_asap=start_asap, timeout=timeout)

    if res:
        unload_controller_list_srv(kill_controllers, ns=ns)
        return True
    else:
        return False

使用示例:

#!/usr/bin/env python

import rospy
import time

# 导入你的函数模块(假设上述代码保存为`controller_manager_utils.py`)
from controller_manager_utils import (
    load_controller_srv,
    unload_controller_srv,
    start_controllers_srv,
    stop_controllers_srv,
    reset_controllers_srv,
    spawn_controllers_srv,
    kill_controllers_srv
)

def main():
    rospy.init_node("controller_manager_test", anonymous=True)

    # 示例控制器名称
    controller_name = "joint_state_controller"
    controller_list = ["joint_state_controller", "effort_controller"]

    # 1. 加载控制器
    rospy.loginfo("加载控制器: {}".format(controller_name))
    if load_controller_srv(controller_name):
        rospy.loginfo("控制器加载成功")
    else:
        rospy.logerr("控制器加载失败")

    # 2. 启动控制器
    rospy.loginfo("启动控制器: {}".format(controller_name))
    if start_controllers_srv([controller_name]):
        rospy.loginfo("控制器启动成功")
    else:
        rospy.logerr("控制器启动失败")

    # 等待一段时间
    time.sleep(2)

    # 3. 停止控制器
    rospy.loginfo("停止控制器: {}".format(controller_name))
    if stop_controllers_srv([controller_name]):
        rospy.loginfo("控制器停止成功")
    else:
        rospy.logerr("控制器停止失败")

    # 4. 卸载控制器
    rospy.loginfo("卸载控制器: {}".format(controller_name))
    if unload_controller_srv(controller_name):
        rospy.loginfo("控制器卸载成功")
    else:
        rospy.logerr("控制器卸载失败")

    # 5. 测试控制器列表操作
    rospy.loginfo("加载控制器列表: {}".format(controller_list))
    load_controller_list_srv(controller_list)

    rospy.loginfo("启动控制器列表: {}".format(controller_list))
    if start_controllers_srv(controller_list):
        rospy.loginfo("控制器列表启动成功")
    else:
        rospy.logerr("控制器列表启动失败")

    time.sleep(2)

    rospy.loginfo("停止控制器列表: {}".format(controller_list))
    if stop_controllers_srv(controller_list):
        rospy.loginfo("控制器列表停止成功")
    else:
        rospy.logerr("控制器列表停止失败")

    rospy.loginfo("卸载控制器列表: {}".format(controller_list))
    unload_controller_list_srv(controller_list)

    # 6. 测试重置控制器
    rospy.loginfo("测试重置控制器: {}".format(controller_name))
    if reset_controllers_srv([controller_name]):
        rospy.loginfo("控制器重置成功")
    else:
        rospy.logerr("控制器重置失败")

    # 7. 测试生成和杀死控制器
    rospy.loginfo("测试生成控制器: {}".format(controller_name))
    if spawn_controllers_srv([controller_name]):
        rospy.loginfo("控制器生成成功")
    else:
        rospy.logerr("控制器生成失败")

    time.sleep(2)

    rospy.loginfo("测试杀死控制器: {}".format(controller_name))
    if kill_controllers_srv([controller_name]):
        rospy.loginfo("控制器杀死成功")
    else:
        rospy.logerr("控制器杀死失败")

if __name__ == "__main__":
    try:
        main()
    except rospy.ROSInterruptException:
        pass

但是在实际使用的过程中发现控制器启动失败了,所以我还是使用node,通过spawer来加载和启动控制器。

        # # 启动 controller_manager 的 spawner 节点
        node_name = "cartpole_controller_node"
        pkg_name = "controller_manager"
        node_type = "spawner"
        controllers = "joint_state_controller stand_cart_position_controller"
        ros_node.ros_node_from_pkg(pkg_name, node_type, launch_new_term=False, name=node_name, ns=ns, args=controllers)

由于node之前没有考虑有args传入,所以也需要对应修改一下:

def ros_node_from_pkg(
    pkg_name,
    node_name,
    launch_master=False,
    launch_master_term=True,
    launch_new_term=True,
    name=None,
    ns="/",
    output="log",
    args=None  # 新增参数
) -> bool:
    """
    从包中启动 ROS 节点的函数。

    :param pkg_name: 要从中启动节点的包的名称。
    :type pkg_name: str

    :param node_name: 要启动的节点的名称。
    :type node_name: str

    :param launch_master: 如果 ROSMASTER 没有运行,则启动它。
    :type launch_master: bool

    :param launch_master_term: 如果启动 ROSMASTER,则在外部终端中启动。
    :type launch_master_term: bool

    :param launch_new_term: 是否在新终端(Xterm)中启动进程。
    :type launch_new_term: bool

    :param name: 要启动的节点的名称。
    :type name: str

    :param ns: 要启动的节点的命名空间。
    :type ns: str

    :param output: 输出目标,可以是 log、screen 或 None。
    :type output: str

    :param args: 要传递给节点的额外参数。
    :type args: str

    :return: 如果节点已启动,则返回 True,否则返回 False。
    :rtype: bool
    """

    rospack = rospkg.RosPack()
    try:
        rospack.get_path(pkg_name)
        rospy.logdebug("找到包...")
    except rospkg.common.ResourceNotFound:
        rospy.logerr("未找到包")
        return False

    if launch_master:
        print("启动 Master")
        try:
            rospy.get_master().getPid()
        except ConnectionRefusedError:
            print("Master 未运行")
            if launch_master_term:
                subprocess.Popen("xterm -e 'roscore' ", shell=True)
            else:
                subprocess.Popen("roscore", shell=True)
            time.sleep(5.0)
        else:
            print("Master 正在运行")

    try:
        rospy.get_master().getPid()
    except ConnectionRefusedError:
        print("Master 未运行")
        return False
    else:
        print("Master 正在运行")

    term_command = "rosrun " + pkg_name + " " + node_name

    if name is not None:
        term_command += " __name:=" + str(name)

    term_command += " __ns:=" + str(ns)
    term_command += " __log:=" + str(output)

    if args is not None:
        term_command += " " + args  # 将额外的参数添加到命令中

    if launch_new_term:
        term_command = "xterm -e ' " + term_command + "'"

    subprocess.Popen(term_command, shell=True)
    time.sleep(5.0)

    return True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白云千载尽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值