00001
00046 #include <ros/ros.h>
00047 #include "jaco_driver/jaco_comm.h"
00048 #include <string>
00049 #include <vector>
00050
00051
00052 namespace jaco
00053 {
00054
00055 JacoComm::JacoComm(const ros::NodeHandle& node_handle,
00056 boost::recursive_mutex &api_mutex,
00057 const bool is_movement_on_start)
00058 : is_software_stop_(false), api_mutex_(api_mutex)
00059 {
00060 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00061
00062
00063 std::string serial_number = "";
00064 node_handle.getParam("serial_number", serial_number);
00065
00066 std::vector<int> api_version;
00067 int result = jaco_api_.getAPIVersion(api_version);
00068 if (result != NO_ERROR_KINOVA)
00069 {
00070 throw JacoCommException("Could not get the Kinova API version", result);
00071 }
00072
00073 ROS_INFO_STREAM("Initializing Kinova API (header version: " << COMMAND_LAYER_VERSION << ", library version: "
00074 << api_version[0] << "." << api_version[1] << "." << api_version[2] << ")");
00075
00076 result = jaco_api_.initAPI();
00077 if (result != NO_ERROR_KINOVA)
00078 {
00079 throw JacoCommException("Could not initialize Kinova API", result);
00080 }
00081
00082 std::vector<KinovaDevice> devices_list;
00083 result = NO_ERROR_KINOVA;
00084 jaco_api_.getDevices(devices_list, result);
00085 if (result != NO_ERROR_KINOVA)
00086 {
00087 throw JacoCommException("Could not get devices list", result);
00088 }
00089
00090 bool found_arm = false;
00091 for (int device_i = 0; device_i < devices_list.size(); device_i++)
00092 {
00093
00094 if ((serial_number == "")
00095 || (std::strcmp(serial_number.c_str(), devices_list[device_i].SerialNumber) == 0))
00096 {
00097 result = jaco_api_.setActiveDevice(devices_list[device_i]);
00098 if (result != NO_ERROR_KINOVA)
00099 {
00100 throw JacoCommException("Could not set the active device", result);
00101 }
00102
00103 GeneralInformations general_info;
00104 result = jaco_api_.getGeneralInformations(general_info);
00105 if (result != NO_ERROR_KINOVA)
00106 {
00107 throw JacoCommException("Could not get general information about the device", result);
00108 }
00109
00110 ClientConfigurations configuration;
00111 getConfig(configuration);
00112
00113 QuickStatus quick_status;
00114 getQuickStatus(quick_status);
00115
00116 if ((quick_status.RobotType != 0) && (quick_status.RobotType != 1))
00117 {
00118 ROS_ERROR("Could not get the type of the arm from the quick status, expected "
00119 "either type 0 (JACO), or type 1 (MICO), got %d", quick_status.RobotType);
00120 throw JacoCommException("Could not get the type of the arm", quick_status.RobotType);
00121 }
00122
00123 num_fingers_ = quick_status.RobotType == 0 ? 3 : 2;
00124
00125 ROS_INFO_STREAM("Found " << devices_list.size() << " device(s), using device at index " << device_i
00126 << " (model: " << configuration.Model
00127 << ", serial number: " << devices_list[device_i].SerialNumber
00128 << ", code version: " << general_info.CodeVersion
00129 << ", code revision: " << general_info.CodeRevision << ")");
00130
00131 found_arm = true;
00132 break;
00133 }
00134 }
00135
00136 if (!found_arm)
00137 {
00138 ROS_ERROR("Could not find the specified arm (serial: %s) among the %d attached devices",
00139 serial_number.c_str(), static_cast<int>(devices_list.size()));
00140 throw JacoCommException("Could not find the specified arm", 0);
00141 }
00142
00143
00144
00145 startAPI();
00146 stopAPI();
00147 startAPI();
00148
00149
00150 TrajectoryPoint jaco_velocity;
00151 memset(&jaco_velocity, 0, sizeof(jaco_velocity));
00152 setCartesianVelocities(jaco_velocity.Position.CartesianPosition);
00153
00154 if (is_movement_on_start)
00155 {
00156 initFingers();
00157 }
00158 else
00159 {
00160 ROS_WARN("Movement on connection to the arm has been suppressed on initialization. You may "
00161 "have to home the arm (through the home service) before movement is possible");
00162 }
00163 }
00164
00165
00166 JacoComm::~JacoComm()
00167 {
00168 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00169 jaco_api_.closeAPI();
00170 }
00171
00172
00179 bool JacoComm::isHomed(void)
00180 {
00181 QuickStatus quick_status;
00182 getQuickStatus(quick_status);
00183
00184 if (quick_status.RetractType == 1)
00185 {
00186 return true;
00187 }
00188 else
00189 {
00190 return false;
00191 }
00192 }
00193
00194
00205 void JacoComm::homeArm(void)
00206 {
00207 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00208
00209 if (isStopped())
00210 {
00211 ROS_INFO("Arm is stopped, cannot home");
00212 return;
00213 }
00214 else if (isHomed())
00215 {
00216 ROS_INFO("Arm is already in \"home\" position");
00217 return;
00218 }
00219
00220 stopAPI();
00221 ros::Duration(1.0).sleep();
00222 startAPI();
00223
00224 ROS_INFO("Homing the arm");
00225 int result = jaco_api_.moveHome();
00226 if (result != NO_ERROR_KINOVA)
00227 {
00228 throw JacoCommException("Move home failed", result);
00229 }
00230 }
00231
00232
00239 void JacoComm::initFingers(void)
00240 {
00241 ROS_INFO("Initializing fingers...this will take a few seconds and the fingers should open completely");
00242 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00243 int result = jaco_api_.initFingers();
00244 if (result != NO_ERROR_KINOVA)
00245 {
00246 throw JacoCommException("Could not init fingers", result);
00247 }
00248 return;
00249 }
00250
00251
00257 void JacoComm::setJointAngles(const JacoAngles &angles, int timeout, bool push)
00258 {
00259 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00260
00261 if (isStopped())
00262 {
00263 ROS_INFO("The angles could not be set because the arm is stopped");
00264 return;
00265 }
00266
00267 int result = NO_ERROR_KINOVA;
00268 TrajectoryPoint jaco_position;
00269 jaco_position.InitStruct();
00270 memset(&jaco_position, 0, sizeof(jaco_position));
00271
00272 if (push)
00273 {
00274 result = jaco_api_.eraseAllTrajectories();
00275 if (result != NO_ERROR_KINOVA)
00276 {
00277 throw JacoCommException("Could not erase trajectories", result);
00278 }
00279 }
00280
00281 startAPI();
00282
00283 result = jaco_api_.setAngularControl();
00284 if (result != NO_ERROR_KINOVA)
00285 {
00286 throw JacoCommException("Could not set angular control", result);
00287 }
00288
00289 jaco_position.Position.Delay = 0.0;
00290 jaco_position.Position.Type = ANGULAR_POSITION;
00291 jaco_position.Position.Actuators = angles;
00292
00293 result = jaco_api_.sendAdvanceTrajectory(jaco_position);
00294 if (result != NO_ERROR_KINOVA)
00295 {
00296 throw JacoCommException("Could not send advanced joint angle trajectory", result);
00297 }
00298 }
00299
00300
00306 void JacoComm::setCartesianPosition(const JacoPose &position, int timeout, bool push)
00307 {
00308 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00309
00310 if (isStopped())
00311 {
00312 ROS_INFO("The position could not be set because the arm is stopped");
00313 return;
00314 }
00315
00316 int result = NO_ERROR_KINOVA;
00317 TrajectoryPoint jaco_position;
00318 jaco_position.InitStruct();
00319 memset(&jaco_position, 0, sizeof(jaco_position));
00320
00321 if (push)
00322 {
00323 result = jaco_api_.eraseAllTrajectories();
00324 if (result != NO_ERROR_KINOVA)
00325 {
00326 throw JacoCommException("Could not erase trajectories", result);
00327 }
00328 }
00329
00330 startAPI();
00331
00332 result = jaco_api_.setCartesianControl();
00333 if (result != NO_ERROR_KINOVA)
00334 {
00335 throw JacoCommException("Could not set Cartesian control", result);
00336 }
00337
00338 jaco_position.Position.Delay = 0.0;
00339 jaco_position.Position.Type = CARTESIAN_POSITION;
00340 jaco_position.Position.HandMode = HAND_NOMOVEMENT;
00341
00342
00343 jaco_position.Position.Actuators.Actuator1 = 0.0f;
00344 jaco_position.Position.Actuators.Actuator2 = 0.0f;
00345 jaco_position.Position.Actuators.Actuator3 = 0.0f;
00346 jaco_position.Position.Actuators.Actuator4 = 0.0f;
00347 jaco_position.Position.Actuators.Actuator5 = 0.0f;
00348 jaco_position.Position.Actuators.Actuator6 = 0.0f;
00349
00350 jaco_position.Position.CartesianPosition = position;
00351
00352 result = jaco_api_.sendBasicTrajectory(jaco_position);
00353 if (result != NO_ERROR_KINOVA)
00354 {
00355 throw JacoCommException("Could not send basic trajectory", result);
00356 }
00357 }
00358
00359
00363 void JacoComm::setFingerPositions(const FingerAngles &fingers, int timeout, bool push)
00364 {
00365 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00366
00367 if (isStopped())
00368 {
00369 ROS_INFO("The fingers could not be set because the arm is stopped");
00370 return;
00371 }
00372
00373 int result = NO_ERROR_KINOVA;
00374 TrajectoryPoint jaco_position;
00375 jaco_position.InitStruct();
00376 memset(&jaco_position, 0, sizeof(jaco_position));
00377
00378 if (push)
00379 {
00380 result = jaco_api_.eraseAllTrajectories();
00381 if (result != NO_ERROR_KINOVA)
00382 {
00383 throw JacoCommException("Could not erase trajectories", result);
00384 }
00385 }
00386
00387 startAPI();
00388
00389 result = jaco_api_.setCartesianControl();
00390 if (result != NO_ERROR_KINOVA)
00391 {
00392 throw JacoCommException("Could not set Cartesian control", result);
00393 }
00394
00395
00396 jaco_position.Position.HandMode = POSITION_MODE;
00397 jaco_position.Position.Type = CARTESIAN_POSITION;
00398 jaco_position.Position.Fingers = fingers;
00399 jaco_position.Position.Delay = 0.0;
00400 jaco_position.LimitationsActive = 0;
00401
00402
00403 JacoAngles angles;
00404 getJointAngles(angles);
00405 jaco_position.Position.Actuators = angles;
00406
00407
00408
00409 JacoPose pose;
00410 getCartesianPosition(pose);
00411 jaco_position.Position.CartesianPosition = pose;
00412
00413 result = jaco_api_.sendAdvanceTrajectory(jaco_position);
00414 if (result != NO_ERROR_KINOVA)
00415 {
00416 throw JacoCommException("Could not send advanced finger trajectory", result);
00417 }
00418 }
00419
00420
00424 void JacoComm::setJointVelocities(const AngularInfo &joint_vel)
00425 {
00426 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00427
00428 if (isStopped())
00429 {
00430 ROS_INFO("The velocities could not be set because the arm is stopped");
00431 return;
00432 }
00433
00434 TrajectoryPoint jaco_velocity;
00435 jaco_velocity.InitStruct();
00436
00437 memset(&jaco_velocity, 0, sizeof(jaco_velocity));
00438
00439 startAPI();
00440 jaco_velocity.Position.Type = ANGULAR_VELOCITY;
00441
00442
00443 jaco_velocity.Position.Actuators = joint_vel;
00444
00445 int result = jaco_api_.sendAdvanceTrajectory(jaco_velocity);
00446 if (result != NO_ERROR_KINOVA)
00447 {
00448 throw JacoCommException("Could not send advanced joint velocity trajectory", result);
00449 }
00450 }
00451
00452
00456 void JacoComm::setCartesianVelocities(const CartesianInfo &velocities)
00457 {
00458 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00459
00460 if (isStopped())
00461 {
00462 ROS_INFO("The cartesian velocities could not be set because the arm is stopped");
00463 jaco_api_.eraseAllTrajectories();
00464 return;
00465 }
00466
00467 TrajectoryPoint jaco_velocity;
00468 jaco_velocity.InitStruct();
00469
00470 memset(&jaco_velocity, 0, sizeof(jaco_velocity));
00471
00472 startAPI();
00473 jaco_velocity.Position.Type = CARTESIAN_VELOCITY;
00474
00475
00476 jaco_velocity.Position.CartesianPosition = velocities;
00477
00478 int result = jaco_api_.sendAdvanceTrajectory(jaco_velocity);
00479 if (result != NO_ERROR_KINOVA)
00480 {
00481 throw JacoCommException("Could not send advanced Cartesian velocity trajectory", result);
00482 }
00483 }
00484
00485
00492 void JacoComm::setConfig(const ClientConfigurations &config)
00493 {
00494 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00495 int result = jaco_api_.setClientConfigurations(config);
00496 if (result != NO_ERROR_KINOVA)
00497 {
00498 throw JacoCommException("Could not set the client configuration", result);
00499 }
00500 }
00501
00502
00506 void JacoComm::getJointAngles(JacoAngles &angles)
00507 {
00508 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00509 AngularPosition jaco_angles;
00510 memset(&jaco_angles, 0, sizeof(jaco_angles));
00511
00512 int result = jaco_api_.getAngularPosition(jaco_angles);
00513 if (result != NO_ERROR_KINOVA)
00514 {
00515 throw JacoCommException("Could not get the angular position", result);
00516 }
00517
00518 angles = JacoAngles(jaco_angles.Actuators);
00519 }
00520
00521
00525 void JacoComm::getCartesianPosition(JacoPose &position)
00526 {
00527 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00528 CartesianPosition jaco_cartesian_position;
00529 memset(&jaco_cartesian_position, 0, sizeof(jaco_cartesian_position));
00530
00531 int result = jaco_api_.getCartesianPosition(jaco_cartesian_position);
00532 if (result != NO_ERROR_KINOVA)
00533 {
00534 throw JacoCommException("Could not get the Cartesian position", result);
00535 }
00536
00537 position = JacoPose(jaco_cartesian_position.Coordinates);
00538 }
00539
00540
00544 void JacoComm::getFingerPositions(FingerAngles &fingers)
00545 {
00546 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00547 CartesianPosition jaco_cartesian_position;
00548 memset(&jaco_cartesian_position, 0, sizeof(jaco_cartesian_position));
00549
00550 int result = jaco_api_.getCartesianPosition(jaco_cartesian_position);
00551 if (result != NO_ERROR_KINOVA)
00552 {
00553 throw JacoCommException("Could not get Cartesian finger position", result);
00554 }
00555
00556 if (num_fingers_ == 2)
00557 {
00558 jaco_cartesian_position.Fingers.Finger3 = 0.0;
00559 }
00560
00561 fingers = FingerAngles(jaco_cartesian_position.Fingers);
00562 }
00563
00564
00568 void JacoComm::getConfig(ClientConfigurations &config)
00569 {
00570 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00571 memset(&config, 0, sizeof(config));
00572
00573 int result = jaco_api_.getClientConfigurations(config);
00574 if (result != NO_ERROR_KINOVA)
00575 {
00576 throw JacoCommException("Could not get client configuration", result);
00577 }
00578 }
00579
00580
00584 void JacoComm::getQuickStatus(QuickStatus &quick_status)
00585 {
00586 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00587 memset(&quick_status, 0, sizeof(quick_status));
00588 int result = jaco_api_.getQuickStatus(quick_status);
00589 if (result != NO_ERROR_KINOVA)
00590 {
00591 throw JacoCommException("Could not get quick status", result);
00592 }
00593 }
00594
00595
00596 void JacoComm::stopAPI()
00597 {
00598 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00599 is_software_stop_ = true;
00600
00601 int result = jaco_api_.stopControlAPI();
00602 if (result != NO_ERROR_KINOVA)
00603 {
00604 throw JacoCommException("Could not stop the control API", result);
00605 }
00606
00607 result = jaco_api_.eraseAllTrajectories();
00608 if (result != NO_ERROR_KINOVA)
00609 {
00610 throw JacoCommException("Could not erase all trajectories", result);
00611 }
00612 }
00613
00614
00615 void JacoComm::startAPI()
00616 {
00617 boost::recursive_mutex::scoped_lock lock(api_mutex_);
00618 if (is_software_stop_)
00619 {
00620 is_software_stop_ = false;
00621 jaco_api_.stopControlAPI();
00622 ros::Duration(0.05).sleep();
00623 }
00624
00625 int result = jaco_api_.startControlAPI();
00626 if (result != NO_ERROR_KINOVA)
00627 {
00628 throw JacoCommException("Could not start the control API", result);
00629 }
00630 }
00631
00632
00633 int JacoComm::numFingers()
00634 {
00635 return num_fingers_;
00636 }
00637
00638
00642 void JacoComm::printAngles(const JacoAngles &angles)
00643 {
00644 ROS_INFO("Joint angles (deg) -- J1: %f, J2: %f J3: %f, J4: %f, J5: %f, J6: %f",
00645 angles.Actuator1, angles.Actuator2, angles.Actuator3,
00646 angles.Actuator4, angles.Actuator5, angles.Actuator6);
00647 }
00648
00649
00653 void JacoComm::printPosition(const JacoPose &position)
00654 {
00655 ROS_INFO("Arm position\n"
00656 "\tposition (m) -- x: %f, y: %f z: %f\n"
00657 "\trotation (rad) -- theta_x: %f, theta_y: %f, theta_z: %f",
00658 position.X, position.Y, position.Z,
00659 position.ThetaX, position.ThetaY, position.ThetaZ);
00660 }
00661
00662
00666 void JacoComm::printFingers(const FingersPosition &fingers)
00667 {
00668 ROS_INFO("Finger positions -- F1: %f, F2: %f, F3: %f",
00669 fingers.Finger1, fingers.Finger2, fingers.Finger3);
00670 }
00671
00672
00676 void JacoComm::printConfig(const ClientConfigurations &config)
00677 {
00678 ROS_INFO_STREAM("Arm configuration:\n"
00679 "\tClientID: " << config.ClientID <<
00680 "\n\tClientName: " << config.ClientName <<
00681 "\n\tOrganization: " << config.Organization <<
00682 "\n\tSerial:" << config.Serial <<
00683 "\n\tModel: " << config.Model <<
00684 "\n\tMaxForce: " << config.MaxForce <<
00685 "\n\tSensibility: " << config.Sensibility <<
00686 "\n\tDrinkingHeight: " << config.DrinkingHeight <<
00687 "\n\tComplexRetractActive: " << config.ComplexRetractActive <<
00688 "\n\tRetractedPositionAngle: " << config.RetractedPositionAngle <<
00689 "\n\tRetractedPositionCount: " << config.RetractedPositionCount <<
00690 "\n\tDrinkingDistance: " << config.DrinkingDistance <<
00691 "\n\tFingers2and3Inverted: " << config.Fingers2and3Inverted <<
00692 "\n\tDrinkingLength: " << config.DrinkingLenght <<
00693 "\n\tDeletePreProgrammedPositionsAtRetract: " <<
00694 config.DeletePreProgrammedPositionsAtRetract <<
00695 "\n\tEnableFlashErrorLog: " << config.EnableFlashErrorLog <<
00696 "\n\tEnableFlashPositionLog: " << config.EnableFlashPositionLog);
00697 }
00698
00699
00700 bool JacoComm::isStopped()
00701 {
00702 return is_software_stop_;
00703 }
00704
00705
00706 }