MOOS 0.2375
|
00001 00002 // 00003 // MOOS - Mission Oriented Operating Suite 00004 // 00005 // A suit of Applications and Libraries for Mobile Robotics Research 00006 // Copyright (C) 2001-2005 Massachusetts Institute of Technology and 00007 // Oxford University. 00008 // 00009 // This software was written by Paul Newman and others 00010 // at MIT 2001-2002 and Oxford University 2003-2005. 00011 // email: pnewman@robots.ox.ac.uk. 00012 // 00013 // This file is part of a MOOS Instrument. 00014 // 00015 // This program is free software; you can redistribute it and/or 00016 // modify it under the terms of the GNU General Public License as 00017 // published by the Free Software Foundation; either version 2 of the 00018 // License, or (at your option) any later version. 00019 // 00020 // This program is distributed in the hope that it will be useful, 00021 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00023 // General Public License for more details. 00024 // 00025 // You should have received a copy of the GNU General Public License 00026 // along with this program; if not, write to the Free Software 00027 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00028 // 02111-1307, USA. 00029 // 00031 // MOOSBluefinDriver.cpp: implementation of the CMOOSBluefinDriver class. 00032 // 00034 #include <MOOSLIB/MOOSLib.h> 00035 #include <iostream> 00036 #include <math.h> 00037 #include <sstream> 00038 #include "MOOSBluefinDriver.h" 00039 00040 #define BLUEFIN_UNKNOWN -1; 00041 #define BLUEFIN_THRUSTER 1 00042 #define BLUEFIN_RUDDER 2 00043 #define BLUEFIN_ELEVATOR 3 00044 #define BLUEFIN_MAX_ELEVATOR_ANGLE 18.0 00045 #define BLUEFIN_MAX_RUDDER_ANGLE 18.0 00046 00047 //this is for a 6 Mhz unit 00048 #define BLUEFIN_ZERO_THRUST 92 00049 #define BLUEFIN_FS_THRUST 40 00050 #define VOLTS_2_RPM 1.87 00051 #define BLUEFIN_THRUST_DEADZONE 10 00052 00053 00054 #define BLUEFIN_MID_ANALOG_STROKE 144.0 00055 #define ANALOG_2_COUNTS (4000.0/(248.0-67.0)) 00056 00057 //#define BLUEFIN_ACTUATOR_FS 1608.69 00059 // Construction/Destruction 00061 00062 CMOOSBluefinDriver::CMOOSBluefinDriver() 00063 { 00064 00065 m_nSelectedActuation = BLUEFIN_UNKNOWN; 00066 00067 00068 00069 } 00070 00071 CMOOSBluefinDriver::~CMOOSBluefinDriver() 00072 { 00073 00074 00075 } 00076 00077 00078 00079 bool CMOOSBluefinDriver::Initialise() 00080 { 00081 00082 00083 if(m_pPort != NULL ) 00084 { 00085 00086 STRING_LIST List; 00087 00088 //Initialization isn't really needed, but it would be nice to 00089 //see the result of this. The TT8 will spit out several lines of 00090 //initialization data, which can be turned off as needed. 00091 00092 //thruster 00093 List.push_back("BD1\r"); 00094 List.push_back("M92\r"); 00095 00096 00097 00098 00099 //rudder 00100 List.push_back("BD2\r"); 00101 // List.push_back("SD400\r"); 00102 List.push_back("SD300\r"); 00103 List.push_back("SA10\r"); 00104 // List.push_back("SM400\r"); 00105 00106 List.push_back("SM300\r"); 00107 List.push_back("SF\r"); 00108 List.push_back("SO\r"); 00109 00110 //elevator 00111 List.push_back("BD3\r"); 00112 List.push_back("SD400\r"); 00113 List.push_back("SA10\r"); 00114 List.push_back("SM400\r"); 00115 List.push_back("SF\r"); 00116 List.push_back("SO\r"); 00117 00118 STRING_LIST::iterator p; 00119 00120 for(p = List.begin();p!=List.end();p++) 00121 { 00122 string sCmd = *p; 00123 00124 string sReply; 00125 00126 if(m_pPort->IsVerbose()) 00127 { 00128 MOOSTrace("iActuation Init() : Sending %s \n",sCmd.c_str()); 00129 } 00130 //note bluefin tail cone does not reply to commands... 00131 //hence false 00132 if(!SendAndAck(sCmd,sReply,false)) 00133 { 00134 MOOSTrace("Failed command\n"); 00135 } 00136 MOOSPause(100); 00137 } 00138 } 00139 00140 HomeActuators(); 00141 00142 //Bluefin hardware requires passing through a true zero point 00143 //briefly reversing does this.... 00144 MOOSTrace("Energizing thruster..."); 00145 SetThrust(-2); 00146 MOOSPause(1000); 00147 SetThrust(0); 00148 00149 00150 MOOSTrace("OK\n"); 00151 00152 00153 00154 return true; 00155 } 00156 00157 00158 string CMOOSBluefinDriver::GetBoardSelectString(int nActuator) 00159 { 00160 switch(nActuator) 00161 { 00162 case BLUEFIN_THRUSTER: return "BD1\r"; 00163 case BLUEFIN_RUDDER: return "BD2\r"; 00164 case BLUEFIN_ELEVATOR: return "BD3\r"; 00165 default: 00166 MOOSTrace("Unknown board! Dummy!\n"); 00167 return "BD1\r"; 00168 } 00169 } 00170 00171 bool CMOOSBluefinDriver::SelectBoard(int nActuator) 00172 { 00173 if(m_nSelectedActuation==nActuator) 00174 return true; 00175 00176 string sReply; 00177 00178 string sBoard = GetBoardSelectString(nActuator); 00179 00180 //here we're checking to make sure the BD select command worked 00181 if(SendAndAck(sBoard,sReply,false)) 00182 { 00183 //read EEPROM location zero - contains board ID # 00184 bool bResult = SendAndAck("RE0\r",sReply,true); 00185 if(bResult) 00186 { 00187 int nBoard = atoi(sReply.c_str()); 00188 int nExpected = -1; 00189 switch(nActuator) 00190 { 00191 case BLUEFIN_THRUSTER: nExpected = 1;break; 00192 case BLUEFIN_RUDDER: nExpected = 2;break; 00193 case BLUEFIN_ELEVATOR: nExpected = 3;break; 00194 } 00195 if(nExpected!=nBoard) 00196 { 00197 MOOSTrace("Aw shucks board select didn't work\n\a"); 00198 m_nSelectedActuation = BLUEFIN_UNKNOWN; 00199 return false; 00200 } 00201 else MOOSTrace("Switched to board %d\n", nBoard); 00202 } 00203 else 00204 { 00205 MOOSTrace("No reply when reading board ID\n\a"); 00206 m_nSelectedActuation = BLUEFIN_UNKNOWN; 00207 return false; 00208 } 00209 m_nSelectedActuation = nActuator; 00210 return true; 00211 } 00212 else 00213 { 00214 m_nSelectedActuation = BLUEFIN_UNKNOWN; 00215 return false; 00216 } 00217 } 00218 00219 00220 bool CMOOSBluefinDriver::SetElevator(double dfAng,bool bAnalog) 00221 { 00222 00223 //return true; 00224 00225 00226 if(fabs(dfAng)>BLUEFIN_MAX_ELEVATOR_ANGLE) 00227 { 00228 dfAng = BLUEFIN_MAX_ELEVATOR_ANGLE*fabs(dfAng)/dfAng; 00229 } 00230 00231 00232 return MoveTo(BLUEFIN_ELEVATOR, dfAng+m_dfElevatorOffset,bAnalog); 00233 } 00234 00235 bool CMOOSBluefinDriver::SetRudder(double dfAng,bool bAnalog) 00236 { 00237 00238 if(fabs(dfAng)>BLUEFIN_MAX_RUDDER_ANGLE) 00239 { 00240 dfAng = BLUEFIN_MAX_RUDDER_ANGLE*fabs(dfAng)/dfAng; 00241 } 00242 00243 return MoveTo(BLUEFIN_RUDDER, dfAng+m_dfRudderOffset,bAnalog); 00244 } 00245 00246 bool CMOOSBluefinDriver::SetZeroElevator() 00247 { 00248 00249 00250 00251 return true; 00252 } 00253 00254 bool CMOOSBluefinDriver::SetZeroRudder() 00255 { 00256 00257 return true; 00258 } 00259 00260 bool CMOOSBluefinDriver::SetThrust(double dfPercent) 00261 { 00262 if(!SelectBoard(BLUEFIN_THRUSTER)) 00263 return false; 00264 00265 00266 int nThrust; 00267 00268 if(dfPercent>100) 00269 { 00270 dfPercent = 100.0; 00271 } 00272 if(dfPercent<-100) 00273 { 00274 dfPercent = -100.0; 00275 } 00276 00277 double dfOffset = dfPercent>0 ? 00278 BLUEFIN_THRUST_DEADZONE: 00279 -BLUEFIN_THRUST_DEADZONE; 00280 00281 if(dfPercent==0) 00282 dfOffset = 0; 00283 00284 nThrust = (int)((dfPercent/100.0)* BLUEFIN_FS_THRUST + BLUEFIN_ZERO_THRUST+dfOffset ); 00285 00286 if(nThrust<0) 00287 nThrust = 0; 00288 00289 //now format motor command 00290 stringstream os; 00291 os<<"M"<<nThrust<<"\r"<<ends; 00292 string sCmd = os.str(); 00293 00294 00295 string sReply; 00296 00297 if(!SendAndAck(sCmd,sReply,false)) 00298 return false; 00299 00300 00301 return true; 00302 00303 } 00304 00305 00306 00307 bool CMOOSBluefinDriver::HomeActuators() 00308 { 00309 //home rudder 00310 SetElevator(0,true); 00311 00312 //wait for it to get there.... 00313 MOOSTrace("Homing elevator..."); 00314 MOOSPause(2000); 00315 00316 //set this to encoder position zero... 00317 string sReply; 00318 string sCmd = "HM0\r"; 00319 SendAndAck(sCmd,sReply,false); 00320 00321 MOOSTrace("done\n"); 00322 00323 00324 //now do rudder 00325 SetRudder(0,true); 00326 00327 //wait for it to get there.... 00328 MOOSTrace("Homing rudder "); 00329 MOOSPause(2000); 00330 00331 //set this to encoder position zero... 00332 sCmd = "HM0\r"; 00333 SendAndAck(sCmd,sReply,false); 00334 00335 MOOSTrace("done\n"); 00336 00337 00338 return true; 00339 00340 00341 } 00342 00343 //bool CMOOSBluefinDriver::HomeActuator(int nActuator) 00344 //{ 00345 00346 // return true; 00347 //} 00348 00349 bool CMOOSBluefinDriver::GetAnalogReading(double & dfPosition) 00350 { 00351 string sReply; 00352 //stop immediately 00353 // SendAndAck("HI\r",sReply,false); 00354 00355 //ability to average analog reading.. 00356 int nMaxSamples = 4; 00357 int nSamples = 1; 00358 int nGood = 0; 00359 for(int n = 0;n<nMaxSamples && nGood<nSamples;n++) 00360 { 00361 string sCmd = "AD1\r"; 00362 if(!SendAndAck(sCmd,sReply,true)) 00363 { 00364 MOOSTrace("Failed Analog Read (try %d out of %d)\n\a",n+1,nMaxSamples); 00365 continue; 00366 } 00367 00368 double dfJustRead = atof(sReply.c_str()); 00369 00370 if(dfJustRead> 0) 00371 { 00372 dfPosition+= dfJustRead; 00373 nGood++; 00374 } 00375 else 00376 { 00377 MOOSTrace("Experience has shown not to trust 0 volts!\n\a"); 00378 } 00379 00380 00381 if(m_pPort->IsVerbose()) 00382 { 00383 MOOSTrace("AD1 reply = %s\n",sReply.c_str()); 00384 } 00385 00386 } 00387 00388 if(nGood==0) 00389 return false; 00390 00391 //unwrap.. 00392 dfPosition/=nGood; 00393 00394 return true; 00395 00396 } 00397 00398 bool CMOOSBluefinDriver::MoveTo(int nActuation, double dfAngle,bool bAnalog/*=false*/) 00399 { 00400 00401 if(!SelectBoard(nActuation)) 00402 return false; 00403 00404 double dfStepPosition = 0; 00405 00406 double dfAnalogRequired = AnalogFromAngle(nActuation,dfAngle,dfStepPosition); 00407 00408 if(bAnalog) 00409 { 00410 MOOSTrace("ANALOG!\n"); 00411 //figure out where we are... 00412 double dfAnalogPos =0; 00413 string sReply; 00414 SendAndAck("HI\r",sReply,false); 00415 00416 if(!GetAnalogReading(dfAnalogPos)) 00417 return false; 00418 00419 double dfAnalogError =dfAnalogRequired -dfAnalogPos; 00420 00421 if(fabs(dfAnalogError)<2) 00422 return true; 00423 00424 double dfCountsToMove = dfAnalogError*ANALOG_2_COUNTS; 00425 00426 //now format an incremental move.. 00427 stringstream os; 00428 os<<"II"<<(int)dfCountsToMove<<"\r"<<ends; 00429 string sCmd = os.str(); 00430 00431 00432 return SendAndAck(sCmd,sReply,false); 00433 } 00434 else 00435 { 00436 //now format an ABSOLUTE move.. 00437 MOOSTrace("NOT ANALOG\n"); 00438 string sReply; 00439 // SendAndAck("HI\r",sReply,false); 00440 // SendAndAck("RC\r",sReply,true); 00441 00442 if(fabs(dfStepPosition/ANALOG_2_COUNTS)<2) 00443 return true; 00444 00445 stringstream os; 00446 os<<"MI"<<(int)dfStepPosition<<"\r"<<ends; 00447 string sCmd = os.str(); 00448 return SendAndAck(sCmd,sReply,false); 00449 00450 } 00451 00452 /* 00453 static ofstream Hmmm; 00454 if(!Hmmm.is_open()) 00455 { 00456 Hmmm.open("HmmTest.txt"); 00457 } 00458 00459 if(nActuation == BLUEFIN_RUDDER) 00460 { 00461 Hmmm<<MOOSFormat("%.3f",MOOSTime()).c_str()<<" ERROR: "<<dfAnalogError<<" DPOS: "<< dfAngle<<" ANPOS: "<<dfAnalogPos <<endl; 00462 } 00463 */ 00464 00465 00466 00467 } 00468 00469 double CMOOSBluefinDriver::AnalogFromAngle(int nActuation, double dfAng,double & dfStepPosition) 00470 { 00471 double dfPercentRequired = 0; 00472 00473 dfAng*=-1; 00474 00475 double dfL1,dfL2,dfR0,dfTheta0; 00476 00477 //for now we assume that the offsets applied by being able to 00478 //call anywhere zero do not affect the follwing equations 00479 //as the trim angles are likely to be small. 00480 switch(nActuation) 00481 { 00482 case BLUEFIN_RUDDER: 00483 dfL1 = 0.333; 00484 dfL2 =0.075; 00485 dfR0 = 0.302; 00486 dfTheta0 = 1.045; 00487 // dfPercentRequired = dfAng/BLUEFIN_MAX_RUDDER_ANGLE*100; 00488 break; 00489 case BLUEFIN_ELEVATOR: 00490 dfL1 = 0.35; 00491 dfL2 =0.077; 00492 dfR0 = 0.311; 00493 dfTheta0 = 0.936; 00494 00495 // dfPercentRequired = dfAng/BLUEFIN_MAX_ELEVATOR_ANGLE*100; 00496 break; 00497 default: 00498 MOOSTrace("Only set stroke for rudder and elevator!\n"); 00499 return 0; 00500 } 00501 00502 double dfThetaCmd = MOOSDeg2Rad(dfAng)+dfTheta0; 00503 double dfRDes = sqrt(dfL1*dfL1-2*dfL1*dfL2*cos(dfThetaCmd)+dfL2*dfL2); 00504 dfStepPosition = (94488.189)*(dfRDes-dfR0); 00505 double dfAnalog = dfStepPosition/ANALOG_2_COUNTS+BLUEFIN_MID_ANALOG_STROKE; 00506 00507 return dfAnalog; 00508 } 00509 00510 double CMOOSBluefinDriver::GetRPM() 00511 { 00512 return 0; 00513 if(!SelectBoard(BLUEFIN_THRUSTER)) 00514 return 0; 00515 00516 string sReply; 00517 00518 int nDir = 1; 00519 if(SendAndAck("AD2\r",sReply,true)) 00520 { 00521 double dfdir = atof(sReply.c_str()); 00522 if(dfdir>0) 00523 { 00524 nDir = -1; 00525 } 00526 } 00527 00528 if(SendAndAck("AD1\r",sReply,true)) 00529 { 00530 double dfVoltage = atof(sReply.c_str()); 00531 00532 if(m_pPort->IsVerbose()) 00533 { 00534 MOOSTrace("RPM Voltage %f\n",dfVoltage); 00535 } 00536 00537 double dfRPM = Volts2RPM(dfVoltage); 00538 00539 return nDir*dfRPM; 00540 } 00541 00542 return 0; 00543 } 00544 00545 double CMOOSBluefinDriver::Volts2RPM(double dfVoltage) 00546 { 00547 //here we write a polynomial fit to experimental data 00548 //matlab used for fit 00549 00550 return VOLTS_2_RPM*dfVoltage; 00551 }