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 std::vector<int> motor_direction;
00082
00083 std::map<std::string, JointLimits*> joint_limits;
00084
00085
00086 struct BusParams
00087 {
00088 std::string baudrate;
00089 uint32_t syncInterval;
00090 };
00091
00092
00093
00094 std::string deviceFile;
00095
00096 std::vector<std::string> chainNames;
00097
00098 bool CANopenInit(cob_srvs::Trigger::Request &req, cob_srvs::Trigger::Response &res, std::string chainName)
00099 {
00100 bool all_initialized = true;
00101
00102 ROS_INFO("Trying to initialize the chain: %s", chainName.c_str());
00103
00104 for (auto id : canopen::deviceGroups[chainName].getCANids())
00105 {
00106 if (not canopen::devices[id].getInitialized())
00107 {
00108 all_initialized = false;
00109 }
00110 }
00111
00112 if(all_initialized)
00113 {
00114 res.success.data = true;
00115 res.error_message.data = "This chain is already initialized";
00116 ROS_INFO("This chain is already initialized");
00117 return true;
00118 }
00119
00120 bool init_success = canopen::init(deviceFile, chainName, canopen::syncInterval);
00121 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00122
00123
00124
00125 if(init_success)
00126 {
00127 res.success.data = true;
00128 res.error_message.data = "Sucessfuly initialized";
00129 ROS_INFO("This chain was sucessfuly initialized");
00130
00131 }
00132 else
00133 {
00134 res.success.data = false;
00135 res.error_message.data = "Module could not be initialized";
00136 ROS_WARN("This chain could not be initialized. Check for possible errors and try to initialize it again.");
00137 }
00138
00139
00140 return true;
00141 }
00142
00143
00144 bool CANopenRecover(cob_srvs::Trigger::Request &req, cob_srvs::Trigger::Response &res, std::string chainName)
00145 {
00146
00147 ROS_INFO("Trying to recover the chain: %s", chainName.c_str());
00148
00149 for (auto id : canopen::deviceGroups[chainName].getCANids())
00150 {
00151 if (not canopen::devices[id].getInitialized())
00152 {
00153 res.success.data = false;
00154 res.error_message.data = "not initialized yet";
00155 ROS_INFO("not initialized yet");
00156 return true;
00157 }
00158 }
00159
00160 bool recover_success = canopen::recover(deviceFile,chainName, canopen::syncInterval);
00161 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00162
00163
00164
00165 if(recover_success)
00166 {
00167
00168 res.success.data = true;
00169 res.error_message.data = "Sucessfuly recovered";
00170 ROS_INFO("The device was sucessfuly recovered");
00171 return true;
00172 }
00173 else
00174 {
00175 res.success.data = false;
00176 res.error_message.data = "Module could not be recovered";
00177 ROS_WARN("Module could not be recovered. Check for possible errors and try to recover it again.");
00178 return true;
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, chainName, 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 int counter = 0;
00213
00214 for (auto it : msg.velocities)
00215 {
00216 velocities.push_back( it.value*motor_direction[counter]);
00217 counter++;
00218 }
00219
00220 counter = 0;
00221
00222 for (auto id : canopen::deviceGroups[chainName].getCANids())
00223 {
00224
00225 double pos = ((double)canopen::devices[id].getDesiredPos() + joint_limits[chainName]->getOffsets()[counter])*motor_direction[counter];
00226 positions.push_back(pos);
00227 counter++;
00228 }
00229
00230 joint_limits[chainName]->checkVelocityLimits(velocities);
00231 joint_limits[chainName]->checkPositionLimits(positions, velocities);
00232
00233 canopen::deviceGroups[chainName].setVel(velocities);
00234 }
00235 }
00236
00237 void readParamsFromParameterServer(ros::NodeHandle n)
00238 {
00239 std::string param;
00240
00241 BusParams busParam;
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 param = "device";
00266 XmlRpc::XmlRpcValue device;
00267 if (n.hasParam(param))
00268 {
00269 n.getParam(param, device);
00270 }
00271 else
00272 {
00273 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00274 n.shutdown();
00275 }
00276
00277
00278
00279 deviceFile = static_cast<std::string>(device);
00280
00281 param = "sync_interval";
00282 XmlRpc::XmlRpcValue interval;
00283 if (n.hasParam(param))
00284 {
00285 n.getParam(param, interval);
00286 }
00287 else
00288 {
00289 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00290 n.shutdown();
00291 }
00292
00293 canopen::syncInterval = std::chrono::milliseconds(static_cast<int>(interval));
00294
00295 param = "baudrate";
00296 XmlRpc::XmlRpcValue baudRate;
00297 if (n.hasParam(param))
00298 {
00299 n.getParam(param, baudRate);
00300 }
00301 else
00302 {
00303 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00304 n.shutdown();
00305 }
00306
00307
00308
00309 canopen::baudRate = static_cast<std::string>(baudRate);
00310 busParam.baudrate = canopen::baudRate;
00311
00312 param = "chains";
00313 XmlRpc::XmlRpcValue chainNames_XMLRPC;
00314 if (n.hasParam(param))
00315 {
00316 n.getParam(param, chainNames_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 for (int i=0; i<chainNames_XMLRPC.size(); i++)
00326 chainNames.push_back(static_cast<std::string>(chainNames_XMLRPC[i]));
00327
00328 for (auto chainName : chainNames)
00329 {
00330 std::vector<std::string> jointNames;
00331
00332 param = "/" + chainName + "/joint_names";
00333 XmlRpc::XmlRpcValue jointNames_XMLRPC;
00334 if (n.hasParam(param))
00335 {
00336 n.getParam(param, jointNames_XMLRPC);
00337 }
00338 else
00339 {
00340 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00341 n.shutdown();
00342 }
00343
00344
00345 for (int i=0; i<jointNames_XMLRPC.size(); i++)
00346 jointNames.push_back(static_cast<std::string>(jointNames_XMLRPC[i]));
00347
00348 int DOF = jointNames.size();
00349
00350 param = "/" + chainName + "/motor_direction";
00351 XmlRpc::XmlRpcValue motorDirections_XMLRPC;
00352 if (n.hasParam(param))
00353 {
00354 n.getParam(param, motorDirections_XMLRPC);
00355
00356 if( motorDirections_XMLRPC.size() != DOF)
00357 {
00358 ROS_ERROR("The size of the motor direction parameter is different from the size of the degrees of freedom. Shutting down node...");
00359 n.shutdown();
00360 exit(EXIT_FAILURE);
00361 }
00362
00363
00364 for (int i=0; i<motorDirections_XMLRPC.size(); i++)
00365 {
00366 int this_direction = static_cast<int>(motorDirections_XMLRPC[i]);
00367
00368 if(this_direction != 1 && this_direction != -1 )
00369 {
00370 ROS_ERROR("The value %d is not valid for the motor direction.Please use 1 or -1. Shutting down node...", this_direction);
00371 n.shutdown();
00372 exit(EXIT_FAILURE);
00373 }
00374
00375 motor_direction.push_back(this_direction);
00376 }
00377 }
00378 else
00379 {
00380 ROS_WARN("Parameter %s not set, using default [1]...", param.c_str());
00381 for (int i=0; i < DOF; i++)
00382 motor_direction.push_back(1);
00383 }
00384
00385
00386 param = "/" + chainName + "/module_ids";
00387 XmlRpc::XmlRpcValue moduleIDs_XMLRPC;
00388 if (n.hasParam(param))
00389 {
00390 n.getParam(param, moduleIDs_XMLRPC);
00391 }
00392 else
00393 {
00394 ROS_ERROR("Parameter %s not set, shutting down node...", param.c_str());
00395 n.shutdown();
00396 }
00397
00398 if( moduleIDs_XMLRPC.size() != DOF)
00399 {
00400 ROS_ERROR("The size of the ids parameter is different from the size of the degrees of freedom. Shutting down node...");
00401 n.shutdown();
00402 exit(EXIT_FAILURE);
00403 }
00404
00405
00406 std::vector<uint8_t> moduleIDs;
00407 for (int i=0; i<moduleIDs_XMLRPC.size(); i++)
00408 moduleIDs.push_back(static_cast<int>(moduleIDs_XMLRPC[i]));
00409
00410 for (unsigned int i=0; i<jointNames.size(); i++)
00411 canopen::devices[ moduleIDs[i] ] = canopen::Device(moduleIDs[i], jointNames[i], chainName);
00412
00413 canopen::deviceGroups[ chainName ] = canopen::DeviceGroup(moduleIDs, jointNames);
00414
00415 }
00416
00417 }
00418
00419 void setJointConstraints(ros::NodeHandle n)
00420 {
00421
00422
00423
00424
00425
00426
00427 for (auto chainName : chainNames)
00428 {
00429 joint_limits[chainName] = new JointLimits();
00431
00432 int DOF = canopen::deviceGroups[chainName].getNames().size();
00433
00434 std::string param_name = "/robot_description";
00435 std::string full_param_name;
00436 std::string xml_string;
00437
00438 n.searchParam(param_name, full_param_name);
00439 if (n.hasParam(full_param_name))
00440 {
00441 n.getParam(full_param_name.c_str(), xml_string);
00442 }
00443
00444 else
00445 {
00446 ROS_ERROR("Parameter %s not set, shutting down node...", full_param_name.c_str());
00447 n.shutdown();
00448 }
00449
00450 if (xml_string.size() == 0)
00451 {
00452 ROS_ERROR("Unable to load robot model from parameter %s",full_param_name.c_str());
00453 n.shutdown();
00454 }
00455 ROS_INFO("Robot model loaded succesfully");
00456
00457
00459 urdf::Model model;
00460
00461 if (!model.initString(xml_string))
00462 {
00463 ROS_ERROR("Failed to parse urdf file");
00464 n.shutdown();
00465 }
00466 ROS_INFO("Successfully parsed urdf file");
00467
00469 std::vector<double> MaxVelocities(DOF);
00470 std::vector<double> LowerLimits(DOF);
00471 std::vector<double> UpperLimits(DOF);
00472 std::vector<double> Offsets(DOF);
00473
00474 std::vector<std::string> jointNames = canopen::deviceGroups[chainName].getNames();
00475 for (int i = 0; i < DOF; i++)
00476 {
00477 if(!model.getJoint(jointNames[i].c_str()))
00478 {
00479 ROS_ERROR("Joint %s is not available",jointNames[i].c_str());
00480 n.shutdown();
00481 exit(1);
00482 }
00483 if(!model.getJoint(jointNames[i].c_str())->limits)
00484 {
00485 ROS_ERROR("Parameter limits could not be found in the URDF contents.");
00486 n.shutdown();
00487 exit(1);
00488 }
00489 else if(!model.getJoint(jointNames[i].c_str())->limits->velocity)
00490 {
00491 ROS_ERROR("Limits has no velocity attribute");
00492 n.shutdown();
00493 exit(1);
00494 }
00495 if(!model.getJoint(jointNames[i].c_str())->limits->lower)
00496 {
00497 ROS_ERROR("Limits has no lower attribute");
00498 n.shutdown();
00499 exit(1);
00500 }
00501 else if(!model.getJoint(jointNames[i].c_str())->limits->upper)
00502 {
00503 ROS_ERROR("Limits has no upper attribute");
00504 n.shutdown();
00505 exit(1);
00506 }
00507
00508 MaxVelocities[i] = model.getJoint(jointNames[i].c_str())->limits->velocity;
00509
00511 LowerLimits[i] = model.getJoint(jointNames[i].c_str())->limits->lower;
00512
00513
00514 UpperLimits[i] = model.getJoint(jointNames[i].c_str())->limits->upper;
00515
00517 if(!model.getJoint(jointNames[i].c_str())->calibration)
00518 {
00519 ROS_ERROR("Parameter calibration could not be found in the URDF contents.");
00520 n.shutdown();
00521 exit(1);
00522 }
00523 else if(!model.getJoint(jointNames[i].c_str())->calibration->rising)
00524 {
00525 ROS_ERROR("Calibration has no rising attribute");
00526 n.shutdown();
00527 exit(1);
00528 }
00529 Offsets[i] = model.getJoint(jointNames[i].c_str())->calibration->rising.get()[0];
00530 }
00531 ROS_INFO("Successfully got offsets and limits");
00532
00534
00535 joint_limits[chainName]->setDOF(DOF);
00536 joint_limits[chainName]->setUpperLimits(UpperLimits);
00537 joint_limits[chainName]->setLowerLimits(LowerLimits);
00538 joint_limits[chainName]->setMaxVelocities(MaxVelocities);
00539 joint_limits[chainName]->setOffsets(Offsets);
00540
00541
00542
00543
00544
00545 }
00546 }
00547
00548
00549 int main(int argc, char **argv)
00550 {
00551
00552
00553
00554 ros::init(argc, argv, "ipa_canopen_ros");
00555 ros::NodeHandle n("");
00556
00557 readParamsFromParameterServer(n);
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 canopen::sendPos = canopen::defaultPDOOutgoing_interpolated;
00570 for (auto it : canopen::devices) {
00571 canopen::incomingPDOHandlers[ 0x180 + it.first ] = [it](const TPCANRdMsg mS) { canopen::defaultPDO_incoming_status( it.first, mS ); };
00572 canopen::incomingPDOHandlers[ 0x480 + it.first ] = [it](const TPCANRdMsg mP) { canopen::defaultPDO_incoming_pos( it.first, mP ); };
00573 canopen::incomingEMCYHandlers[ 0x081 + it.first ] = [it](const TPCANRdMsg mE) { canopen::defaultEMCY_incoming( it.first, mE ); };
00574 }
00575
00576
00577 std::vector<TriggerType> initCallbacks;
00578 std::vector<ros::ServiceServer> initServices;
00579 std::vector<TriggerType> recoverCallbacks;
00580 std::vector<ros::ServiceServer> recoverServices;
00581 std::vector<TriggerType> stopCallbacks;
00582 std::vector<ros::ServiceServer> stopServices;
00583 std::vector<SetOperationModeCallbackType> setOperationModeCallbacks;
00584 std::vector<ros::ServiceServer> setOperationModeServices;
00585
00586 std::vector<JointVelocitiesType> jointVelocitiesCallbacks;
00587 std::vector<ros::Subscriber> jointVelocitiesSubscribers;
00588 std::map<std::string, ros::Publisher> currentOperationModePublishers;
00589 std::map<std::string, ros::Publisher> statePublishers;
00590 ros::Publisher jointStatesPublisher = n.advertise<sensor_msgs::JointState>("/joint_states", 1);
00591 ros::Publisher diagnosticsPublisher = n.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 1);
00592
00593 for (auto it : canopen::deviceGroups)
00594 {
00595 ROS_INFO("Configuring %s", it.first.c_str());
00596
00597 initCallbacks.push_back( boost::bind(CANopenInit, _1, _2, it.first) );
00598 initServices.push_back( n.advertiseService("/" + it.first + "/init", initCallbacks.back()) );
00599 recoverCallbacks.push_back( boost::bind(CANopenRecover, _1, _2, it.first) );
00600 recoverServices.push_back( n.advertiseService("/" + it.first + "/recover", recoverCallbacks.back()) );
00601 stopCallbacks.push_back( boost::bind(CANOpenHalt, _1, _2, it.first) );
00602 stopServices.push_back( n.advertiseService("/" + it.first + "/halt", stopCallbacks.back()) );
00603 setOperationModeCallbacks.push_back( boost::bind(setOperationModeCallback, _1, _2, it.first) );
00604 setOperationModeServices.push_back( n.advertiseService("/" + it.first + "/set_operation_mode", setOperationModeCallbacks.back()) );
00605
00606 jointVelocitiesCallbacks.push_back( boost::bind(setVel, _1, it.first) );
00607 jointVelocitiesSubscribers.push_back( n.subscribe<brics_actuator::JointVelocities>("/" + it.first + "/command_vel", 1, jointVelocitiesCallbacks.back()) );
00608
00609 currentOperationModePublishers[it.first] = n.advertise<std_msgs::String>("/" + it.first + "/current_operationmode", 1);
00610
00611 statePublishers[it.first] = n.advertise<control_msgs::JointTrajectoryControllerState>("/" + it.first + "/state", 1);
00612 }
00613
00614 double lr = 1000.0 / std::chrono::duration_cast<std::chrono::milliseconds>(canopen::syncInterval).count();
00615
00616 ros::Rate loop_rate(lr);
00617
00618 setJointConstraints(n);
00619
00620 while (ros::ok())
00621 {
00622
00623
00624
00625
00626 for (auto dg : (canopen::deviceGroups))
00627 {
00628
00629 int counter = 0;
00630 std::vector <double> positions;
00631 std::vector <double> desired_positions;
00632
00633 for (auto id : dg.second.getCANids())
00634 {
00635
00636 double pos = ((double)canopen::devices[id].getActualPos() + joint_limits[dg.first]->getOffsets()[counter])*motor_direction[counter];
00637 double des_pos = ((double)canopen::devices[id].getDesiredPos() + joint_limits[dg.first]->getOffsets()[counter])*motor_direction[counter];
00638 positions.push_back(pos);
00639 desired_positions.push_back(des_pos);
00640 counter++;
00641 }
00642
00643
00644 sensor_msgs::JointState js;
00645 js.name = dg.second.getNames();
00646 js.header.stamp = ros::Time::now();
00647
00648 js.position = positions;
00649
00650 js.velocity = dg.second.getActualVel();
00651 js.effort = std::vector<double>(dg.second.getNames().size(), 0.0);
00652 jointStatesPublisher.publish(js);
00653
00654 control_msgs::JointTrajectoryControllerState jtcs;
00655 jtcs.header.stamp = js.header.stamp;
00656 jtcs.actual.positions = js.position;
00657 jtcs.actual.velocities = js.velocity;
00658 jtcs.desired.positions = desired_positions;
00659 jtcs.desired.velocities = dg.second.getDesiredVel();
00660 statePublishers[dg.first].publish(jtcs);
00661
00662 std_msgs::String opmode;
00663 opmode.data = "velocity";
00664 currentOperationModePublishers[dg.first].publish(opmode);
00665 counter++;
00666 }
00667
00668
00669 diagnostic_msgs::DiagnosticArray diagnostics;
00670 diagnostic_msgs::DiagnosticStatus diagstatus;
00671 std::vector<diagnostic_msgs::DiagnosticStatus> diagstatus_msg;
00672
00673 diagnostic_msgs::KeyValue keyval;
00674 std::vector<diagnostic_msgs::KeyValue> keyvalues;
00675
00676
00677
00678 diagnostics.status.resize(1);
00679
00680 for (auto dg : (canopen::deviceGroups))
00681 {
00682 for (auto id : dg.second.getCANids())
00683 {
00684
00685 std::string name = canopen::devices[id].getName();
00686
00687
00688 keyval.key = "Node ID";
00689 uint16_t node_id = canopen::devices[id].getCANid();
00690 std::stringstream result;
00691 result << node_id;
00692 keyval.value = result.str().c_str();
00693 keyvalues.push_back(keyval);
00694
00695 keyval.key = "Device Name";
00696 keyval.value = name.c_str();
00697
00698
00699 keyvalues.push_back(keyval);
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739 bool error_ = canopen::devices[id].getFault();
00740 bool initialized_ = canopen::devices[id].getInitialized();
00741
00742 if(initialized_)
00743 {
00744 std::stringstream operation_string;
00745 operation_string << "Mode of operation for Node" << node_id;
00746 keyval.key = operation_string.str().c_str();
00747 int8_t mode_display = canopen::devices[id].getCurrentModeofOperation();
00748 keyval.value = canopen::modesDisplay[mode_display];
00749 keyvalues.push_back(keyval);
00750
00751 std::stringstream error_register_string;
00752 error_register_string << "Error Register from Node" << node_id;
00753 keyval.key = error_register_string.str().c_str();
00754 keyval.value = canopen::devices[id].getErrorRegister();
00755 keyvalues.push_back(keyval);
00756
00757 std::stringstream driver_temperature_string;
00758 driver_temperature_string << "Current Driver Temperature for Node" << node_id;
00759 keyval.key = driver_temperature_string.str().c_str();
00760 double driver_temperature = canopen::devices[id].getDriverTemperature();
00761 keyval.value = std::to_string(driver_temperature);
00762 keyvalues.push_back(keyval);
00763 }
00764
00765
00766
00767
00768 std::stringstream diag_string;
00769 diag_string << dg.first;
00770 diagstatus.name = diag_string.str().c_str();
00771
00772
00773 if(error_)
00774 {
00775 diagstatus.level = 2;
00776 diagstatus.message = "Fault occured.";
00777 diagstatus.values = keyvalues;
00778 break;
00779 }
00780 else
00781 {
00782 if (initialized_)
00783 {
00784 diagstatus.level = 0;
00785 diagstatus.message = "Device initialized and running";
00786 diagstatus.values = keyvalues;
00787 }
00788 else
00789 {
00790 diagstatus.level = 1;
00791 diagstatus.message = "Device not initialized";
00792 diagstatus.values = keyvalues;
00793 break;
00794 }
00795 }
00796 }
00797 }
00798 diagstatus_msg.push_back(diagstatus);
00799
00800 diagnostics.status = diagstatus_msg;
00801 diagnostics.header.stamp = ros::Time::now();
00802 diagnosticsPublisher.publish(diagnostics);
00803
00804 ros::spinOnce();
00805 loop_rate.sleep();
00806 }
00807
00808 return 0;
00809 }
00810