33 : spinner_(1, callback_queue_.
get()),
34 callback_queue_(
boost::make_shared<
ros::CallbackQueue>()),
35 node_handle_(
ros::NodeHandle()),
36 node_handle_control_(node_handle_,
"control"),
37 control_duration_(node_handle_.
param<double>(
"control_duration", 0.01)),
38 init_success_(devices_.
init(node_handle_, node_handle_)),
39 controller_manager_(&devices_, node_handle_control_) {
78 if (result->error_code != result->SUCCESSFUL) {
79 ROS_WARN_STREAM_NAMED(
"robot_control",
"Controller [" << controller <<
"] action ended in state [" << state.
toString() <<
"] with error code [" << result->error_code <<
"]");
94 for (
int i=0; i<feedback->joint_names.size(); i++) {
95 ROS_DEBUG_STREAM_NAMED(
"robot_control",
"Controller [" << controller <<
"] joint [" << feedback->joint_names.at(i) <<
"] state is [" << feedback->actual.positions.at(i) <<
"] (expecting [" << feedback->desired.positions.at(i) <<
"]).");
124 if (std::regex_search(controller, match, std::regex(
"^" + device_name))) {
128 ROS_ERROR_STREAM(
"Controller [" << controller <<
"] has no associated device hardware interface.");
147 std::vector<trajectory_msgs::JointTrajectoryPoint> points;
148 double delta_period = period/samples_per_period;
149 double omega = 2*M_PI/period;
151 for (
int i=0; i<samples_per_period*periods; i++) {
152 trajectory_msgs::JointTrajectoryPoint point;
153 double point_time = (i+1)*delta_period;
155 point.positions.push_back(amplitude * std::sin(omega*point_time));
156 point.velocities.push_back(amplitude*omega * std::cos(omega*point_time));
157 point.accelerations.push_back(-amplitude*std::pow(omega,2) * std::sin(omega*point_time));
160 points.push_back(point);
167 std::vector<trajectory_msgs::JointTrajectoryPoint> points;
168 std::vector<double> semi_amplitudes({amplitude, amplitude, -amplitude, -amplitude});
169 std::vector<double> semi_periods({ramp_duration, period/2, period/2+ramp_duration, period});
171 for (
int i=0; i<semi_periods.size()*periods; i++) {
172 trajectory_msgs::JointTrajectoryPoint point;
173 double point_time = i*period + semi_periods.at(i%semi_periods.size());
175 point.positions.push_back(semi_amplitudes.at(i%semi_amplitudes.size()));
176 point.velocities.push_back(0);
177 point.accelerations.push_back(0);
180 points.push_back(point);
189 return trajectory_msgs::JointTrajectory();
191 auto min_max_sizes(std::minmax_element(joint_points.begin(), joint_points.end(), [](
auto pl,
auto pr){
return pl.size() < pr.size(); }));
192 if (min_max_sizes.first != min_max_sizes.second) {
194 return trajectory_msgs::JointTrajectory();
197 trajectory_msgs::JointTrajectory joint_trajectory;
198 for (
int i=0; i<joint_points.front().size(); i++) {
199 trajectory_msgs::JointTrajectoryPoint point;
200 for (
int j=0; j<joint_points.size(); j++) {
201 point.positions.push_back(joint_points.at(j).at(i).positions.front());
202 point.velocities.push_back(joint_points.at(j).at(i).velocities.front());
203 point.accelerations.push_back(joint_points.at(j).at(i).accelerations.front());
205 point.time_from_start = joint_points.front().at(i).time_from_start;
206 joint_trajectory.points.push_back(point);
210 joint_trajectory.header.stamp =
ros::Time(0);
211 return joint_trajectory;
216 if (!node_handle.
getParam(
"waypoints", waypoints)) {
218 return trajectory_msgs::JointTrajectory();
221 trajectory_msgs::JointTrajectory joint_trajectory;
222 for (
int i=0; i<waypoints.
size(); i++) {
223 trajectory_msgs::JointTrajectoryPoint point;
226 if (!waypoints[i].hasMember(
"time")) {
231 if (!waypoints[i].hasMember(
"joint_positions") || !waypoints[i][
"joint_positions"].
hasMember(device_name) || !
parseVector(waypoints[i][
"joint_positions"][device_name], controller, point.positions)) {
236 if (!waypoints[i].hasMember(
"joint_velocities") || !waypoints[i][
"joint_velocities"].
hasMember(device_name) || !
parseVector(waypoints[i][
"joint_velocities"][device_name], controller, point.velocities)) {
237 point.velocities = std::vector<double>(
controller_joints_.at(controller).size(), 0.0);
239 if (!waypoints[i].hasMember(
"joint_accelerations") || !waypoints[i][
"joint_accelerations"].hasMember(device_name) || !
parseVector(waypoints[i][
"joint_accelerations"][device_name], controller, point.accelerations)) {
240 point.accelerations = std::vector<double>(
controller_joints_.at(controller).size(), 0.0);
244 for (
int j=0; j<waypoints[i][
"time"].
size(); j++) {
245 point.time_from_start =
ros::Duration(xmlCast<double>(waypoints[i][
"time"][j]));
246 joint_trajectory.points.push_back(point);
249 if (!joint_trajectory.points.empty()) {
251 joint_trajectory.header.stamp =
ros::Time(0);
254 return joint_trajectory;
263 for (
auto const &
param : parameters) {
264 std::string controller(
param.first);
265 std::vector<std::string> controller_joints;
267 std::string controller_action(controller +
"/follow_joint_trajectory");
282 void qbDeviceControl::move(
const trajectory_msgs::JointTrajectory &joint_trajectory,
const std::string &controller) {
283 control_msgs::FollowJointTrajectoryAction control_action;
284 control_action.action_goal.goal.trajectory = joint_trajectory;
285 control_action.action_goal.header.stamp =
ros::Time(0);
286 action_clients_.at(controller)->sendGoal(control_action.action_goal.goal,
297 for (
int j=0; j<xml_value.
size(); j++) {
298 vector.push_back(xmlCast<double>(xml_value[j]));
307 if (!trajectory.points.empty()) {
352 return static_cast<bool>(xml_value);
355 return static_cast<double>(xml_value);
358 return static_cast<int>(xml_value);
ros::ServiceServer set_async_commands_server_
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val)
#define ROS_DEBUG_STREAM_NAMED(name, args)
void publish(const boost::shared_ptr< M > &message) const
#define ROS_ERROR_STREAM_NAMED(name, args)
ros::ServiceClient set_pid_client_
bool getAsyncMeasurementsCallback(qb_device_srvs::GetMeasurementsRequest &request, qb_device_srvs::GetMeasurementsResponse &response)
Make a call to the same type of service provided by the Communication Handler.
trajectory_msgs::JointTrajectory getCustomTrajectory(const std::vector< std::vector< trajectory_msgs::JointTrajectoryPoint >> &joint_points, const std::string &controller)
Build a joint trajectory for the given controller using the given points, which must match the contro...
bool setAsyncCommandsCallback(qb_device_srvs::SetCommandsRequest &request, qb_device_srvs::SetCommandsResponse &response)
Make a call to the same type of service provided by the Communication Handler.
void init(const M_string &remappings)
bool waitForResult(const ros::Duration &timeout, const std::string &controller)
Wait until the action is completed or the given timeout is reached.
ros::WallTimer frequency_timer_
bool call(MReq &req, MRes &res)
void initActionClients()
Retrieve all the controllers which have their parameters set in the Parameter Server and initialize t...
std::vector< trajectory_msgs::JointTrajectoryPoint > getTrapezoidalPoints(const double &litude, const double &period, const double &ramp_duration, const int &periods)
Build a single-joint trapezoidal wave point trajectory from the given parameters. ...
std::map< std::string, std::string > controller_device_name_
std::map< std::string, trajectory_msgs::JointTrajectory > joint_trajectories_
std::map< std::string, std::unique_ptr< actionlib::SimpleActionClient< control_msgs::FollowJointTrajectoryAction > > > action_clients_
ros::Publisher frequency_publisher_
ros::ServiceServer get_async_measurements_server_
#define ROS_INFO_STREAM_NAMED(name, args)
std::vector< std::string > controllers_
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
T xmlCast(XmlRpc::XmlRpcValue xml_value)
Cast an XmlRpcValue from TypeDouble, TypeInt or TypeBoolean to the specified template type...
Type const & getType() const
bool parseVector(const XmlRpc::XmlRpcValue &xml_value, const std::string &controller, std::vector< double > &vector)
Parse the given XmlRpcValue as a std::vector, since the XmlRpc::XmlRpcValue class does not handle thi...
void update(const ros::WallTime &time, const ros::WallDuration &period)
Read the current state from the HW, update all active controllers, and send the new references to the...
std::string extractDeviceName(const std::string &controller)
Extract the device names associated to the given controller (each controller name is assumed to start...
std::string toString() const
void controlSetupCallback(const ros::WallTimerEvent &timer_event)
Initialize the control timer and automatically start the waypoint trajectory if it is not empty...
void actionDoneCallback(const actionlib::SimpleClientGoalState &state, const control_msgs::FollowJointTrajectoryResultConstPtr &result, const std::string &controller)
Restart the waypoint trajectory automatically if waypoints have been retrieved during the initializat...
ROSCPP_DECL bool get(const std::string &key, std::string &s)
ros::WallDuration control_duration_
void controlCallback(const ros::WallTimerEvent &timer_event)
Call the update() each time the timer triggers.
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void setCallbackQueue(CallbackQueueInterface *queue)
std::vector< trajectory_msgs::JointTrajectoryPoint > getSinusoidalPoints(const double &litude, const double &period, const int &samples_per_period, const int &periods)
Build a single-joint sine wave point trajectory from the given parameters.
virtual void read(const ros::Time &time, const ros::Duration &period)
std::map< std::string, std::vector< std::string > > controller_joints_
qbDeviceControl()
Initialize the control structures needed by ros_control: the combined_robot_hw::CombinedRobotHW to co...
const std::string & getNamespace() const
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
ros::ServiceServer set_async_pid_server_
ros::ServiceClient get_measurements_client_
ros::WallTimer control_setup_timer_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::CallbackQueuePtr callback_queue_
ros::ServiceClient set_commands_client_
bool setAsyncPIDCallback(qb_device_srvs::SetPIDRequest &request, qb_device_srvs::SetPIDResponse &response)
Make a call to the same type of service provided by the Communication Handler.
bool hasMember(const std::string &name) const
void move()
Make all the calls to the Action Servers relative to all the waypoint trajectories previously parsed...
ros::WallTimer control_timer_
ros::NodeHandle node_handle_control_
std::mutex sync_protector_
bool getParam(const std::string &key, std::string &s) const
void frequencyCallback(const ros::WallTimerEvent &timer_event)
Publish the real control loop frequency in Hz in the relative topic.
void actionFeedbackCallback(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &feedback, const std::string &controller)
Do nothing apart from debug info.
void parseWaypoints()
Parse all the waypoints set up in the Parameter Server at <robot_namespace>/waypoints.
virtual void write(const ros::Time &time, const ros::Duration &period)
ros::AsyncSpinner spinner_
bool hasParam(const std::string &key) const
#define ROS_ERROR_STREAM(args)
void update(const ros::Time &time, const ros::Duration &period, bool reset_controllers=false)
virtual ~qbDeviceControl()
Stop timer and spinner structures.
void actionActiveCallback(const std::string &controller)
Do nothing apart from debug info.
std::vector< std::string > device_names_
controller_manager::ControllerManager controller_manager_
ros::NodeHandle node_handle_
#define ROS_WARN_STREAM_NAMED(name, args)
trajectory_msgs::JointTrajectory getWaypointTrajectory(ros::NodeHandle &node_handle, const std::string &controller)
Retrieve a set of reference waypoints from the Parameter Server.
combined_robot_hw::CombinedRobotHW devices_