$search
00001 /* 00002 * UOS-ROS packages - Robot Operating System code by the University of Osnabrück 00003 * Copyright (C) 2010 University of Osnabrück 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * Katana.cpp 00020 * 00021 * Created on: 06.12.2010 00022 * Author: Martin Günther <mguenthe@uos.de> 00023 * Co-Author: Henning Deeken <hdeeken@uos.de> 00024 */ 00025 00026 #include "katana/Katana.h" 00027 00028 namespace katana 00029 { 00030 00031 Katana::Katana() : 00032 AbstractKatana() 00033 { 00034 ros::NodeHandle nh; 00035 ros::NodeHandle pn("~"); 00036 motor_status_.resize(NUM_MOTORS); 00037 00038 /* ********* get parameters ********* */ 00039 00040 // general parameters 00041 std::string config_file_path; 00042 bool use_serial; 00043 00044 bool has_path = pn.getParam("config_file_path", config_file_path); 00045 if (!has_path) { 00046 ROS_ERROR("Required parameter config_file_path could not be found on param server!"); 00047 return; 00048 } 00049 00050 pn.param("use_serial", use_serial, false); 00051 00052 converter = new KNIConverter(config_file_path); 00053 00054 // parameters for TCP/IP connection 00055 std::string ip; 00056 int tcpip_port; 00057 00058 pn.param<std::string> ("ip", ip, "192.168.1.1"); 00059 pn.param("port", tcpip_port, 5566); 00060 00061 // parameters for serial connection 00062 int serial_port; 00063 00064 pn.param("serial_port", serial_port, 0); 00065 if (serial_port < 0 || serial_port > 9) 00066 { 00067 ROS_ERROR("serial_port must be in the range [0-9]!"); 00068 return; 00069 } 00070 00071 try 00072 { 00073 /* ********* open device ********* */ 00074 if (use_serial) 00075 { 00076 ROS_INFO("trying to connect to katana (serial port: /dev/ttyS%d) ...", serial_port); 00077 00078 TCdlCOMDesc serial_config; 00079 serial_config.port = serial_port; // serial port number (0-9 for /dev/ttyS[0-9]) 00080 serial_config.baud = 57600; // baud rate of port 00081 serial_config.data = 8; // data bits 00082 serial_config.parity = 'N'; // parity bit 00083 serial_config.stop = 1; // stop bit 00084 serial_config.rttc = 300; // read total timeout 00085 serial_config.wttc = 0; // write total timeout 00086 00087 device = new CCdlCOM(serial_config); 00088 ROS_INFO("success: serial connection to Katana opened"); 00089 } 00090 else 00091 { 00092 ROS_INFO("trying to connect to katana (TCP/IP) on %s:%d...", ip.c_str(), tcpip_port); 00093 char* nonconst_ip = strdup(ip.c_str()); 00094 device = new CCdlSocket(nonconst_ip, tcpip_port); 00095 free(nonconst_ip); 00096 ROS_INFO("success: TCP/IP connection to Katana opened"); 00097 } 00098 00099 /* ********* init protocol ********* */ 00100 protocol = new CCplSerialCRC(); 00101 ROS_INFO("success: protocol class instantiated"); 00102 00103 protocol->init(device); //fails if no response from Katana 00104 ROS_INFO("success: communication with Katana initialized"); 00105 00106 /* ********* init robot ********* */ 00107 kni.reset(new CLMBase()); 00108 kni->create(config_file_path.c_str(), protocol); 00109 ROS_INFO("success: katana initialized"); 00110 } 00111 catch (Exception &e) 00112 { 00113 ROS_ERROR("Exception during initialization: '%s'", e.message().c_str()); 00114 return; 00115 } 00116 00117 setLimits(); 00118 00119 /* ********* calibrate ********* */ 00120 calibrate(); 00121 ROS_INFO("success: katana calibrated"); 00122 00123 refreshEncoders(); 00124 00125 // boost::thread worker_thread(&Katana::test_speed, this); 00126 00127 /* ********* services ********* */ 00128 switch_motors_off_srv_ = nh.advertiseService("switch_motors_off", &Katana::switchMotorsOff, this); 00129 switch_motors_on_srv_ = nh.advertiseService("switch_motors_on", &Katana::switchMotorsOn, this); 00130 test_speed_srv_ = nh.advertiseService("test_speed", &Katana::testSpeedSrv, this); 00131 } 00132 00133 Katana::~Katana() 00134 { 00135 // protocol and device are members of kni, so we should be 00136 // the last ones using it before deleting them 00137 assert(kni.use_count() == 1); 00138 00139 kni.reset(); // delete kni, so protocol and device won't be used any more 00140 delete protocol; 00141 delete device; 00142 delete converter; 00143 } 00144 00145 void Katana::setLimits(void) { 00146 for (size_t i = 0; i < NUM_MOTORS; i++) { 00147 // These two settings probably only influence KNI functions like moveRobotToEnc(), 00148 // openGripper() and so on, and not the spline trajectories. We still set them 00149 // just to be sure. 00150 kni->setMotorAccelerationLimit(i, KNI_MAX_ACCELERATION); 00151 kni->setMotorVelocityLimit(i, KNI_MAX_VELOCITY); 00152 } 00153 } 00154 00155 void Katana::refreshEncoders() 00156 { 00157 try 00158 { 00159 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00160 CMotBase* motors = kni->GetBase()->GetMOT()->arr; 00161 00162 kni->GetBase()->recvMPS(); // refresh all pvp->pos at once 00163 00164 // Using recvMPS() instead of recvPVP() makes our updates 6 times 00165 // faster, since we only need one KNI call instead of 6. The KNI 00166 // needs exactly 40 ms for every update call. 00167 00168 for (size_t i = 0; i < NUM_MOTORS; i++) 00169 { 00170 // motors[i].recvPVP(); // refresh pvp->pos, pvp->vel and pvp->msf for single motor; throws ParameterReadingException 00171 const TMotPVP* pvp = motors[i].GetPVP(); 00172 00173 double current_angle = converter->angle_enc2rad(i, pvp->pos); 00174 double time_since_update = (ros::Time::now() - last_encoder_update_).toSec(); 00175 00176 if (last_encoder_update_ == ros::Time(0.0) || time_since_update == 0.0) 00177 { 00178 motor_velocities_[i] = 0.0; 00179 } 00180 else 00181 { 00182 motor_velocities_[i] = (current_angle - motor_angles_[i]) / time_since_update; 00183 } 00184 // // only necessary when using recvPVP(): 00185 // motor_velocities_[i] = vel_enc2rad(i, pvp->vel) * (-1); // the -1 is because the KNI is inconsistent about velocities 00186 00187 motor_angles_[i] = current_angle; 00188 } 00189 00190 // // This is an ugly workaround, but apparently the velocities returned by the 00191 // // Katana are wrong by a factor of exactly 0.5 for motor 2 and a factor of -1 00192 // // for motor 4. This is only necessary when using recvPVP() to receive the 00193 // // velocities directly from the KNI. 00194 // motor_velocities_[2] *= 0.5; 00195 // motor_velocities_[4] *= -1.0; 00196 00197 last_encoder_update_ = ros::Time::now(); 00198 } 00199 catch (const WrongCRCException &e) 00200 { 00201 ROS_ERROR("WrongCRCException: Two threads tried to access the KNI at once. This means that the locking in the Katana node is broken. (exception in refreshEncoders(): %s)", e.message().c_str()); 00202 } 00203 catch (const ReadNotCompleteException &e) 00204 { 00205 ROS_ERROR("ReadNotCompleteException: Another program accessed the KNI. Please stop it and restart the Katana node. (exception in refreshEncoders(): %s)", e.message().c_str()); 00206 } 00207 catch (const ParameterReadingException &e) 00208 { 00209 ROS_ERROR("ParameterReadingException: Could not receive PVP (Position Velocity PWM) parameters from a motor (exception in refreshEncoders(): %s)", e.message().c_str()); 00210 } 00211 catch (const Exception &e) 00212 { 00213 ROS_ERROR("Unhandled exception in refreshEncoders(): %s", e.message().c_str()); 00214 } 00215 catch (...) 00216 { 00217 ROS_ERROR("Unhandled exception in refreshEncoders()"); 00218 } 00219 } 00220 00221 void Katana::refreshMotorStatus() 00222 { 00223 try 00224 { 00225 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00226 CMotBase* motors = kni->GetBase()->GetMOT()->arr; 00227 00228 kni->GetBase()->recvGMS(); // refresh all pvp->msf at once 00229 00230 for (size_t i = 0; i < NUM_MOTORS; i++) 00231 { 00232 const TMotPVP* pvp = motors[i].GetPVP(); 00233 00234 motor_status_[i] = pvp->msf; 00235 // MSF_MECHSTOP = 1, //!< mechanical stopper reached, new: unused (default value) 00236 // MSF_MAXPOS = 2, //!< max. position was reached, new: unused 00237 // MSF_MINPOS = 4, //!< min. position was reached, new: calibrating 00238 // MSF_DESPOS = 8, //!< in desired position, new: fixed, state holding 00239 // MSF_NORMOPSTAT = 16, //!< trying to follow target, new: moving (polymb not full) 00240 // MSF_MOTCRASHED = 40, //!< motor has crashed, new: collision (MG: this means that the motor has reached a collision limit (e.g., after executing a invalid spline) and has to be reset using unBlock()) 00241 // MSF_NLINMOV = 88, //!< non-linear movement ended, new: poly move finished 00242 // MSF_LINMOV = 152, //!< linear movement ended, new: moving poly, polymb full 00243 // MSF_NOTVALID = 128 //!< motor data not valid 00244 00245 /* 00246 * Das Handbuch zu Katana4D sagt (zu ReadAxisState): 00247 * 0 = off (ausgeschaltet) 00248 * 8 = in gewünschter Position (Roboter fixiert) 00249 * 24 = im "normalen Bewegungsstatus"; versucht die gewünschte Position zu erreichen 00250 * 40 = wegen einer Kollision gestoppt 00251 * 88 = die Linearbewegung ist beendet 00252 * 128 = ungültige Achsendaten (interne Kommunikationsprobleme) 00253 */ 00254 } 00255 } 00256 catch (const WrongCRCException &e) 00257 { 00258 ROS_ERROR("WrongCRCException: Two threads tried to access the KNI at once. This means that the locking in the Katana node is broken. (exception in refreshMotorStatus(): %s)", e.message().c_str()); 00259 } 00260 catch (const ReadNotCompleteException &e) 00261 { 00262 ROS_ERROR("ReadNotCompleteException: Another program accessed the KNI. Please stop it and restart the Katana node. (exception in refreshMotorStatus(): %s)", e.message().c_str()); 00263 } 00264 catch (const Exception &e) 00265 { 00266 ROS_ERROR("Unhandled exception in refreshMotorStatus(): %s", e.message().c_str()); 00267 } 00268 catch (...) 00269 { 00270 ROS_ERROR("Unhandled exception in refreshMotorStatus()"); 00271 } 00272 } 00273 00279 bool Katana::executeTrajectory(boost::shared_ptr<SpecifiedTrajectory> traj) 00280 { 00281 assert(traj->size() > 0); 00282 00283 try 00284 { 00285 // ------- wait until all motors idle 00286 ros::Rate idleWait(10); 00287 while (!allMotorsReady()) 00288 { 00289 refreshMotorStatus(); 00290 ROS_DEBUG("Motor status: %d, %d, %d, %d, %d, %d", motor_status_[0], motor_status_[1], motor_status_[2], motor_status_[3], motor_status_[4], motor_status_[5]); 00291 00292 // ------- check if motors are blocked 00293 // it is important to do this inside the allMotorsReady() loop, otherwise we 00294 // could get stuck in a deadlock if the motors crash while we wait for them to 00295 // become ready 00296 if (someMotorCrashed()) 00297 { 00298 ROS_WARN("Motors are crashed before executing trajectory! Unblocking..."); 00299 00300 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00301 kni->unBlock(); 00302 } 00303 00304 idleWait.sleep(); 00305 } 00306 00308 //{ 00309 // assert(traj->at(0).splines.size() == NUM_JOINTS); 00310 // 00311 // boost::recursive_mutex::scoped_lock lock(kni_mutex); 00312 // std::vector<int> encoders; 00313 // 00314 // for (size_t i = 0; i < NUM_JOINTS; i++) { 00315 // encoders.push_back(converter->angle_rad2enc(i, traj->at(0).splines[i].coef[0])); 00316 // } 00317 // 00318 // std::vector<int> current_encoders = kni->getRobotEncoders(true); 00319 // ROS_INFO("current encoders: %d %d %d %d %d", current_encoders[0], current_encoders[1], current_encoders[2], current_encoders[3], current_encoders[4]); 00320 // ROS_INFO("target encoders: %d %d %d %d %d", encoders[0], encoders[1], encoders[2], encoders[3], encoders[4]); 00321 // 00322 // kni->moveRobotToEnc(encoders, false); 00323 // ros::Duration(2.0).sleep(); 00324 //} 00325 00326 // ------- wait until start time 00327 ros::Time start_time = ros::Time(traj->at(0).start_time); 00328 double time_until_start = (start_time - ros::Time::now()).toSec(); 00329 00330 if (time_until_start < -0.01) 00331 { 00332 ROS_WARN("Trajectory started %f s too late! Scheduled: %f, started: %f", -time_until_start, start_time.toSec(), ros::Time::now().toSec()); 00333 } 00334 else if (time_until_start > 0.0) 00335 { 00336 ROS_DEBUG("Sleeping %f seconds until scheduled start of trajectory", time_until_start); 00337 ros::Time::sleepUntil(start_time); 00338 } 00339 00340 // ------- start trajectory 00341 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00342 00343 // fix start times: set the trajectory start time to now(); since traj is a shared pointer, 00344 // this fixes the current_trajectory_ in joint_trajectory_action_controller, which synchronizes 00345 // the "state" publishing to the actual start time (more or less) 00346 double delay = ros::Time::now().toSec() - traj->at(0).start_time; 00347 for (size_t i = 0; i < traj->size(); i++) 00348 { 00349 traj->at(i).start_time += delay; 00350 } 00351 00352 for (size_t i = 0; i < traj->size(); i++) 00353 { 00354 Segment seg = traj->at(i); 00355 if (seg.splines.size() != joint_names_.size()) 00356 { 00357 ROS_ERROR("Wrong number of joints in specified trajectory (was: %zu, expected: %zu)!", seg.splines.size(), joint_names_.size()); 00358 } 00359 00360 // set and start movement 00361 int activityflag = 0; 00362 if (i == (traj->size() - 1)) 00363 { 00364 // last spline, start movement 00365 activityflag = 1; // no_next 00366 } 00367 else if (seg.start_time - traj->at(0).start_time < 0.4) 00368 { 00369 // more splines following, do not start movement yet 00370 activityflag = 2; // no_start 00371 } 00372 else 00373 { 00374 // more splines following, start movement 00375 activityflag = 0; 00376 } 00377 00378 std::vector<short> polynomial; 00379 short s_time = round(seg.duration * KNI_TO_ROS_TIME); 00380 if (s_time <= 0) 00381 s_time = 1; 00382 00383 for (size_t j = 0; j < seg.splines.size(); j++) 00384 { 00385 // some parts taken from CLMBase::movLM2P 00386 polynomial.push_back(s_time); // duration 00387 00388 polynomial.push_back(converter->angle_rad2enc(j, seg.splines[j].target_position)); // target position 00389 00390 // the four spline coefficients 00391 // the actual position, round 00392 polynomial.push_back(round(converter->angle_rad2enc(j, seg.splines[j].coef[0]))); // p0 00393 00394 // shift to be firmware compatible and round 00395 polynomial.push_back(round(64 * converter->vel_rad2enc(j, seg.splines[j].coef[1]))); // p1 00396 polynomial.push_back(round(1024 * converter->acc_rad2enc(j, seg.splines[j].coef[2]))); // p2 00397 polynomial.push_back(round(32768 * converter->jerk_rad2enc(j, seg.splines[j].coef[3]))); // p3 00398 } 00399 00400 // gripper: hold current position 00401 polynomial.push_back(s_time); // duration 00402 polynomial.push_back(converter->angle_rad2enc(5, motor_angles_[5])); // target position (angle) 00403 polynomial.push_back(converter->angle_rad2enc(5, motor_angles_[5])); // p0 00404 polynomial.push_back(0); // p1 00405 polynomial.push_back(0); // p2 00406 polynomial.push_back(0); // p3 00407 00408 ROS_DEBUG("setAndStartPolyMovement(%d): ", activityflag); 00409 00410 for (size_t k = 5; k < polynomial.size(); k += 6) 00411 { 00412 ROS_DEBUG(" time: %d target: %d p0: %d p1: %d p2: %d p3: %d", 00413 polynomial[k-5], polynomial[k-4], polynomial[k-3], polynomial[k-2], polynomial[k-1], polynomial[k]); 00414 } 00415 00416 kni->setAndStartPolyMovement(polynomial, false, activityflag); 00417 } 00418 return true; 00419 } 00420 catch (const WrongCRCException &e) 00421 { 00422 ROS_ERROR("WrongCRCException: Two threads tried to access the KNI at once. This means that the locking in the Katana node is broken. (exception in executeTrajectory(): %s)", e.message().c_str()); 00423 } 00424 catch (const ReadNotCompleteException &e) 00425 { 00426 ROS_ERROR("ReadNotCompleteException: Another program accessed the KNI. Please stop it and restart the Katana node. (exception in executeTrajectory(): %s)", e.message().c_str()); 00427 } 00428 catch (const FirmwareException &e) 00429 { 00430 // TODO: find out what the real cause of this is when it happens again 00431 // the message returned by the Katana is: 00432 // FirmwareException : 'StopperThread: collision on axis: 1 (axis N)' 00433 ROS_ERROR("FirmwareException: Motor collision? Perhaps we tried to send a trajectory that the arm couldn't follow. (exception in executeTrajectory(): %s)", e.message().c_str()); 00434 } 00435 catch (const Exception &e) 00436 { 00437 ROS_ERROR("Unhandled exception in executeTrajectory(): %s", e.message().c_str()); 00438 } 00439 catch (...) 00440 { 00441 ROS_ERROR("Unhandled exception in executeTrajectory()"); 00442 } 00443 return false; 00444 } 00445 00446 void Katana::freezeRobot() 00447 { 00448 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00449 kni->flushMoveBuffers(); 00450 kni->freezeRobot(); 00451 } 00452 00453 bool Katana::moveJoint(int motorIndex, double desiredAngle) 00454 { 00455 if (desiredAngle < motor_limits_[motorIndex].min_position || motor_limits_[motorIndex].max_position < desiredAngle) 00456 { 00457 ROS_ERROR("Desired angle %f is out of range [%f, %f]", desiredAngle, motor_limits_[motorIndex].min_position, motor_limits_[motorIndex].max_position); 00458 return false; 00459 } 00460 00461 try 00462 { 00463 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00464 kni->moveMotorToEnc(motorIndex, converter->angle_rad2enc(motorIndex, desiredAngle), false, 100); 00465 return true; 00466 } 00467 catch (const WrongCRCException &e) 00468 { 00469 ROS_ERROR("WrongCRCException: Two threads tried to access the KNI at once. This means that the locking in the Katana node is broken. (exception in moveJoint(): %s)", e.message().c_str()); 00470 } 00471 catch (const ReadNotCompleteException &e) 00472 { 00473 ROS_ERROR("ReadNotCompleteException: Another program accessed the KNI. Please stop it and restart the Katana node. (exception in moveJoint(): %s)", e.message().c_str()); 00474 } 00475 catch (const Exception &e) 00476 { 00477 ROS_ERROR("Unhandled exception in moveJoint(): %s", e.message().c_str()); 00478 } 00479 catch (...) 00480 { 00481 ROS_ERROR("Unhandled exception in moveJoint()"); 00482 } 00483 return false; 00484 } 00485 00486 bool Katana::someMotorCrashed() 00487 { 00488 for (size_t i = 0; i < NUM_MOTORS; i++) 00489 { 00490 if (motor_status_[i] == MSF_MOTCRASHED) 00491 return true; 00492 } 00493 00494 return false; 00495 } 00496 00497 bool Katana::allJointsReady() 00498 { 00499 for (size_t i = 0; i < NUM_JOINTS; i++) 00500 { 00501 if ((motor_status_[i] != MSF_DESPOS) && (motor_status_[i] != (MSF_NLINMOV))) 00502 return false; 00503 } 00504 00505 return true; 00506 } 00507 00508 bool Katana::allMotorsReady() 00509 { 00510 for (size_t i = 0; i < NUM_MOTORS; i++) 00511 { 00512 if ((motor_status_[i] != MSF_DESPOS) && (motor_status_[i] != (MSF_NLINMOV))) 00513 return false; 00514 } 00515 00516 return true; 00517 } 00518 00519 /* ******************************** helper functions ******************************** */ 00520 00524 short inline Katana::round(const double x) 00525 { 00526 if (x >= 0) 00527 return (short)(x + 0.5); 00528 else 00529 return (short)(x - 0.5); 00530 } 00531 00532 void Katana::calibrate() 00533 { 00534 // private function only called in constructor, so no locking required 00535 bool calibrate = false; 00536 const int encoders = 100; 00537 00538 kni->unBlock(); 00539 00540 // check if gripper collides in both cases (open and close gripper) 00541 // note MG: "1" is not the gripper! 00542 kni->enableCrashLimits(); 00543 00544 try 00545 { 00546 kni->moveMotorByEnc(1, encoders); 00547 ROS_INFO("no calibration required"); 00548 } 00549 catch (...) 00550 { 00551 ROS_INFO("first calibration collision... "); 00552 try 00553 { 00554 kni->moveMotorByEnc(1, -encoders); 00555 ROS_INFO("no calibration required"); 00556 } 00557 catch (...) 00558 { 00559 ROS_INFO("second calibration collision: calibration required"); 00560 calibrate = true; 00561 } 00562 } 00563 00564 if (calibrate) 00565 { 00566 kni->disableCrashLimits(); 00567 kni->calibrate(); 00568 kni->enableCrashLimits(); 00569 } 00570 } 00571 00576 bool Katana::switchMotorsOff(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response) 00577 { 00578 ROS_WARN("Switching all motors off!"); 00579 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00580 kni->switchRobotOff(); 00581 return true; 00582 } 00583 00584 bool Katana::switchMotorsOn(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response) 00585 { 00586 ROS_INFO("Switching all motors back on."); 00587 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00588 kni->switchRobotOn(); 00589 return true; 00590 } 00591 00592 bool Katana::testSpeedSrv(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response) 00593 { 00594 testSpeed(); 00595 return true; 00596 } 00597 00598 void Katana::testSpeed() 00599 { 00600 ros::Rate idleWait(5); 00601 std::vector<double> pos1_angles(NUM_MOTORS); 00602 std::vector<double> pos2_angles(NUM_MOTORS); 00603 00604 // these are safe values, i.e., no self-collision is possible 00605 pos1_angles[0] = 2.88; 00606 pos2_angles[0] = -3.02; 00607 00608 pos1_angles[1] = 0.15; 00609 pos2_angles[1] = 2.16; 00610 00611 pos1_angles[2] = 1.40; 00612 pos2_angles[2] = -2.21; 00613 00614 pos1_angles[3] = 0.50; 00615 pos2_angles[3] = -2.02; 00616 00617 pos1_angles[4] = 2.86; 00618 pos2_angles[4] = -2.98; 00619 00620 pos1_angles[5] = -0.44; 00621 pos2_angles[5] = 0.30; 00622 00623 for (size_t i = 0; i < NUM_MOTORS; i++) 00624 { 00625 int pos1_encoders = (int)converter->angle_rad2enc(i, pos1_angles[i]); 00626 int pos2_encoders = (int)converter->angle_rad2enc(i, pos2_angles[i]); 00627 00628 int accel = kni->getMotorAccelerationLimit(i); 00629 int max_vel = kni->getMotorVelocityLimit(i); 00630 00631 ROS_INFO("Motor %zu - acceleration: %d (= %f), max speed: %d (=%f)", i, accel, 2.0 * converter->acc_enc2rad(i, accel), max_vel, converter->vel_enc2rad(i, max_vel)); 00632 ROS_INFO("KNI encoders: %d, %d", kni->GetBase()->GetMOT()->arr[i].GetEncoderMinPos(), kni->GetBase()->GetMOT()->arr[i].GetEncoderMaxPos()); 00633 ROS_INFO("moving to encoders: %d, %d", pos1_encoders, pos2_encoders); 00634 ROS_INFO("current encoders: %d", kni->getMotorEncoders(i, true)); 00635 00636 ROS_INFO("Moving to min"); 00637 { 00638 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00639 kni->moveMotorToEnc(i, pos1_encoders); 00640 } 00641 00642 do 00643 { 00644 idleWait.sleep(); 00645 refreshMotorStatus(); 00646 } while (!allMotorsReady()); 00647 00648 ROS_INFO("Moving to max"); 00649 { 00650 boost::recursive_mutex::scoped_lock lock(kni_mutex); 00651 kni->moveMotorToEnc(i, pos2_encoders); 00652 } 00653 00654 do 00655 { 00656 idleWait.sleep(); 00657 refreshMotorStatus(); 00658 } while (!allMotorsReady()); 00659 } 00660 00661 // Result: 00662 // Motor 0 - acceleration: 2 (= -4.908739), max speed: 180 (=-2.208932) 00663 // Motor 1 - acceleration: 2 (= -2.646220), max speed: 180 (=-1.190799) 00664 // Motor 2 - acceleration: 2 (= 5.292440), max speed: 180 (=2.381598) 00665 // --> wrong! the measured values are more like 2.6, 1.2 00666 // 00667 // Motor 3 - acceleration: 2 (= -4.908739), max speed: 180 (=-2.208932) 00668 // Motor 4 - acceleration: 2 (= -4.908739), max speed: 180 (=-2.208932) 00669 // Motor 5 - acceleration: 2 (= 1.597410), max speed: 180 (=0.718834) 00670 // (TODO: the gripper duration can be calculated from this) 00671 } 00672 00673 }