$search
00001 /**************************************************************** 00002 * 00003 * Copyright (c) 2010 00004 * 00005 * Fraunhofer Institute for Manufacturing Engineering 00006 * and Automation (IPA) 00007 * 00008 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 00009 * 00010 * Project name: 00011 * ROS stack name: 00012 * ROS package name: 00013 * Description: 00014 * 00015 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 00016 * 00017 * Author: 00018 * Supervised by: 00019 * 00020 * Date of creation: Jan 2010 00021 * ToDo: 00022 * 00023 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 00024 * 00025 * Redistribution and use in source and binary forms, with or without 00026 * modification, are permitted provided that the following conditions are met: 00027 * 00028 * * Redistributions of source code must retain the above copyright 00029 * notice, this list of conditions and the following disclaimer. 00030 * * Redistributions in binary form must reproduce the above copyright 00031 * notice, this list of conditions and the following disclaimer in the 00032 * documentation and/or other materials provided with the distribution. 00033 * * Neither the name of the Fraunhofer Institute for Manufacturing 00034 * Engineering and Automation (IPA) nor the names of its 00035 * contributors may be used to endorse or promote products derived from 00036 * this software without specific prior written permission. 00037 * 00038 * This program is free software: you can redistribute it and/or modify 00039 * it under the terms of the GNU Lesser General Public License LGPL as 00040 * published by the Free Software Foundation, either version 3 of the 00041 * License, or (at your option) any later version. 00042 * 00043 * This program is distributed in the hope that it will be useful, 00044 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00045 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00046 * GNU Lesser General Public License LGPL for more details. 00047 * 00048 * You should have received a copy of the GNU Lesser General Public 00049 * License LGPL along with this program. 00050 * If not, see <http://www.gnu.org/licenses/>. 00051 * 00052 ****************************************************************/ 00053 00054 //################## 00055 //#### includes #### 00056 00057 // header 00058 #include <CANOpen_driver.h> 00059 00060 // standard includes 00061 #include <stdlib.h> 00062 00063 /* ============================================================== */ 00064 /* ======================= public =============================== */ 00065 /* ============================================================== */ 00066 00067 // Constructor 00068 CANOpenMaster::CANOpenMaster() 00069 { 00070 //can_itf = new CANPeakSysUSB("/home/tim/git/care-o-bot/schunk_modular_robotics/CANOpen_driver/CanCtrl.ini"); 00071 CANObj = new CANOpenCiA401ObjDirectory(); 00072 00073 m_CanBaseAddress = 0x0c; 00074 00075 TxSDO = 0x580 + m_CanBaseAddress; 00076 RxSDO = 0x600 + m_CanBaseAddress; 00077 TxPDO1 = 0x180 + m_CanBaseAddress; 00078 RxPDO1 = 0x200 + m_CanBaseAddress; 00079 TxPDO2 = 0x280 + m_CanBaseAddress; 00080 RxPDO2 = 0x300 + m_CanBaseAddress; 00081 TxPDO3 = 0x380 + m_CanBaseAddress; 00082 RxPDO3 = 0x400 + m_CanBaseAddress; 00083 TxPDO4 = 0x480 + m_CanBaseAddress; 00084 RxPDO4 = 0x500 + m_CanBaseAddress; 00085 SYNC = 0x080; 00086 EMCY = 0x080 + m_CanBaseAddress; 00087 NMT = 0x000; 00088 HEARTBEAT = 0x700 + m_CanBaseAddress; 00089 00090 NodeState = 0x05; 00091 ControlerState = 0; 00092 00093 // motorcommands 00094 SWITCH_ON = 0x07; 00095 SHUTDOWN = 0x06; 00096 DISABLE_VOLTAGE = 0x00; 00097 QUICKSTOP = 0x02; 00098 DISABLE_OPERATION = 0x07; 00099 ENABLE_OPERATION = 0x0F; 00100 FAULT_RESET = 0x0080; 00101 00102 // motorstates 00103 Not_Ready_To_Switch_On = 0x0000; 00104 Switch_On_Disabled = 0x0040; 00105 Ready_To_Switch_On = 0x0021; 00106 Switched_On = 0x0023; 00107 Operation_Enable = 0x0027; 00108 Fault = 0x0008; 00109 Fault_Reaction_Active = 0x000F; 00110 Quick_Stop_Active = 0x0007; 00111 00112 // statusvariables for state mashine 00113 IS_HOMED = false; 00114 FAULT_WAS_ACTIVE = true; 00115 00116 // variabels for CAN-msg download header 00117 const int ciInitDownloadReq = 0x20; 00118 const int ciNrBytesNoData = 0x00; 00119 const int ciExpedited = 0x02; 00120 const int ciDataSizeInd = 0x01; 00121 00122 CANDownloadHeader = ciInitDownloadReq | (ciNrBytesNoData << 2) | ciExpedited | ciDataSizeInd; 00123 00124 Lin_Axis_max_speed = 83; //m/s 00125 } 00126 00127 /*---------------------------------------------------------------*/ 00128 // Destructor 00129 CANOpenMaster::~CANOpenMaster() 00130 { 00131 delete can_itf; 00132 delete CANObj; 00133 } 00134 00135 /*---------------------------------------------------------------*/ 00136 // Inits the CanOpen interface to the linear axis 00137 int CANOpenMaster::Init() 00138 { 00139 00140 usleep(500000); 00141 // wait for inital heardbeat (not neccessary for Schunk) 00142 /* while (timer<=timeout){if (WaitForHeartbeat()==0){break;} timer++;} 00143 if (timer==timeout){ROS_INFO("timeout on initial heardbeat of linear axis"); 00144 return -1; 00145 } 00146 */ 00147 //reset CAN-node 00148 SendNMT(m_CanBaseAddress,0x01); 00149 00150 usleep(500000); 00151 00152 // set COB_ID SYNC 00153 // if (WriteObject(&CANObj->COB_ID_SYNC, CANObj->SYNC_CONSUMER + m_CanBaseAddress)!=0){return -1;} 00154 usleep(100000); 00155 00156 // set COB_ID EMCY 00157 // if (WriteObject(&CANObj->COB_ID_EMCY, CANObj->EMCY_EXIST + m_CanBaseAddress)!=0){return -2;} 00158 usleep(100000); 00159 00160 00161 /* configure TPDO1 */ 00162 /* 00163 // disable COB_ID TPDO1 00164 WriteObject(&CANObj->COB_ID_TPDO1[1], 0x80000000 + TxPDO1); 00165 usleep(200000); 00166 00167 // disable mapping on TPDO1 00168 if (WriteObject(&CANObj->PDO_MAP_TPDO1[0],0x0)!=0){return -5;} 00169 usleep(200000); 00170 00171 // map status to TPDO1 00172 if (WriteObject(&CANObj->PDO_MAP_TPDO1[1],((CANObj->controlword.Index << 16) + (CANObj->controlword.SubIndex << 8) + 16 /*Lenght 16 Bit))!=0){return -6;} 00173 usleep(200000); 00174 00175 // map interpolation_data_record to RPDO1 00176 if (WriteObject(&CANObj->PDO_MAP_RPDO1[2],0x60C10120)!=0){return -7;} 00177 usleep(200000); 00178 00179 // enable mapping on RPDO1 00180 if (WriteObject(&CANObj->PDO_MAP_RPDO1[0],0x02)!=0){return -8;} 00181 usleep(200000); 00182 00183 // enable COB_ID TPDO1 00184 WriteObject(&CANObj->COB_ID_TPDO1[1], TxPDO1); 00185 usleep(200000); 00186 */ 00187 00188 /* configure RPDO1 */ 00189 /* 00190 // disable COB_ID RPDO1 00191 WriteObject(&CANObj->COB_ID_RPDO1[1], 0x80000000 + RxPDO1); 00192 usleep(500000); 00193 00194 // disable mapping on RPDO1 00195 if (WriteObject(&CANObj->PDO_MAP_RPDO1[0],0x0)!=0){return -5;} 00196 usleep(500000); 00197 00198 // map controlword to RPDO1 00199 if (WriteObject(&CANObj->PDO_MAP_RPDO1[1],((CANObj->controlword.Index << 16) + (CANObj->controlword.SubIndex << 8) + 16 /*Lenght 16 Bit))!=0){return -6;} 00200 usleep(500000); 00201 00202 // map interpolation_data_record to RPDO1 00203 if (WriteObject(&CANObj->PDO_MAP_RPDO1[2],0x60C10120)!=0){return -7;} 00204 usleep(200000); 00205 00206 // enable mapping on RPDO1 00207 if (WriteObject(&CANObj->PDO_MAP_RPDO1[0],0x02)!=0){return -8;} 00208 usleep(200000); 00209 00210 // enable COB_ID RPDO1 00211 if (WriteObject(&CANObj->COB_ID_RPDO1[1], RxPDO1)!=0){return -9;} 00212 usleep(200000); 00213 */ 00214 // set COB_ID TPDO2 and disable CH 00215 // if (WriteObject(&CANObj->COB_ID_TPDO2[1],0x80000000 + TxPDO1)!=0){return -10;} 00216 usleep(100000); 00217 00218 // set transmission type of RPDO2 00219 // if (WriteObject(&CANObj->COB_ID_TPDO1[2], 0xFF)!=0){return -9;} // asynchronous 00220 usleep(100000); 00221 00222 /* not implemented yet in PowerBall controller 00223 00224 // set COB_ID TPDO3 and disable CH 00225 // if (WriteObject(&CANObj->COB_ID_TPDO3[1],0x80000000 + TxPDO3)!=0){return -10;} 00226 usleep(100000); 00227 00228 // set COB_ID RPDO3 and disable CH 00229 // if (WriteObject(&CANObj->COB_ID_RPDO3[1],0x80000000 + RxPDO3)!=0){return -11;} 00230 usleep(100000); 00231 00232 // set COB_ID TPDO4 and disable CH 00233 // if (WriteObject(&CANObj->COB_ID_TPDO4[1],0x80000000 + TxPDO4)!=0){return -12;} 00234 usleep(100000); 00235 00236 // set COB_ID RPDO4 and disable CH 00238 usleep(100000); 00239 */ 00240 00241 // set GIT to 10 ms 00242 // if (WriteObject(&CANObj->Communication_cycle_period,0x00002710)!=0){return -26;} 00243 usleep(100000); 00244 /* 00245 // set ip_sync_definition 00246 if (WriteObject(&CANObj->ip_sync_definition[1],0x00)!=0){return -27;} //general sync 00247 usleep(100000); 00248 00249 // set ip_sync_definition 00250 if (WriteObject(&CANObj->ip_sync_definition[2],0x01)!=0){return -28;} //sync every event 00251 usleep(100000); 00252 00253 // set ip_data_configuration 00254 if (WriteObject(&CANObj->ip_data_configuration[3],0x00)!=0){return -29;} //FIFO-buffer 00255 usleep(100000); 00256 00257 // set ip_data_configuration 00258 if (WriteObject(&CANObj->ip_data_configuration[5],0x01)!=0){return -30;} //1 pos value 00259 usleep(100000); 00260 */ 00261 //initiate CAN-node (set in operational mode s.CiA301) 00262 SendNMT(m_CanBaseAddress,0x01); 00263 00264 usleep(100000); 00265 00266 return 0; 00267 } 00268 00269 /*---------------------------------------------------------------*/ 00270 // home axis 00271 int CANOpenMaster::Homing() 00272 { 00273 int timer = 0; 00274 int referenced = 0; 00275 00276 // get mode of operation 00277 try{std::cout << "mode: " << ReadObject(&CANObj->mode_of_operation_display) << std::endl;} 00278 catch(int error) 00279 {ROS_INFO("Error on reading: %i", error);return -1;} 00280 00281 usleep(500000); 00282 00283 // set mode of operation to homing 00284 if (WriteObject(&CANObj->mode_of_operation, CANObj->HOMING_MODE)!=0){return -2;} 00285 00286 usleep(500000); 00287 00288 // get mode of operation 00289 try{std::cout << "mode: " << ReadObject(&CANObj->mode_of_operation_display) << std::endl;} 00290 catch(int error) 00291 {ROS_INFO("Error on reading: %i", error);return -3;} 00292 00293 00294 // wait for activating homing mode 00295 while(timer<50) 00296 { 00297 try{ 00298 referenced = ReadObject(&CANObj->mode_of_operation_display); 00299 } 00300 catch(int error) 00301 {ROS_INFO("Error on reading: %i", error);return -4;} 00302 00303 if(referenced == CANObj->HOMING_MODE){break;} 00304 00305 timer++; 00306 usleep(10000); 00307 } 00308 00309 // start homing with sending controlword 00310 if (WriteObject(&CANObj->controlword, SHUTDOWN)!=0){return -5;} 00311 usleep(200000); 00312 // start homing with sending controlword 00313 if (WriteObject(&CANObj->controlword, SWITCH_ON)!=0){return -6;} 00314 usleep(200000); 00315 // start homing with sending controlword 00316 if (WriteObject(&CANObj->controlword, ENABLE_OPERATION)!=0){return -7;} 00317 usleep(200000); 00318 // start homing with sending controlword 00319 if (WriteObject(&CANObj->controlword, (0x0010 | ENABLE_OPERATION))!=0){return -8;} 00320 00321 ROS_INFO("Homing Start"); 00322 00323 // wait finishing homing 00324 while(timer<100) 00325 { 00326 try{ 00327 referenced = ReadObject(&CANObj->statusword); 00328 } 00329 catch(int error) 00330 {ROS_INFO("Error on reading: %i", error);return -9;} 00331 00332 if((referenced & 0x1000) == 0x1000) 00333 { 00334 break; 00335 } 00336 00337 timer++; 00338 usleep(100000); 00339 } 00340 00341 // set mode of operation to IP-mode 00342 if (WriteObject(&CANObj->mode_of_operation, CANObj->IP_MODE)!=0){return -10;} 00343 00344 // wait for activating IP mode 00345 while(timer<500) 00346 { 00347 try{ 00348 referenced = ReadObject(&CANObj->mode_of_operation_display); 00349 } 00350 catch(int error) 00351 {ROS_INFO("Error on reading: %i", error);return -11;} 00352 00353 if(referenced == CANObj->IP_MODE) 00354 { 00355 // get mode of operation 00356 try{std::cout << "mode: " << ReadObject(&CANObj->mode_of_operation_display) << std::endl;} 00357 catch(int error) 00358 {ROS_INFO("Error on reading: %i", error);return -12;} 00359 00360 // start homing with sending controlword 00361 if (WriteObject(&CANObj->controlword, ( FAULT_RESET | 0x0010 | ENABLE_OPERATION))!=0){return -13;} 00362 usleep(500000); 00363 00364 std::cout << "Status: " << (ReadObject(&CANObj->statusword)) << std::endl; 00365 00366 return 0; 00367 } 00368 00369 timer++; 00370 usleep(1000); 00371 } 00372 00373 return -14; 00374 00375 } 00376 00377 /*---------------------------------------------------------------*/ 00378 // send SYNC msg 00379 void CANOpenMaster::SendSYNC() 00380 { 00381 CanMsg CMsgTr; 00382 00383 CMsgTr.m_iLen = 0; 00384 CMsgTr.m_iID = SYNC; 00385 00386 can_itf->transmitMsg(CMsgTr); 00387 00388 //if(can_itf->receiveMsg(&CMsgTr)!=0) 00389 //{CMsgTr.print();} 00390 } 00391 00392 /*---------------------------------------------------------------*/ 00393 // set speed 00394 int CANOpenMaster::SetSpeed(int SpeedCmdMS) 00395 { // Limit speed 00396 if (SpeedCmdMS > Lin_Axis_max_speed){SpeedCmdMS = Lin_Axis_max_speed;} 00397 if (SpeedCmdMS < -Lin_Axis_max_speed){SpeedCmdMS = -Lin_Axis_max_speed;} 00398 00399 if (WriteObject(&CANObj->target_velocity, SpeedCmdMS)!=0){return -1;} 00400 return 0; 00401 } 00402 00403 /*---------------------------------------------------------------*/ 00404 // get speed 00405 int CANOpenMaster::GetSpeed() 00406 { 00407 int SpeedMS; 00408 try{SpeedMS = ReadObject(&CANObj->velocity_actual_value);} 00409 catch(int error){ROS_INFO("Error on reading: %i",error);return -1;} 00410 return SpeedMS; 00411 } 00412 00413 /*---------------------------------------------------------------*/ 00414 // get digital inputs 00415 int CANOpenMaster::GetDIn() 00416 { 00417 int DIn; 00418 try{DIn = ReadObject(&CANObj->digital_inputs);} 00419 catch(int error){ROS_INFO("Error on reading: %i",error);return -1;} 00420 return DIn; 00421 } 00422 00423 /*---------------------------------------------------------------*/ 00424 // recover from errors 00425 int CANOpenMaster::Recover() 00426 { 00427 int nErr = 0, timer=0; 00428 // read status 00429 EvaluateControlerState(); 00430 00431 while((ControlerState == Fault) || (ControlerState == Fault_Reaction_Active) || (ControlerState == Quick_Stop_Active)) 00432 { 00433 // reset faults (positive edge of bit 7) 00434 if (WriteObject(&CANObj->controlword, 0x00)!=0){return -1;} 00435 usleep(500000); 00436 00437 if (WriteObject(&CANObj->controlword, FAULT_RESET)!=0){return -1;} 00438 usleep(500000); 00439 00440 // read status 00441 EvaluateControlerState(); 00442 00443 // timeout watchdog 00444 if (timer>10) 00445 {return -1;} 00446 else 00447 {timer++;} 00448 } 00449 00450 if (ControlerState != Switch_On_Disabled) 00451 {ROS_INFO("error on transition to Switch_On_Disabled.Controllerstate = %i",ControlerState); 00452 try{ 00453 nErr = (0x0000FF00 & ReadObject(&CANObj->pre_defined_error_field[0])); 00454 } 00455 catch(int error) 00456 { std::cout << "Error on reading: " << error << std::endl;} 00457 if (nErr != 0) 00458 { std::cout << "There are Errors: " << std::endl; 00459 for (int i=0;i<nErr;i++) 00460 { try{std::cout << "Error" << i <<": " << ReadObject(&CANObj->pre_defined_error_field[i]) << std::endl;} 00461 catch(int error) 00462 {std::cout << "Error on reading: " << error << std::endl; return -1;} 00463 } 00464 }else{std::cout << "No Errors saved" << std::endl;} 00465 return -1; 00466 } 00467 00468 usleep(100000); 00469 00470 // go to ready_to_switch_on 00471 if (WriteObject(&CANObj->controlword, SHUTDOWN)!=0){return -1;} 00472 00473 usleep(100000); 00474 00475 // read status 00476 if(EvaluateControlerState()!=0){return -1;} 00477 if (ControlerState != Ready_To_Switch_On) 00478 {ROS_INFO("error on transition to Ready_To_Switch_On. Controllerstate = %i",ControlerState); return -1;} 00479 00480 usleep(100000); 00481 00482 // go to Switched_On 00483 WriteObject(&CANObj->controlword, SWITCH_ON); 00484 00485 usleep(100000); 00486 00487 // read status 00488 if(EvaluateControlerState()!=0){return -1;} 00489 if (ControlerState != Switched_On) 00490 {ROS_INFO("error on transition to Switched_On.Controllerstate = %i",ControlerState); return -1;} 00491 00492 usleep(200000); 00493 00494 // go to Operation_Enable 00495 WriteObject(&CANObj->controlword, ENABLE_OPERATION); 00496 00497 usleep(500000); 00498 00499 // read status 00500 EvaluateControlerState(); 00501 if (ControlerState != Operation_Enable) 00502 {ROS_INFO("error on transition to Operation_Enable."); return -1;} 00503 00504 FAULT_WAS_ACTIVE = false; 00505 00506 return 0; 00507 } 00508 00509 /*---------------------------------------------------------------*/ 00510 // get Nodestate 00511 int CANOpenMaster::GetNodeState() 00512 { 00513 unsigned int status; 00514 00515 try{status = ReadObject(&CANObj->manufacturer_status_register);} 00516 catch(int error){ std::cout << "Error: " << error << std::endl; return -1;} 00517 00518 // print state 00519 // Bit 0 00520 if ((status & 1)==1) 00521 { std::cout << "Homing active" << std::endl; } 00522 // Bit 1 00523 if ((status & 2)==2) 00524 { std::cout << "Homingswitch reached" << std::endl; } 00525 // Bit 2 00526 if ((status & 4)==4) 00527 { std::cout << "negative endswitch reached" << std::endl; } 00528 // Bit 3 00529 if ((status & 8)==8) 00530 { std::cout << "positive endswitch reached" << std::endl; } 00531 // Bit 4 00532 if ((status & 16)==16) 00533 { std::cout << "positioning successfull" << std::endl; } 00534 // Bit 5 00535 if ((status & 32)==32) 00536 { std::cout << "target reached" << std::endl; } 00537 // Bit 6 00538 if ((status & 64)==64) 00539 { std::cout << "rest of positioning distance reached" << std::endl; } 00540 // Bit 7 00541 if ((status & 128)==128) 00542 { std::cout << "reversive mode" << std::endl; } 00543 // Bit 8 00544 if ((status & 256)==256) 00545 { std::cout << "rpm reached n_ist=(n_mel +/-n_mel_hyst)" << std::endl; } 00546 // Bit 9 00547 if ((status & 512)==512) 00548 { std::cout << "rpm reached n_ist=(n_soll +/-n_mel_hyst)" << std::endl; } 00549 // Bit 10 00550 if ((status & 1024)==1024) 00551 { std::cout << "Positioning started" << std::endl; } 00552 // Bit 11 00553 if ((status & 2048)==2048) 00554 { std::cout << "I²t, Current-limiting active" << std::endl; } 00555 // Bit 12 00556 if ((status & 4096)==4096) 00557 { std::cout << "SinCos producer active" << std::endl; } 00558 // Bit 13 00559 if ((status & 8192)==8192) 00560 { std::cout << "rpm reached n_ist=(0 +/-n_mel_hyst)" << std::endl; } 00561 // Bit 14 00562 if ((status & 16384)==16384) 00563 { std::cout << "rpm reached n_ist=(0 +/-n_mel_hyst)" << std::endl; } 00564 // Bit 15 00565 if ((status & 32768)==32768) 00566 { std::cout << "rpm reached n_ist=(0 +/-n_mel_hyst)" << std::endl; } 00567 // Bit 16 00568 if ((status & 65536)==65536) 00569 { std::cout << "Warning" << std::endl; } 00570 // Bit 17 00571 if ((status & 131072)==131072) 00572 { std::cout << "General Error present" << std::endl; } 00573 // Bit 18 00574 if ((status & 262144)==262144) 00575 { std::cout << "negative direction resticted" << std::endl; } 00576 // Bit 19 00577 if ((status & 524288)==524288) 00578 { std::cout << "positiv direction resticted" << std::endl; } 00579 // Bit 20 00580 if ((status & 1048576)==1048576) 00581 { std::cout << "Homeing done" << std::endl; } 00582 // Bit 21 00583 if ((status & 2097152)==2097152) 00584 { std::cout << "automatic syncronization activ" << std::endl; } 00585 // Bit 22 00586 if ((status & 4194304)==4194304) 00587 { std::cout << "MMC initiated" << std::endl; } 00588 // Bit 23 00589 if ((status & 8388608)==8388608) 00590 { std::cout << "Amps enabled" << std::endl; } 00591 // Bit 24 00592 if ((status & 16777216)==16777216) 00593 { std::cout << "controler and amps enabled" << std::endl; } 00594 // Bit 25 00595 if ((status & 33554432)==33554432) 00596 { std::cout << "rpm desired value enabled" << std::endl; } 00597 // Bit 26 00598 if ((status & 67108864)==67108864) 00599 { std::cout << "emergency stop without positioinsensor" << std::endl; } 00600 // Bit 27 00601 if ((status & 134217728)==134217728) 00602 { std::cout << "MOTID-Mode" << std::endl; } 00603 // Bit 28 00604 if ((status & 268435456)==268435456) 00605 { std::cout << "write permission" << std::endl; } 00606 // Bit 29 00607 if ((status & 536870912)==536870912) 00608 { std::cout << "Technologiemodul present" << std::endl; } 00609 // Bit 30 00610 if ((status & 1073741824)==1073741824) 00611 { std::cout << "MMC pluged in" << std::endl; } 00612 // Bit 31 00613 if ((status & (unsigned int) 2147483648)== (unsigned int) 2147483648) 00614 { std::cout << "safe stop pluged in" << std::endl; } 00615 00616 return 0; 00617 } 00618 00619 /*---------------------------------------------------------------*/ 00620 void CANOpenMaster::PrintMotorStatus() 00621 { 00622 CanMsg CMsgTr; 00623 const int ciInitUploadReq = 0x40; 00624 00625 CMsgTr.m_iLen = 6; 00626 CMsgTr.m_iID = RxSDO; 00627 00628 unsigned char cMsg[8]; 00629 00630 cMsg[0] = ciInitUploadReq; 00631 cMsg[1] = 0x41; 00632 cMsg[2] = 0x60; 00633 cMsg[3] = 0x00; 00634 cMsg[4] = 0x00; 00635 cMsg[5] = 0x00; 00636 cMsg[6] = 0x00; 00637 cMsg[7] = 0x00; 00638 00639 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]); 00640 can_itf->transmitMsg(CMsgTr); 00641 00642 while (can_itf->receiveMsg(&CMsgTr)==0) 00643 { 00644 //std::cout << "waiting for statusreport" << std::endl; 00645 CMsgTr.print(); 00646 usleep(500); 00647 } 00648 CMsgTr.print(); 00649 if (CMsgTr.getAt(0) == 0x80) 00650 { std::cout << "Error on status request. SDO Errorcode: " << std::hex << CMsgTr.getAt(7) << " " << std::hex << CMsgTr.getAt(6) << " " << std::hex << CMsgTr.getAt(5) << " " << std::hex << CMsgTr.getAt(4) << std::endl; 00651 } 00652 else 00653 { 00654 short CurrState = ((CMsgTr.getAt(7)<<8)|CMsgTr.getAt(6)); 00655 //std::cout << CurrState << std::endl; 00656 00657 // bits 0-3 and 5-6 displays state of the motorcontoller 00658 00659 // Not_Ready_To_Switch_On (bit 5 doesn't matter) 00660 if ((CurrState & 0x004F)==0) 00661 { std::cout << "MotorState: Not_Ready_To_Switch_On" << std::endl; } 00662 00663 // Switch_On_Disabled (bit 5 doesn't matter) 00664 if ((CurrState & 0x004F)==0x0040) 00665 { std::cout << "MotorState: Switch_On_Disabled" << std::endl; } 00666 00667 // Ready_To_Switch_On 00668 if ((CurrState & 0x006F)==0x0021) 00669 { std::cout << "MotorState: Ready_To_Switch_On" << std::endl; } 00670 00671 // Switched_On 00672 if ((CurrState & 0x006F)==0x0023) 00673 { std::cout << "MotorState: Switched_On" << std::endl; } 00674 00675 // Operation_Enable 00676 if ((CurrState & 0x006F)==0x0027) 00677 { std::cout << "MotorState: Operation_Enable" << std::endl; } 00678 00679 // Fault (bit 5 doesn't matter) 00680 if ((CurrState & 0x004F)==0x0008) 00681 { std::cout << "MotorState: Fault" << std::endl; } 00682 00683 // Fault_Reaction_Active (bit 5 doesn't matter) 00684 if ((CurrState & 0x004F)==0x00F) 00685 { std::cout << "MotorState: Fault_Reaction_Active" << std::endl; } 00686 00687 // Quick_Stop_Active 00688 if ((CurrState & 0x006F)==0x0007) 00689 { std::cout << "MotorState: Quick_Stop_Active" << std::endl; } 00690 00691 // bit 4 displays the voltage state 00692 if ((CurrState & 0x0010)==0x0010) 00693 { std::cout << "voltage_enabled" << std::endl; } 00694 00695 // bit 7 displays if there are warnings 00696 if ((CurrState & 0x0080)==0x0080) 00697 { std::cout << "There are Warnings! Check!" << std::endl; } 00698 00699 // bit 8 is enabled if the drive moves 00700 if ((CurrState & 0x0100)==0x0100) 00701 { std::cout << "drive moves" << std::endl; } 00702 00703 // bit 9 is set when remote control via can is active 00704 if ((CurrState & 0x0200)==0x0200) 00705 { std::cout << "voltage_enabled" << std::endl; } 00706 00707 // bit 10 is set if target position is reached 00708 //(point in point mode, velocity in speed mode) 00709 if ((CurrState & 0x0400)==0x0400) 00710 { std::cout << "target reached" << std::endl; } 00711 00712 // bit 11 is set when internal limits are reached 00713 if ((CurrState & 0x0800)==0x0800) 00714 { std::cout << "internal limits reached" << std::endl; } 00715 00716 // bit 12 set_point_acknowladge / speed_0 / homing_attained / ip_mode_active 00717 if ((CurrState & 0x1000)==0x1000) 00718 { std::cout << "set_point_acknowladge / speed_0 / homing_attained / ip_mode_active" << std::endl; } 00719 00720 // bit 13 following_error / homing_error 00721 if ((CurrState & 0x2000)==0x2000) 00722 { std::cout << "following_error / homing_error" << std::endl; } 00723 00724 // bit 14 reserved 00725 00726 // bit 15 drive referenced 00727 if ((CurrState & 0x8000)==0x8000) 00728 { std::cout << "drive referenced" << std::endl; } 00729 } 00730 } 00731 00732 /* ============================================================== */ 00733 /* ====================== private =============================== */ 00734 /* ============================================================== */ 00735 00736 00737 00738 /*---------------------------------------------------------------*/ 00739 // handle CAN Error 00740 bool CANOpenMaster::CANError(CanMsg* CMsgTr) 00741 { 00742 // error case for SDOs 00743 if (CMsgTr->getAt(0) == 0x80) 00744 { 00745 ROS_INFO("Error on CAN request: %i %i %i %i", CMsgTr->getAt(4), CMsgTr->getAt(5), CMsgTr->getAt(6), CMsgTr->getAt(7)); 00746 return true; 00747 } 00748 00749 return false; 00750 } 00751 /*---------------------------------------------------------------*/ 00752 // Nodestate Error (test if heardbeat message has changed) 00753 bool CANOpenMaster::NodeStateError(CanMsg* CMsgTr) 00754 { 00755 // if Msg is Heartbeat 00756 if (CMsgTr->m_iID == HEARTBEAT) 00757 { 00758 //if Nodestate has changed send an error 00759 if (CMsgTr->getAt(0) != NodeState) 00760 { 00761 ROS_INFO("Error! CAN-Node %i not operational. State: %i", m_CanBaseAddress, CMsgTr->getAt(0)); 00762 return true; 00763 } 00764 //get next msg because heartbeat is evaluated 00765 can_itf->receiveMsg(CMsgTr); 00766 } 00767 00768 return false; 00769 } 00770 /*---------------------------------------------------------------*/ 00771 // read object from device 00772 unsigned int CANOpenMaster::ReadObject(CANOpenCiA401ObjDirectory::CANOpenObj* obj) 00773 { 00774 CanMsg CMsgTr; 00775 00776 int i, result = 0, timer = 0; 00777 00778 switch (obj->Format) 00779 { case 0x2F : CMsgTr.m_iLen = 5; 00780 case 0x2b : CMsgTr.m_iLen = 6; 00781 case 0x23 : CMsgTr.m_iLen = 8; 00782 } 00783 00784 CMsgTr.m_iID = RxSDO; 00785 00786 unsigned char cMsg[8]; 00787 00788 cMsg[0] = 0x40; //for read always 0x40 00789 cMsg[1] = obj->Index; // low byte 00790 cMsg[2] = obj->Index >> 8; // high byte 00791 cMsg[3] = obj->SubIndex; 00792 cMsg[4] = 0x00; 00793 cMsg[5] = 0x00; 00794 cMsg[6] = 0x00; 00795 cMsg[7] = 0x00; 00796 00797 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]); 00798 00799 if (can_itf->transmitMsg(CMsgTr) == 0) 00800 {throw -1; } 00801 00802 while(timer<1000) 00803 { 00804 can_itf->receiveMsg(&CMsgTr); 00805 00806 if (NodeStateError(&CMsgTr)) {throw -2;} 00807 00808 if (CANError(&CMsgTr)) {throw -3;} 00809 00810 if((CMsgTr.getAt(0) == (obj->Format+0x20) ) && (CMsgTr.getAt(1)==cMsg[1]) && (CMsgTr.getAt(2)==cMsg[2]) && (CMsgTr.getAt(3)==cMsg[3])) 00811 { 00812 for(i=4;i<CMsgTr.m_iLen;i++) 00813 { 00814 result += (CMsgTr.getAt(i) << (8*(i-4))); 00815 } 00816 return result; 00817 } 00818 timer++; 00819 usleep(1000); 00820 } 00821 CMsgTr.print(); 00822 throw -4; 00823 } 00824 00825 /*---------------------------------------------------------------*/ 00826 // write object on device 00827 int CANOpenMaster::WriteObject(CANOpenCiA401ObjDirectory::CANOpenObj* obj, int val) 00828 { 00829 CanMsg CMsgTr; 00830 00831 int timer = 0; 00832 00833 switch (obj->Format) 00834 { case 0x2F : CMsgTr.m_iLen = 5; 00835 case 0x2b : CMsgTr.m_iLen = 6; 00836 case 0x23 : CMsgTr.m_iLen = 8; 00837 } 00838 00839 CMsgTr.m_iID = RxSDO; 00840 00841 unsigned char cMsg[8]; 00842 00843 cMsg[0] = obj->Format; //for read always 0x40 00844 cMsg[1] = obj->Index; // low byte 00845 cMsg[2] = obj->Index >> 8; // high byte 00846 cMsg[3] = obj->SubIndex; 00847 cMsg[4] = val; 00848 if (CMsgTr.m_iLen > 5){cMsg[5] = val >> 8;}else{cMsg[5] = 0;} 00849 if (CMsgTr.m_iLen > 6){cMsg[6] = val >> 16; cMsg[7] = val >> 24;}else{cMsg[6] = 0,cMsg[7] = 0;} 00850 00851 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]); 00852 00853 if (can_itf->transmitMsg(CMsgTr) == 0) 00854 {return -1; } 00855 00856 // wait for ACK 00857 while(timer<1000) 00858 { 00859 can_itf->receiveMsg(&CMsgTr); 00860 00861 if (NodeStateError(&CMsgTr)) {return -2;} 00862 00863 if (CANError(&CMsgTr)) {return -3;} 00864 00865 if((CMsgTr.getAt(0) == 0x60) && (CMsgTr.getAt(1)==cMsg[1]) && (CMsgTr.getAt(2)==cMsg[2]) && (CMsgTr.getAt(3)==cMsg[3])) 00866 { 00867 // ACK 00868 return 0; 00869 } 00870 timer++; 00871 usleep(1000); 00872 } 00873 CMsgTr.print(); 00874 return -4; 00875 } 00876 00877 /*---------------------------------------------------------------*/ 00878 // write object PDO on bus 00879 int CANOpenMaster::WritePDO(CanMsg CMsgTr) 00880 { 00881 //CMsgTr.print(); 00882 if (can_itf->transmitMsg(CMsgTr) == 0) 00883 {return -1; } 00884 00885 return 0; 00886 } 00887 00888 /*---------------------------------------------------------------*/ 00889 // write object PDO on bus 00890 int CANOpenMaster::WritePDO(int ControlWord, int IP_command) 00891 { 00892 CanMsg CMsgTr; 00893 00894 CMsgTr.m_iID = RxPDO1; 00895 CMsgTr.m_iLen = 8; 00896 00897 unsigned char cMsg[8]; 00898 00899 cMsg[0] = (ControlWord >> 0); 00900 cMsg[1] = (ControlWord >> 8); 00901 cMsg[2] = 0; 00902 cMsg[3] = 0; 00903 cMsg[4] = (IP_command >> 0); 00904 cMsg[5] = (IP_command >> 8); 00905 cMsg[6] = (IP_command >> 16); 00906 cMsg[7] = (IP_command >> 24); 00907 00908 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]); 00909 00910 //CMsgTr.print(); 00911 if (can_itf->transmitMsg(CMsgTr) == 0) 00912 {return -1; } 00913 00914 // read Buffer for debug 00915 00916 if(can_itf->receiveMsg(&CMsgTr)!=0) 00917 {CMsgTr.print();} 00918 00919 return 0; 00920 } 00921 00922 00923 /*---------------------------------------------------------------*/ 00924 // send CAN-Network-Management commands to control the state-machine of the CAN-node 00925 void CANOpenMaster::SendNMT(unsigned char NodeID, unsigned char NMT_Command) 00926 { 00927 CanMsg CMsgTr; 00928 00929 CMsgTr.m_iLen = 2; 00930 CMsgTr.m_iID = 0x000; 00931 00932 unsigned char cMsg[2]; 00933 00934 cMsg[0] = NMT_Command; 00935 cMsg[1] = NodeID; 00936 00937 CMsgTr.set(cMsg[0], cMsg[1]); 00938 can_itf->transmitMsg(CMsgTr); 00939 } 00940 00941 /*---------------------------------------------------------------*/ 00945 int CANOpenMaster::WaitForHeartbeat() 00946 { 00947 CanMsg CMsgTr; 00948 int timer = 0; 00949 00950 while(timer<100) 00951 { can_itf->receiveMsg(&CMsgTr); 00952 if(CMsgTr.m_iID == HEARTBEAT) 00953 {return CMsgTr.getAt(0);} 00954 timer++; 00955 usleep(10000); 00956 } 00957 return -1; 00958 } 00959 00960 /*---------------------------------------------------------------*/ 00961 // sets global variables of controller state 00962 int CANOpenMaster::EvaluateControlerState() 00963 { 00964 int CurrState; 00965 00966 try {CurrState = ReadObject(&CANObj->statusword);} 00967 catch(int error){return error;} 00968 00969 // bits 0-3 and 5-6 displays state of the motorcontoller 00970 00971 // Not_Ready_To_Switch_On (bit 5 doesn't matter) 00972 if ((CurrState & 0x004F)==Not_Ready_To_Switch_On) 00973 { ControlerState = Not_Ready_To_Switch_On; 00974 std::cout << "MotorState: Not_Ready_To_Switch_On" << std::endl; } 00975 00976 // Switch_On_Disabled (bit 5 doesn't matter) 00977 if ((CurrState & 0x004F)==Switch_On_Disabled) 00978 { ControlerState = Switch_On_Disabled; 00979 std::cout << "MotorState: Switch_On_Disabled" << std::endl; } 00980 00981 // Ready_To_Switch_On 00982 if ((CurrState & 0x006F)==Ready_To_Switch_On) 00983 { ControlerState = Ready_To_Switch_On; 00984 std::cout << "MotorState: Ready_To_Switch_On" << std::endl; } 00985 00986 // Switched_On 00987 if ((CurrState & 0x006F)==Switched_On) 00988 { ControlerState = Switched_On; 00989 std::cout << "MotorState: Switched_On" << std::endl; } 00990 00991 // Operation_Enable 00992 if ((CurrState & 0x006F)==Operation_Enable) 00993 { ControlerState = Operation_Enable; 00994 std::cout << "MotorState: Operation_Enable" << std::endl; } 00995 00996 // Fault (bit 5 doesn't matter) 00997 if ((CurrState & 0x004F)==Fault) 00998 { ControlerState = Fault; 00999 std::cout << "MotorState: Fault" << std::endl; } 01000 01001 // Fault_Reaction_Active (bit 5 doesn't matter) 01002 if ((CurrState & 0x004F)==Fault_Reaction_Active) 01003 { ControlerState = Fault_Reaction_Active; 01004 std::cout << "MotorState: Fault_Reaction_Active" << std::endl; } 01005 01006 // Quick_Stop_Active 01007 if ((CurrState & 0x006F)==Quick_Stop_Active) 01008 { ControlerState = Quick_Stop_Active; 01009 std::cout << "MotorState: Quick_Stop_Active" << std::endl; } 01010 01011 // bit 4 displays the voltage state 01012 if ((CurrState & 0x0010)==0x0010) 01013 { std::cout << "voltage_enabled" << std::endl; } 01014 01015 // bit 7 displays if there are warnings 01016 if ((CurrState & 0x0080)==0x0080) 01017 { std::cout << "There are Warnings! Check!" << std::endl; } 01018 01019 // bit 8 is enabled if the drive moves 01020 if ((CurrState & 0x0100)==0x0100) 01021 { std::cout << "drive moves" << std::endl; } 01022 01023 // bit 9 is set when remote control via can is active 01024 if ((CurrState & 0x0200)==0x0200) 01025 { std::cout << "voltage_enabled" << std::endl; } 01026 01027 // bit 10 is set if target position is reached 01028 //(point in point mode, velocity in speed mode) 01029 if ((CurrState & 0x0400)==0x0400) 01030 { std::cout << "target reached" << std::endl; } 01031 01032 // bit 11 is set when internal limits are reached 01033 if ((CurrState & 0x0800)==0x0800) 01034 { std::cout << "internal limits reached" << std::endl; } 01035 01036 // bit 12 set_point_acknowladge / speed_0 / homing_attained / ip_mode_active 01037 if ((CurrState & 0x1000)==0x1000) 01038 { std::cout << "set_point_acknowladge / speed_0 / homing_attained / ip_mode_active" << std::endl; } 01039 01040 // bit 13 following_error / homing_error 01041 if ((CurrState & 0x2000)==0x2000) 01042 { std::cout << "following_error / homing_error" << std::endl; } 01043 01044 // bit 14 reserved 01045 01046 // bit 15 drive referenced 01047 if ((CurrState & 0x8000)==0x8000) 01048 { std::cout << "drive referenced" << std::endl; } 01049 01050 return 0; 01051 }