ros_control中的controller_manager通过硬实时控制环来控制抽象机器人对象hardware_interface::RobotHW,另外支持controller的加载,卸载,启动和停止。当controller_manager加载controller时候会将controller name作为其所有参数的root,及type(决定加载哪个插件)。
一 controller_manager重要数据结构
1 controller_manager::ControllerLoader< T > Class Template
缺省controller加载器使用pluginlib来加载并实例化controller插件库。 模板参数T是要加载的controller类型的基类。
2 controller_manager::ControllerLoaderInterface Class
这个接口被用以实现以source方式加载和实例化controllers,而非基于插件的方式。 from sources other than the pluginlib-based ControllerLoader.
3 controller_manager::ControllerSpec Struct
该struct含有指向给定controller的指针和controller info。
4 controller_manager::ControllerManager Class
ROS Controller Manager and Runner
该class支持ROS interface for loading, unloading, starting, and stopping ros_control-based controllers。 它也update接口序列化运行controller。
class ControllerManager{
public:
//Parameters
//robot_hw A pointer to a robot hardware interface
//nh The ros::NodeHandle in whose namespace all ROS interfaces should operate.
ControllerManager(hardware_interface::RobotHW *robot_hw,
const ros::NodeHandle& nh=ros::NodeHandle());
virtual ~ControllerManager();
//Update all active controllers.
//When controllers are started or stopped (or switched), those calls are made in this function.
//Parameters
//time The current time
//period The change in time since the last call to update
//reset_controllers If true, stop and start all running controllers before updating
void update(const ros::Time& time, const ros::Duration& period, bool reset_controllers=false);
//Load a new controller by name.
//This dynamically loads a controller called name and initializes the newly loaded controller.
//It determines the controller type by accessing the ROS parameter "type" in the namespace given by name relative to the namespace of root_nh_.
//It then initializes the controller with the hardware_interface::RobotHW pointer robot_hw_,
//the ros::NodeHandle describing this namespace, and a reference to a std::set to retrieve the resources needed by this controller.
//A controller cannot be loaded while already loaded. To re-load a controller, first unloadController and then loadController.
//Parameters
//name The name of the controller as well as the ROS namespace under which the controller should be loaded
//Returns
//True on success
//False on failure
bool loadController(const std::string& name);
bool unloadController(const std::string &name);
//Switch multiple controllers simultaneously.
//Parameters
//start_controllers A vector of controller names to be started
//stop_controllers A vector of controller names to be stopped
//strictness How important it is that the requested controllers are started and stopped.
//The levels are defined in the controller_manager_msgs/SwitchControllers service as either BEST_EFFORT or STRICT.
//BEST_EFFORT means that switchController can still succeed if a non-existent controller is requested to be stopped or started.
bool switchController(const std::vector<std::string>& start_controllers,
const std::vector<std::string>& stop_controllers,
const int strictness);
//Get a controller by name
virtual controller_interface::ControllerBase* getControllerByName(const std::string& name);
//Register a controller loader.
//By default, the pluginlib-based ControllerLoader is registered on construction of this class.
//To load controllers through alternate means, register alternate controller loaders here.
//Note, however, that when controllers are loaded by loadController the controller loaders are queried in the order that they were registered.
//This means that if a controller CAN be loaded by the pluginlib-based ControllerLoader, then it WILL, regardless of which other loaders are registered.
//Parameters
//controller_loader A pointer to the loader to be registered
void registerControllerLoader(boost::shared_ptr<ControllerLoaderInterface> controller_loader);
private:
void getControllerNames(std::vector<std::string> &v);
hardware_interface::RobotHW* robot_hw_;
ros::NodeHandle root_nh_, cm_node_;
typedef boost::shared_ptr<ControllerLoaderInterface> LoaderPtr;
std::list<LoaderPtr> controller_loaders_;
std::vector<controller_interface::ControllerBase*> start_request_, stop_request_;
std::list<hardware_interface::ControllerInfo> switch_start_list_, switch_stop_list_;
bool please_switch_;
int switch_strictness_;
boost::recursive_mutex controllers_lock_;
std::vector<ControllerSpec> controllers_lists_[2];
int current_controllers_list_;
int used_by_realtime_;
bool listControllerTypesSrv(controller_manager_msgs::ListControllerTypes::Request &req,
controller_manager_msgs::ListControllerTypes::Response &resp);
bool listControllersSrv(controller_manager_msgs::ListControllers::Request &req,
controller_manager_msgs::ListControllers::Response &resp);
bool switchControllerSrv(controller_manager_msgs::SwitchController::Request &req,
controller_manager_msgs::SwitchController::Response &resp);
bool loadControllerSrv(controller_manager_msgs::LoadController::Request &req,
controller_manager_msgs::LoadController::Response &resp);
bool unloadControllerSrv(controller_manager_msgs::UnloadController::Request &req,
controller_manager_msgs::UnloadController::Response &resp);
bool reloadControllerLibrariesSrv(controller_manager_msgs::ReloadControllerLibraries::Request &req,
controller_manager_msgs::ReloadControllerLibraries::Response &resp);
boost::mutex services_lock_;
ros::ServiceServer srv_list_controllers_, srv_list_controller_types_, srv_load_controller_;
ros::ServiceServer srv_unload_controller_, srv_switch_controller_, srv_reload_libraries_;
};
二 controller_manager使用方法
controller_manager可以基于你运行controller的不同方式(启动文件的方式,命令行的方式,ROS node方式)诉求, 提供相应的工具来运行controller,以下是controller_manager运行controller的简单状态机,
下面基于不同方式,介绍controller_manager如何运行controller:
1 Command-line tools
1.1 controller_manager
可以使用controller_manager脚本实现controller_manager与controller交互。
(1)controller_manager与controller交互命令
$ rosrun controller_manager controller_manager <command> <controller_name>
命令选项:
-
load: 加载controller (controller构造和初始化)
-
unload: 卸载controller (析构controller)
-
start: 启动controller
-
stop: 停止controller
-
spawn: 加载并启动controller
-
kill: 停止并卸载controller
$ rosrun controller_manager controller_manager <command>
命令选项:
-
list: 按照controller启动运行顺序给出每个controller的状态
-
list-types: 列出所有controller_manager管理的controller类型。如果你要使用controller不在该列表你 就不能启动它
-
reload-libraries: 重载所有controller插件库。插件方式的controller库在开发新的controller是非常便于测试,不需要每次重启robot。这不会重启之前运行的controllers
-
reload-libraries --restore: 重载所有controller插件并恢复controller到原始状态。
使用该工具可以实现一次自动加载并启动所有controller,一次自动停止并卸载所有controller。
$ rosrun controller_manager spawner [--stopped] name1 name2 name3
当你运行spawner且没有指定--stoped时候,所有命令中列举的controller将被加载和启动。 the listed controllers will get loaded and started (unless you specify --stopped). 如果controller出于up状态,Spawner会保持运行它。当你执行ctrl-c或者kill spawner时候,将自动停止并卸载之间加载启动的controller。
1.3 unspawner
实现自动停止,然后重启controller的功能,
$ rosrun controller_manager unspawner name1 name2 name3
命令列举的controllers会被停止,但是不会被卸载。 一旦spawner关闭,controller将被重启。
2 launch files
我们可以在启动文件让controller_manager来启动 controllers,但是这种方式在launch被down时候controller还会保持up。 而在启动文件中使用spawner的话,可以实现controller的自动加载启动和停止卸载(当你启动spawner时候加载并启动controller,当停止spawner<launch文件down>时候停止并卸载controller)。
<launch>
<node pkg="controller_manager"
type="spawner"
args="controller_name1 controller_name2" />
</launch>
或者你只想加载controller但是不启动的话
<launch>
<node pkg="controller_manager"
type="spawner"
args="--stopped controller_name1 controller_name2" />
</launch>
3 Graphical tools
rqt_controller_manager是rqt的一个插件,允许图形化的方式加载,卸载,启动,停止controller, 并显示加载的controller信息。
从rqt的plugin menu或者如下命令行都可以运行,rosrun rqt_controller_manager rqt_controller_manager
4 ROS API
如果要使用ROS node中与controller交互,可以使用controller_manager提供的5中service调用:
controller_manager/load_controller (controller_manager_msgs/LoadController)
- 该service请求应该含有要加载的controller名字,service响应以bool指示成功or失败。
- 该service请求应该含有要加卸载的controller名字,service响应以bool指示成功or失败。注意,仅有出于stopped状态的controller可以被卸载。
- 该service请求包含要启动的controller名字list,要停止的controller名字list,以及一个表明约束度 (BEST_EFFORT or STRICT)的int变量。 STRICT意思是只要有一个controller无效(如非法controller name,controller不能启动等),switch就会失败。 BEST_EFFORT意思是有些controller无效,但是仍然会启动/停止其它剩余controller。 service响应以bool指示成功or失败。
- 该service返回目前所有加载了的controller。响应信息包括: controller name, state (running or stopped), type, hardware interface and claimed resources。
- 该service返回所有controller_manager注册管理的controller类型。
该service重载所有controller插件库。当开发新controller时候,不用每次重启robot就可以测试新code,非常方便。这个service只有当没有controller被加载时候才能work。