MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Instruments/Ocean/iActuation/MOOSJRKerrDriver.cpp
Go to the documentation of this file.
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 // MOOSJRKerrDriver.cpp: implementation of the CMOOSJRKerrDriver class.
00032 //
00033 // Driver for three JR Kerr / Kerr Automation Engineering
00034 // PIC-SERVO-3PH motor controllers in a tailcone for an Odyssey II class vehicle
00035 //
00036 // This code does some slightly non-portable things like assume ints
00037 // are always 32 bits and chars always 8 bits, but we'll live with it
00038 // for now.
00039 //
00040 // 2/2002 - jmorash@alum.mit.edu
00041 //
00043 #include <MOOSLIB/MOOSLib.h>
00044 #include <iostream>
00045 #include <fstream>
00046 #include <math.h>
00047 #include "MOOSJRKerrDriver.h"
00048 
00049 #define JRKERR_UNKNOWN -1;
00050 #define JRKERR_ADDR_INITIAL    0x00
00051 #define JRKERR_ADDR_GROUP      0xFF
00052 //these addresses reflect the wiring in the aft sphere
00053 #define JRKERR_ADDR_THRUSTER   0x01
00054 #define JRKERR_ADDR_RUDDER     0x02
00055 #define JRKERR_ADDR_ELEVATOR   0x03
00056 
00057 //Command bytes are: upper nibble = number of following Data bytes, lower nibble = command number
00058 #define JRKERR_RESET_POSITION       0x00
00059 #define JRKERR_SET_ADDRESS          0x21
00060 #define JRKERR_DEFINE_STATUS        0x12
00061 #define JRKERR_READ_STATUS          0x13
00062 #define JRKERR_LOAD_TRAJECTORY_POS  0xD4
00063 #define JRKERR_LOAD_TRAJECTORY_PWM  0x24
00064 #define JRKERR_START_MOTION         0x05
00065 #define JRKERR_SET_GAINS            0xD6
00066 #define JRKERR_STOP_MOTOR           0x17
00067 #define JRKERR_IO_CONTROL           0x18
00068 #define JRKERR_SET_HOME_MODE        0x19
00069 #define JRKERR_SET_BAUD_RATE        0x1A
00070 #define JRKERR_CLEAR_BITS           0x0B
00071 #define JRKERR_SAVE_AS_HOME         0x0C
00072 #define JRKERR_NOP                  0x0E
00073 #define JRKERR_HARD_RESET           0x0F
00074 
00075 #define JRKERR_MAX_ELEVATOR_ANGLE 45
00076 #define JRKERR_MAX_RUDDER_ANGLE 45
00077 
00078 #define JRKERR_ENCODER_TICKS_PER_DEGREE 13.194
00079 
00080 #define JRKERR_FS_THRUST 255
00081 #define JRKERR_ZERO_THRUST 0
00082 
00083 #define HARDWARE_FAILURE_TO 4.0
00084 
00085 // Construction/Destruction
00087 
00088 CMOOSJRKerrDriver::CMOOSJRKerrDriver()
00089 {
00090     m_bMoveDone = true;
00091     m_sLogFileName="JRKerrLog.txt";
00092 
00093     //these will be changed by SyncLog()
00094     m_dfRudder = 0;
00095     m_dfElevator = 0;
00096     m_dfRudderOffset = 0;
00097     m_dfElevatorOffset = 0;
00098 }
00099 
00100 CMOOSJRKerrDriver::~CMOOSJRKerrDriver()
00101 {
00102 
00103 }
00104 
00105 void CMOOSJRKerrDriver::TraceKerrMessage(const char * pMsg,int nLen)
00106 {
00107 
00108 
00109     //print out command sent (hex values)
00110     if(m_pPort->IsVerbose())
00111     {
00112 
00113         MOOSTrace("Sent %02X: %02X", (unsigned char)pMsg[1], (unsigned char)pMsg[2]);
00114         //print Data bytes, but not checksum
00115         for (int i=3; i < (nLen-1); i++)
00116         {
00117             MOOSTrace(" %02X", (unsigned char)pMsg[i]);
00118         }
00119         MOOSTrace("\n");
00120     }
00121 }
00122 
00123 bool CMOOSJRKerrDriver::SendCmd(int addr, int nCmd, const char *Data)
00124 {
00125     //This function assembles, checksums and sends commands, then
00126     //deals with the returned status byte(s)
00127 
00128     int nDataLen=0;
00129     int nRead=0;
00130     char nStatByte=0;
00131     char str[32]="";
00132 
00133 
00134     char status[5]="";
00135 
00136     //Commands always start with 0xAA, followed by the module address,
00137     //then the command byte, then the associated Data bytes, then the
00138     //checksum.  Data length is implicit in the upper nibble of the
00139     //command byte. Checksum does not include the preamble (0xAA).
00140 
00141     nDataLen = (((unsigned char)nCmd & 0xF0) >> 4) & 0x0F;
00142 
00143     char Tx[100];
00144     int nNdx = 0;
00145     Tx[nNdx++] = (char)0xAA;
00146     Tx[nNdx++] = addr;
00147     Tx[nNdx++] = nCmd;
00148     int i=0;
00149     for (i=0;i<nDataLen;i++)
00150     {
00151         //send Data bytes
00152         Tx[nNdx++] = Data[i];
00153     }
00154 
00155     //now figure checksum. it's an 8bit wraparound 2's complement sum
00156     char cCheckSum = 0;
00157     for(i = 1;i<nNdx;i++)
00158     {
00159         cCheckSum+=Tx[i];
00160     }
00161 
00162     //append
00163     Tx[nNdx++] = cCheckSum;
00164 
00165     //write
00166     m_pPort->Write(Tx,nNdx);
00167     TraceKerrMessage(Tx,nNdx);
00168 
00169     //now deal with the returned Data.
00170     //first handle the initial status byte, which is always there.
00171 
00172     nRead = m_pPort->ReadNWithTimeOut(status,1);
00173     if (nRead > 0)
00174     {
00175         nStatByte = status[0];
00176     }
00177     else if (nCmd != JRKERR_HARD_RESET)
00178     {
00179         MOOSTrace("No response from JRKerr controller.\n");
00180         return false;
00181     }
00182 
00183     //then, if we're reading extra info,
00184 
00185     if (nCmd==JRKERR_READ_STATUS)
00186     {
00187         if (Data[0] & 0x20)
00188         {
00189             nRead = m_pPort->ReadNWithTimeOut(status,2);
00190 
00191             if (nRead > 0)
00192             {
00193                 MOOSTrace("%02X: found device type %2d, version %2d\n", addr, status[0], status[1]);
00194             }
00195             else
00196             {
00197                 MOOSTrace("Error reading device type and version\n");
00198             }
00199         }
00200     }
00201 
00202     //finally, read the status cksum
00203     nRead = m_pPort->ReadNWithTimeOut(status,1);
00204 
00205     if ((nRead <= 0) && (nCmd != JRKERR_HARD_RESET))
00206     {
00207         MOOSTrace("Error reading status checksum\n");
00208     }
00209     if (m_pPort->IsVerbose() && (nCmd!=JRKERR_HARD_RESET))
00210     {
00211         MOOSTrace("%02X replies: status 0x%02X\n", addr, (unsigned char)nStatByte);
00212     }
00213 
00214     if (nStatByte & 0x02)
00215     {
00216         MOOSTrace("Checksum error in last command\n");
00217     }
00218 
00219     if (nStatByte & 0x01)
00220     {
00221         m_bMoveDone = true;
00222     }
00223     else
00224     {
00225         m_bMoveDone = false;
00226     }
00227 
00228     return true;
00229 }
00230 
00231 
00232 bool CMOOSJRKerrDriver::LogPosition()
00233 {
00234     //clobber open
00235     ofstream JRKerrLogFile;
00236 
00237     JRKerrLogFile.open(m_sLogFileName.c_str());
00238 
00239     if(JRKerrLogFile.is_open())
00240     {
00241         JRKerrLogFile<<"Rudder="<<m_dfRudder<<",Elevator="<<m_dfElevator<<endl;
00242 
00243         JRKerrLogFile.close();
00244     }
00245     return true;
00246 }
00247 
00248 
00249 bool CMOOSJRKerrDriver::SyncLog()
00250 {
00251     //gentle open
00252     ifstream JRKerrLogFile;
00253     JRKerrLogFile.open(m_sLogFileName.c_str());
00254 
00255     if(JRKerrLogFile.is_open())
00256     {
00257         string sLine;
00258         char Tmp[1000];
00259         JRKerrLogFile.getline(Tmp,sizeof(Tmp));
00260         sLine = string(Tmp);
00261         if(!sLine.empty())
00262         {
00263             MOOSRemoveChars(sLine," \t");
00264             string sRudder = MOOSChomp(sLine,",");
00265             MOOSChomp(sRudder,"Rudder=");
00266 
00267             m_dfKerrRudderOffset = atof(sRudder.c_str());
00268             m_dfRudder = m_dfKerrRudderOffset;
00269 
00270             string sElevator  = sLine;
00271             MOOSChomp(sElevator,"Elevator=");
00272             m_dfKerrElevatorOffset = atof(sElevator.c_str());
00273 
00274             m_dfElevator = m_dfKerrElevatorOffset;
00275         }
00276         JRKerrLogFile.close();
00277     }
00278     return true;
00279 }
00280 
00281 
00282 
00283 bool CMOOSJRKerrDriver::Initialise()
00284 {
00285 
00286     if(m_pPort==NULL)
00287         return false;
00288 
00289     //we keep a log file so fin position
00290     //is known if the driver crashes.
00291     SyncLog();
00292 
00293     if(m_pPort->IsVerbose())
00294     {
00295         MOOSTrace("iActuation Init() : Sending JRKerr init commands\n");
00296     }
00297 
00298     //First we send 16 null bytes, wait 'at least 1 ms' and flush the rx buffer
00299     //on the device
00300     for (int i=0; i<16; i++)
00301     {
00302         m_pPort->Write("\x00", 1);
00303     }
00304     MOOSPause(1);
00305 
00306     m_pPort->Flush();
00307 
00309     //              now send the commands
00311     char Data[14]="";
00312     bool bInitOK = true;
00313 
00314     //first, reset to powerup state
00315     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_GROUP, JRKERR_HARD_RESET, "\x00");
00316 
00317     //set addresses
00318     Data[0]=JRKERR_ADDR_THRUSTER;
00319     Data[1]=(char) 0xFF;
00320     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_INITIAL, JRKERR_SET_ADDRESS, Data);
00321 
00322     Data[0]=JRKERR_ADDR_RUDDER;
00323     Data[1]=(char)0xFF;
00324     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_INITIAL, JRKERR_SET_ADDRESS, Data);
00325 
00326     Data[0]=JRKERR_ADDR_ELEVATOR;
00327     Data[1]=(char)0xFF;
00328     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_INITIAL, JRKERR_SET_ADDRESS, Data);
00329 
00330     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_THRUSTER, JRKERR_READ_STATUS, "\x20");
00331 
00332     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_RUDDER, JRKERR_READ_STATUS, "\x20");
00333 
00334     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_ELEVATOR, JRKERR_READ_STATUS, "\x20");
00335 
00336     //Set PID gains. Kp=5000, Kd=1000, Ki=0, IntLimit=0,
00337     //OutputLimit=255, CurrentLimit=0, ErrorLimit=10000, ServoRate=1
00338     //are fine values for all three actuators.
00339     //Multi-byte values are sent LSB first.
00340 
00341     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_THRUSTER, JRKERR_SET_GAINS, "\x88\x13"
00342         "\xE8\x03"
00343         "\x00\x00"
00344         "\x00\x00"
00345         "\xFF"
00346         "\x00"
00347         "\x10\x27"
00348         "\x01");
00349 
00350     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_RUDDER, JRKERR_SET_GAINS,
00351         "\x88\x13\xE8\x03\x00\x00\x00\x00\xFF\x00\x10\x27\x01");
00352 
00353     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_ELEVATOR, JRKERR_SET_GAINS,
00354         "\x88\x13\xE8\x03\x00\x00\x00\x00\xFF\x00\x10\x27\x01");
00355 
00356     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_THRUSTER, JRKERR_STOP_MOTOR, "\x01");
00357 
00358     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_RUDDER, JRKERR_STOP_MOTOR, "\x01");
00359 
00360     bInitOK = bInitOK && SendCmd(JRKERR_ADDR_ELEVATOR, JRKERR_STOP_MOTOR, "\x01");
00361 
00362 
00363 
00364     if (!bInitOK)
00365     {
00366         MOOSTrace("JRKerr init failed!\n");
00367         return false;
00368     }
00369     else
00370     {
00371         MOOSTrace("JRKerr init OK\n");
00372         return true;
00373     }
00374 }
00375 
00376 
00377 bool CMOOSJRKerrDriver::DoPositionMove(int position, int velocity, int acceleration, int address)
00378 {
00379     char nCmd[13]="";
00380 
00381     //wait until the previous move is complete.
00382     double dfTimeWaited = 0;
00383     while(!m_bMoveDone)
00384     {
00385         //this will set the m_bMoveDone flag when it's done moving - NOP just returns a status byte
00386         SendCmd(address, JRKERR_NOP, "\x00");
00387         MOOSPause(10);
00388         dfTimeWaited+=0.01;
00389 
00390         if(  dfTimeWaited>HARDWARE_FAILURE_TO)
00391         {
00392             MOOSTrace("JRKerr HW not responding! FAILED MOVE ASSUMED\n");
00393             return false;
00394         }
00395     }
00396 
00397     //command byte, then 4bytes pos, 4b vel, 4b accel
00398     //command byte = 10010111: start now, pos mode, load p,v,a
00399     nCmd[0]=(char)0x97;
00400     //now for some crazy fun byte-noodling. Send LSB first.
00401     nCmd[1]=(position & 0x000000FF);
00402     nCmd[2]=(position & 0x0000FF00)>>8;
00403     nCmd[3]=(position & 0x00FF0000)>>16;
00404     nCmd[4]=(position & 0xFF000000)>>24;
00405     nCmd[5]=(velocity & 0x000000FF);
00406     nCmd[6]=(velocity & 0x0000FF00)>>8;
00407     nCmd[7]=(velocity & 0x00FF0000)>>16;
00408     nCmd[8]=(velocity & 0xFF000000)>>24;
00409     nCmd[9]=(acceleration & 0x000000FF);
00410     nCmd[10]=(acceleration & 0x0000FF00)>>8;
00411     nCmd[11]=(acceleration & 0x00FF0000)>>16;
00412     nCmd[12]=(acceleration & 0xFF000000)>>24;
00413 
00414     return SendCmd(address, JRKERR_LOAD_TRAJECTORY_POS, nCmd);
00415 }
00416 
00417 bool CMOOSJRKerrDriver::SetElevator(double dfAng)
00418 {
00419 
00420 
00421     //velocity and acceleration found by experiment, seem to work OK
00422     int position=0, velocity=100000, acceleration=100;
00423 
00424     if (dfAng > JRKERR_MAX_ELEVATOR_ANGLE)
00425     {
00426         dfAng = JRKERR_MAX_ELEVATOR_ANGLE;
00427     }
00428     if (dfAng < -JRKERR_MAX_ELEVATOR_ANGLE)
00429     {
00430         dfAng = -JRKERR_MAX_ELEVATOR_ANGLE;
00431     }
00432     position = int((dfAng - m_dfKerrElevatorOffset) * JRKERR_ENCODER_TICKS_PER_DEGREE);
00433     m_dfElevator = dfAng;
00434     LogPosition();
00435 
00436     return DoPositionMove(position, velocity, acceleration, JRKERR_ADDR_ELEVATOR);
00437 }
00438 
00439 bool CMOOSJRKerrDriver::SetRudder(double dfAng)
00440 {
00441 
00442 
00443 
00444     //velocity and acceleration found by experiment, seem to work OK
00445     int position=0, velocity=100000, acceleration=100;
00446 
00447     if (dfAng > JRKERR_MAX_RUDDER_ANGLE)
00448     {
00449         dfAng = JRKERR_MAX_RUDDER_ANGLE;
00450     }
00451     if (dfAng < -JRKERR_MAX_RUDDER_ANGLE)
00452     {
00453         dfAng = -JRKERR_MAX_RUDDER_ANGLE;
00454     }
00455     position = int((dfAng - m_dfKerrRudderOffset) * JRKERR_ENCODER_TICKS_PER_DEGREE);
00456     m_dfRudder = dfAng;
00457     LogPosition();
00458     return DoPositionMove(position, velocity, acceleration, JRKERR_ADDR_RUDDER);
00459 }
00460 
00461 bool CMOOSJRKerrDriver::SetZeroElevator()
00462 {
00463     m_dfElevator = 0;
00464     m_dfKerrElevatorOffset = 0;
00465     LogPosition();
00466     return SendCmd(JRKERR_ADDR_ELEVATOR, JRKERR_RESET_POSITION, "");
00467 }
00468 
00469 bool CMOOSJRKerrDriver::SetZeroRudder()
00470 {
00471 
00472     m_dfRudder = 0;
00473     m_dfKerrRudderOffset = 0;
00474     LogPosition();
00475     return SendCmd(JRKERR_ADDR_RUDDER, JRKERR_RESET_POSITION, "");
00476 }
00477 
00478 bool CMOOSJRKerrDriver::SetThrust(double dfPercent)
00479 {
00480 
00481     int nThrust;
00482     int nDirection=1; //1=fwd, 0=rev
00483     char nCmd[2]="";
00484 
00485     if(dfPercent>100)
00486     {
00487         dfPercent = 100.0;
00488     }
00489     if(dfPercent<-100)
00490     {
00491         dfPercent = -100.0;
00492     }
00493 
00494     nThrust = (int)((dfPercent/100.0) * JRKERR_FS_THRUST + JRKERR_ZERO_THRUST);
00495 
00496     if(nThrust<0) {
00497         nDirection=0;
00498         nThrust=-nThrust;
00499     }
00500 
00501     //control byte, then PWM byte
00502     //control byte = 0b1?001000 = start move now, PWM mode, ? = direction
00503 
00504     nCmd[0] = 0x88 | ((unsigned char)nDirection << 6);
00505     nCmd[1] = (unsigned char)nThrust;
00506 
00507     return SendCmd(JRKERR_ADDR_THRUSTER, JRKERR_LOAD_TRAJECTORY_PWM, nCmd);
00508 
00509 }
00510 
00511 
00512 double CMOOSJRKerrDriver::GetRPM()
00513 {
00514     return 0;
00515 }
00516 
00517 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines