00001
00060 #include "ros/ros.h"
00061 #include <urdf/model.h>
00062 #include "std_msgs/String.h"
00063 #include "sensor_msgs/JointState.h"
00064 #include "control_msgs/JointTrajectoryControllerState.h"
00065 #include "brics_actuator/JointVelocities.h"
00066 #include "cob_srvs/Trigger.h"
00067 #include "cob_srvs/SetOperationMode.h"
00068 #include <diagnostic_msgs/DiagnosticArray.h>
00069 #include <iostream>
00070 #include <map>
00071 #include <boost/bind.hpp>
00072 #include <boost/filesystem.hpp>
00073 #include <ipa_canopen_core/canopen.h>
00074 #include <XmlRpcValue.h>
00075 #include <ipa_canopen_ros/JointLimits.h>
00076
00077 typedef boost::function<bool(cob_srvs::Trigger::Request&, cob_srvs::Trigger::Response&)> TriggerType;
00078 typedef boost::function<void(const brics_actuator::JointVelocities&)> JointVelocitiesType;
00079 typedef boost::function<bool(cob_srvs::SetOperationMode::Request&, cob_srvs::SetOperationMode::Response&)> SetOperationModeCallbackType;
00080
00081 struct BusParams
00082 {
00083 std::string baudrate;
00084 uint32_t syncInterval;
00085 };
00086
00087 std::map<std::string, BusParams> buses;
00088
00089 std::string deviceFile;
00090
00091 JointLimits* joint_limits_;
00092 std::vector<std::string> chainNames;
00093 std::vector<std::string> jointNames;
00094
00095 bool CANopenInit(cob_srvs::Trigger::Request &req, cob_srvs::Trigger::Response &res, std::string chainName)
00096 {
00097 bool all_initialized = true;
00098
00099 for (auto device : canopen::devices)
00100 {
00101 if (not device.second.getInitialized())
00102 {
00103 all_initialized = false;
00104 }
00105 }
00106
00107 if(all_initialized)
00108 {
00109 res.success.data = true;
00110 res.error_message.data = "already initialized";
00111 ROS_INFO("already initialized");
00112 return true;
00113 }
00114
00115 bool init_success = canopen::init(deviceFile, canopen::syncInterval);
00116 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00117
00118
00119 for (auto device : canopen::devices)
00120 {
00121 if(init_success)
00122 {
00123 res.success.data = true;
00124 res.error_message.data = "Sucessfuly initialized";
00125 ROS_INFO("The device was sucessfuly initialized");
00126
00127 }
00128 else
00129 {
00130 res.success.data = false;
00131 res.error_message.data = "Module could not be initialized";
00132 ROS_WARN("Module could not be initialized. Check for possible errors and try to initialize it again.");
00133 }
00134
00135
00136 return true;
00137
00138 }
00139 }
00140
00141
00142 bool CANopenRecover(cob_srvs::Trigger::Request &req, cob_srvs::Trigger::Response &res, std::string chainName)
00143 {
00144
00145 for (auto device : canopen::devices)
00146 {
00147 if (not device.second.getInitialized())
00148 {
00149 res.success.data = false;
00150 res.error_message.data = "not initialized yet";
00151 ROS_INFO("not initialized yet");
00152 return true;
00153 }
00154 }
00155
00156 bool recover_success = canopen::recover(deviceFile, canopen::syncInterval);
00157 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00158
00159
00160 for (auto device : canopen::devices)
00161 {
00162
00163 if(recover_success)
00164 {
00165
00166 res.success.data = true;
00167 res.error_message.data = "Sucessfuly recovered";
00168 ROS_INFO("The device was sucessfuly recovered");
00169 return true;
00170 }
00171 else
00172 {
00173 res.success.data = false;
00174 res.error_message.data = "Module could not be recovered";
00175 ROS_WARN("Module could not be recovered. Check for possible errors and try to recover it again.");
00176 return true;
00177 }
00178
00179 }
00180
00181 }
00182
00183
00184 bool CANOpenHalt(cob_srvs::Trigger::Request &req, cob_srvs::Trigger::Response &res, std::string chainName)
00185 {
00186
00187
00188
00189 canopen::halt(deviceFile, canopen::syncInterval);
00190 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00191
00192 res.success.data = true;
00193 res.error_message.data = "";
00194 return true;
00195 }
00196
00197
00198 bool setOperationModeCallback(cob_srvs::SetOperationMode::Request &req, cob_srvs::SetOperationMode::Response &res, std::string chainName)
00199 {
00200 res.success.data = true;
00201 return true;
00202 }
00203
00204 void setVel(const brics_actuator::JointVelocities &msg, std::string chainName)
00205 {
00206 if (!canopen::atFirstInit & !canopen::recover_active)
00207 {
00208 std::vector<double> velocities;
00209 std::vector<double> positions;
00210
00211
00212 for (auto it : msg.velocities)
00213 {
00214 velocities.push_back( it.value);
00215 }
00216
00217 int counter = 0;
00218
00219 for (auto device : canopen::devices)
00220 {
00221
00222 double pos = (double)device.second.getDesiredPos();
00223 positions.push_back(pos);
00224 counter++;
00225 }
00226
00227 joint_limits_->checkVelocityLimits(velocities);
00228 joint_limits_->checkPositionLimits(positions, velocities);
00229
00230 canopen::deviceGroups[chainName].setVel(velocities);
00231 }
00232 }
00233
00234 void readParamsFromParameterServer(ros::NodeHandle n)
00235 {
00236 std::string param;
00237
00238 param = "devices";
00239 XmlRpc::XmlRpcValue busParams;
00240 if (n.hasParam(param))
00241 {
00242 n.getParam(param, busParams);
00243 }
00244 else
00245 {
00246 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00247 n.shutdown();
00248 }
00249
00250
00251 for (int i=0; i<busParams.size(); i++)
00252 {
00253 BusParams busParam;
00254 auto name = static_cast<std::string>(busParams[i]["name"]);
00255 busParam.baudrate = static_cast<std::string>(busParams[i]["baudrate"]);
00256 canopen::baudRate = busParam.baudrate;
00257 busParam.syncInterval = static_cast<int>(busParams[i]["sync_interval"]);
00258 buses[name] = busParam;
00259 }
00260
00261
00262 param = "chains";
00263 XmlRpc::XmlRpcValue chainNames_XMLRPC;
00264 if (n.hasParam(param))
00265 {
00266 n.getParam(param, chainNames_XMLRPC);
00267 }
00268 else
00269 {
00270 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00271 n.shutdown();
00272 }
00273
00274
00275 for (int i=0; i<chainNames_XMLRPC.size(); i++)
00276 chainNames.push_back(static_cast<std::string>(chainNames_XMLRPC[i]));
00277
00278 for (auto chainName : chainNames) {
00279 param = "/" + chainName + "/joint_names";
00280 XmlRpc::XmlRpcValue jointNames_XMLRPC;
00281 if (n.hasParam(param))
00282 {
00283 n.getParam(param, jointNames_XMLRPC);
00284 }
00285 else
00286 {
00287 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00288 n.shutdown();
00289 }
00290
00291
00292 for (int i=0; i<jointNames_XMLRPC.size(); i++)
00293 jointNames.push_back(static_cast<std::string>(jointNames_XMLRPC[i]));
00294
00295 param = "/" + chainName + "/module_ids";
00296 XmlRpc::XmlRpcValue moduleIDs_XMLRPC;
00297 if (n.hasParam(param))
00298 {
00299 n.getParam(param, moduleIDs_XMLRPC);
00300 }
00301 else
00302 {
00303 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00304 n.shutdown();
00305 }
00306
00307
00308 std::vector<uint8_t> moduleIDs;
00309 for (int i=0; i<moduleIDs_XMLRPC.size(); i++)
00310 moduleIDs.push_back(static_cast<int>(moduleIDs_XMLRPC[i]));
00311
00312 param = "/" + chainName + "/devices";
00313 XmlRpc::XmlRpcValue devices_XMLRPC;
00314 if (n.hasParam(param))
00315 {
00316 n.getParam(param, devices_XMLRPC);
00317 }
00318 else
00319 {
00320 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00321 n.shutdown();
00322 }
00323
00324
00325 std::vector<std::string> devices;
00326 for (int i=0; i<devices_XMLRPC.size(); i++)
00327 devices.push_back(static_cast<std::string>(devices_XMLRPC[i]));
00328
00329 for (unsigned int i=0; i<jointNames.size(); i++)
00330 {
00331 canopen::devices[ moduleIDs[i] ] = canopen::Device(moduleIDs[i], jointNames[i], chainName, devices[i]);
00332 }
00333
00334 canopen::deviceGroups[ chainName ] = canopen::DeviceGroup(moduleIDs, jointNames);
00335
00336 }
00337
00338 }
00339
00340 void setJointConstraints(ros::NodeHandle n)
00341 {
00342
00343
00344
00345
00346
00347
00349 joint_limits_ = new JointLimits();
00350 int DOF = jointNames.size();
00351
00352 std::string param_name = "/robot_description";
00353 std::string full_param_name;
00354 std::string xml_string;
00355
00356 n.searchParam(param_name, full_param_name);
00357 if (n.hasParam(full_param_name))
00358 {
00359 n.getParam(full_param_name.c_str(), xml_string);
00360 }
00361
00362 else
00363 {
00364 ROS_ERROR("Parameter %s not set, shutting down node...", full_param_name.c_str());
00365 n.shutdown();
00366 }
00367
00368 if (xml_string.size() == 0)
00369 {
00370 ROS_ERROR("Unable to load robot model from parameter %s",full_param_name.c_str());
00371 n.shutdown();
00372 }
00373
00374
00376 urdf::Model model;
00377
00378 if (!model.initString(xml_string))
00379 {
00380 ROS_ERROR("Failed to parse urdf file");
00381 n.shutdown();
00382 }
00383 ROS_INFO("Successfully parsed urdf file");
00384
00386 std::vector<double> MaxVelocities(DOF);
00387 std::vector<double> LowerLimits(DOF);
00388 std::vector<double> UpperLimits(DOF);
00389 std::vector<double> Offsets(DOF);
00390
00391 for (int i = 0; i < DOF; i++)
00392 {
00393 if(!model.getJoint(jointNames[i].c_str())->limits)
00394 {
00395 ROS_ERROR("Parameter limits could not be found in the URDF contents.");
00396 n.shutdown();
00397 exit(1);
00398 }
00399 else if(!model.getJoint(jointNames[i].c_str())->limits->velocity)
00400 {
00401 ROS_ERROR("Limits has no velocity attribute");
00402 n.shutdown();
00403 exit(1);
00404 }
00405 if(!model.getJoint(jointNames[i].c_str())->limits->lower)
00406 {
00407 ROS_ERROR("Limits has no lower attribute");
00408 n.shutdown();
00409 exit(1);
00410 }
00411 else if(!model.getJoint(jointNames[i].c_str())->limits->upper)
00412 {
00413 ROS_ERROR("Limits has no upper attribute");
00414 n.shutdown();
00415 exit(1);
00416 }
00417
00418 MaxVelocities[i] = model.getJoint(jointNames[i].c_str())->limits->velocity;
00419
00421 LowerLimits[i] = model.getJoint(jointNames[i].c_str())->limits->lower;
00422
00423
00424 UpperLimits[i] = model.getJoint(jointNames[i].c_str())->limits->upper;
00425
00427 if(!model.getJoint(jointNames[i].c_str())->calibration)
00428 {
00429 ROS_ERROR("Parameter calibration could not be found in the URDF contents.");
00430 n.shutdown();
00431 exit(1);
00432 }
00433 else if(!model.getJoint(jointNames[i].c_str())->calibration->rising)
00434 {
00435 ROS_ERROR("Calibration has no rising attribute");
00436 n.shutdown();
00437 exit(1);
00438 }
00439 Offsets[i] = model.getJoint(jointNames[i].c_str())->calibration->rising.get()[0];
00440 }
00441
00443
00444 joint_limits_->setDOF(DOF);
00445 joint_limits_->setUpperLimits(UpperLimits);
00446 joint_limits_->setLowerLimits(LowerLimits);
00447 joint_limits_->setMaxVelocities(MaxVelocities);
00448 joint_limits_->setOffsets(Offsets);
00449
00450
00451
00452
00453
00454 }
00455
00456
00457 int main(int argc, char **argv)
00458 {
00459
00460
00461
00462 ros::init(argc, argv, "canopen_ros");
00463 ros::NodeHandle n("");
00464
00465 readParamsFromParameterServer(n);
00466
00467 std::cout << "Sync Interval" << buses.begin()->second.syncInterval << std::endl;
00468 canopen::syncInterval = std::chrono::milliseconds( buses.begin()->second.syncInterval );
00469
00470 deviceFile = buses.begin()->first;
00471
00472
00473
00474
00475
00476
00477 canopen::sendPos = canopen::defaultPDOOutgoing_interpolated;
00478 for (auto it : canopen::devices) {
00479 canopen::incomingPDOHandlers[ 0x180 + it.first ] = [it](const TPCANRdMsg mS) { canopen::defaultPDO_incoming_status( it.first, mS ); };
00480 canopen::incomingPDOHandlers[ 0x480 + it.first ] = [it](const TPCANRdMsg mP) { canopen::defaultPDO_incoming_pos( it.first, mP ); };
00481 canopen::incomingEMCYHandlers[ 0x081 + it.first ] = [it](const TPCANRdMsg mE) { canopen::defaultEMCY_incoming( it.first, mE ); };
00482 }
00483
00484
00485 std::vector<TriggerType> initCallbacks;
00486 std::vector<ros::ServiceServer> initServices;
00487 std::vector<TriggerType> recoverCallbacks;
00488 std::vector<ros::ServiceServer> recoverServices;
00489 std::vector<TriggerType> stopCallbacks;
00490 std::vector<ros::ServiceServer> stopServices;
00491 std::vector<SetOperationModeCallbackType> setOperationModeCallbacks;
00492 std::vector<ros::ServiceServer> setOperationModeServices;
00493
00494 std::vector<JointVelocitiesType> jointVelocitiesCallbacks;
00495 std::vector<ros::Subscriber> jointVelocitiesSubscribers;
00496 std::map<std::string, ros::Publisher> currentOperationModePublishers;
00497 std::map<std::string, ros::Publisher> statePublishers;
00498 ros::Publisher jointStatesPublisher = n.advertise<sensor_msgs::JointState>("/joint_states", 1);
00499 ros::Publisher diagnosticsPublisher = n.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 1);
00500
00501 for (auto it : canopen::deviceGroups)
00502 {
00503 ROS_INFO("Configuring %s", it.first.c_str());
00504
00505 initCallbacks.push_back( boost::bind(CANopenInit, _1, _2, it.first) );
00506 initServices.push_back( n.advertiseService("/" + it.first + "/init", initCallbacks.back()) );
00507 recoverCallbacks.push_back( boost::bind(CANopenRecover, _1, _2, it.first) );
00508 recoverServices.push_back( n.advertiseService("/" + it.first + "/recover", recoverCallbacks.back()) );
00509 stopCallbacks.push_back( boost::bind(CANOpenHalt, _1, _2, it.first) );
00510 stopServices.push_back( n.advertiseService("/" + it.first + "/halt", stopCallbacks.back()) );
00511 setOperationModeCallbacks.push_back( boost::bind(setOperationModeCallback, _1, _2, it.first) );
00512 setOperationModeServices.push_back( n.advertiseService("/" + it.first + "/set_operation_mode", setOperationModeCallbacks.back()) );
00513
00514 jointVelocitiesCallbacks.push_back( boost::bind(setVel, _1, it.first) );
00515 jointVelocitiesSubscribers.push_back( n.subscribe<brics_actuator::JointVelocities>("/" + it.first + "/command_vel", 1, jointVelocitiesCallbacks.back()) );
00516
00517 currentOperationModePublishers[it.first] = n.advertise<std_msgs::String>("/" + it.first + "/current_operationmode", 1);
00518
00519 statePublishers[it.first] = n.advertise<control_msgs::JointTrajectoryControllerState>("/" + it.first + "/state", 1);
00520 }
00521
00522 double lr = 1000.0 / std::chrono::duration_cast<std::chrono::milliseconds>(canopen::syncInterval).count();
00523
00524 ros::Rate loop_rate(lr);
00525
00526 setJointConstraints(n);
00527
00528 while (ros::ok())
00529 {
00530
00531
00532 int counter = 0;
00533 std::vector <double> positions;
00534 std::vector <double> desired_positions;
00535
00536 for (auto device : canopen::devices)
00537 {
00538
00539 double pos = (double)device.second.getActualPos() + joint_limits_->getOffsets()[counter];
00540 double des_pos = (double)device.second.getDesiredPos() + joint_limits_->getOffsets()[counter];
00541 positions.push_back(pos);
00542 desired_positions.push_back(des_pos);
00543 counter++;
00544 }
00545
00546 for (auto dg : (canopen::deviceGroups))
00547 {
00548 sensor_msgs::JointState js;
00549 js.name = dg.second.getNames();
00550 js.header.stamp = ros::Time::now();
00551
00552 js.position = positions;
00553
00554 js.velocity = dg.second.getActualVel();
00555 js.effort = std::vector<double>(dg.second.getNames().size(), 0.0);
00556 jointStatesPublisher.publish(js);
00557
00558 control_msgs::JointTrajectoryControllerState jtcs;
00559 jtcs.header.stamp = js.header.stamp;
00560 jtcs.actual.positions = js.position;
00561 jtcs.actual.velocities = js.velocity;
00562 jtcs.desired.positions = desired_positions;
00563 jtcs.desired.velocities = dg.second.getDesiredVel();
00564 statePublishers[dg.first].publish(jtcs);
00565
00566 std_msgs::String opmode;
00567 opmode.data = "velocity";
00568 currentOperationModePublishers[dg.first].publish(opmode);
00569 counter++;
00570 }
00571
00572
00573 diagnostic_msgs::DiagnosticArray diagnostics;
00574 diagnostic_msgs::DiagnosticStatus diagstatus;
00575 std::vector<diagnostic_msgs::DiagnosticStatus> diagstatus_msg;
00576
00577 diagnostic_msgs::KeyValue keyval;
00578 std::vector<diagnostic_msgs::KeyValue> keyvalues;
00579
00580
00581
00582 diagnostics.status.resize(1);
00583
00584 for (auto dg : (canopen::devices))
00585 {
00586 std::string name = dg.second.getName();
00587
00588
00589 keyval.key = "Node ID";
00590 uint16_t node_id = dg.second.getCANid();
00591 std::stringstream result;
00592 result << node_id;
00593 keyval.value = result.str().c_str();
00594 keyvalues.push_back(keyval);
00595
00596 keyval.key = "Device Name";
00597 std::vector<char> dev_name = dg.second.getManufacturerDevName();
00598 keyval.value = std::string(dev_name.begin(), dev_name.end());
00599 keyvalues.push_back(keyval);
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 bool error_ = dg.second.getFault();
00640 bool initialized_ = dg.second.getInitialized();
00641
00642 if(initialized_)
00643 {
00644 keyval.key = "Current mode of operation";
00645 int8_t mode_display = dg.second.getCurrentModeofOperation();
00646 keyval.value = canopen::modesDisplay[mode_display];
00647 keyvalues.push_back(keyval);
00648
00649 keyval.key = "Errors Register";
00650 keyval.value = dg.second.getErrorRegister();
00651 keyvalues.push_back(keyval);
00652
00653 keyval.key = "Current driver temperature";
00654 double driver_temperature = dg.second.getDriverTemperature();
00655 keyval.value = std::to_string(driver_temperature);
00656 keyvalues.push_back(keyval);
00657 }
00658
00659
00660
00661
00662
00663 if(error_)
00664 {
00665 diagstatus.level = 2;
00666 diagstatus.name = chainNames[0];
00667 diagstatus.message = "Fault occured.";
00668 diagstatus.values = keyvalues;
00669 break;
00670 }
00671 else
00672 {
00673 if (initialized_)
00674 {
00675 diagstatus.level = 0;
00676 diagstatus.name = chainNames[0];
00677 diagstatus.message = "canopen chain initialized and running";
00678 diagstatus.values = keyvalues;
00679 }
00680 else
00681 {
00682 diagstatus.level = 1;
00683 diagstatus.name = chainNames[0];
00684 diagstatus.message = "canopen chain not initialized";
00685 diagstatus.values = keyvalues;
00686 break;
00687 }
00688 }
00689 }
00690 diagstatus_msg.push_back(diagstatus);
00691
00692 diagnostics.status = diagstatus_msg;
00693 diagnostics.header.stamp = ros::Time::now();
00694 diagnosticsPublisher.publish(diagnostics);
00695
00696 ros::spinOnce();
00697 loop_rate.sleep();
00698 }
00699
00700 return 0;
00701 }
00702