garcia_mixed.cc

00001 /*
00002  *  Player - One Hell of a Robot Server
00003  *  Copyright (C) 2000  Brian Gerkey et al.
00004  *
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00112 // ONLY if you need something that was #define'd as a result of configure
00113 // (e.g., HAVE_CFMAKERAW), then #include <config.h>, like so:
00114 /*
00115 #if HAVE_CONFIG_H
00116   #include <config.h>
00117 #endif
00118 */
00119 #include "garcia_mixed.h"
00120 
00121 #define DEG2RAD(x) (((double)(x))*0.01745329251994)
00122 #define RAD2DEG(x) (((double)(x))*57.29577951308232)
00123 
00124 #include <unistd.h>
00125 #include <string.h>
00126 #include <stdint.h>
00127 #include <sys/time.h>
00128 #include <time.h>
00129 #include <assert.h>
00130 #include <math.h>
00131 #include <stdio.h>
00132 using namespace std;
00133 
00134 #include <iostream> // only used for debugging, so remove when done
00135 
00136 const timespec NSLEEP_TIME = {0, 20000000}; // (0s, 20 ms) => max 50 hz
00137 
00139 // Now the driver
00140 
00141 // A factory creation function, declared outside of the class so that it
00142 // can be invoked without any object context (alternatively, you can
00143 // declare it static in the class).  In this function, we create and return
00144 // (as a generic Driver*) a pointer to a new instance of this driver.
00145 Driver*
00146 GarciaDriver_Init(ConfigFile* cf, int section)
00147 {
00148   // Create and return a new instance of this driver
00149   return ((Driver*)(new GarciaDriver(cf, section)));
00150 
00151 }
00152 
00153 // A driver registration function, again declared outside of the class so
00154 // that it can be invoked without object context.  In this function, we add
00155 // the driver into the given driver table, indicating which interface the
00156 // driver can support and how to create a driver instance.
00157 void
00158 GarciaDriver_Register(DriverTable* table)
00159 {
00160   table->AddDriver("garcia", GarciaDriver_Init);
00161 }
00162 
00164 // Constructor.  Retrieve options from the configuration file and do any
00165 // pre-Setup() setup.
00166 GarciaDriver::GarciaDriver(ConfigFile* cf, int section)
00167     : Driver(cf, section),
00168       mLength(0.28),
00169       mWidth(0.20),
00170       mWheelBase(0.182),
00171       mWheelRadius(0.1)
00172 {
00173   // Create position2d interface
00174   if (0 != cf->ReadDeviceAddr(&mPos2dAddr, section, "provides",
00175                               PLAYER_POSITION2D_CODE, -1, NULL))
00176   {
00177     PLAYER_ERROR("Could not read position2d ID ");
00178     SetError(-1);
00179     return;
00180   }
00181   if (0 != AddInterface(mPos2dAddr))
00182   {
00183     PLAYER_ERROR("Could not add position2d interface ");
00184     SetError(-1);
00185     return;
00186   }
00187 
00188   // Create ir interface
00189   if (0 != cf->ReadDeviceAddr(&mIrAddr, section, "provides",
00190                               PLAYER_IR_CODE, -1, NULL))
00191   {
00192     PLAYER_ERROR("Could not read ir ID ");
00193     SetError(-1);
00194     return;
00195   }
00196   if (0 != AddInterface(mIrAddr))
00197   {
00198     PLAYER_ERROR("Could not add ir interface ");
00199     SetError(-1);
00200     return;
00201   }
00202 
00203   // Create speech interface
00204   if (0 != cf->ReadDeviceAddr(&mSpeechAddr, section, "provides",
00205                               PLAYER_SPEECH_CODE, -1, NULL))
00206   {
00207     PLAYER_ERROR("Could not read speech ID ");
00208     SetError(-1);
00209     return;
00210   }
00211   if (0 != AddInterface(mSpeechAddr))
00212   {
00213     PLAYER_ERROR("Could not add speech interface ");
00214     SetError(-1);
00215     return;
00216   }
00217 
00218   // Create dio interface
00219   if (0 != cf->ReadDeviceAddr(&(mDioAddr),section,"provides",
00220                               PLAYER_DIO_CODE,-1,NULL))
00221   {
00222     PLAYER_ERROR("Could not read dio ID ");
00223     SetError(-1);
00224     return;
00225   }
00226   if (0 != AddInterface(mDioAddr))
00227   {
00228     PLAYER_ERROR("Could not add dio interface ");
00229     SetError(-1);
00230     return;
00231   }
00232 
00233   // Create power interface
00234   if (0 != cf->ReadDeviceAddr(&mPowerAddr,
00235                             section,
00236                             "provides",
00237                             PLAYER_POWER_CODE,
00238                             -1,
00239                             NULL))
00240   {
00241     PLAYER_ERROR("could not read power address");
00242     SetError(-1);
00243     return;
00244   }
00245 
00246   if (0 != AddInterface(mPowerAddr))
00247   {
00248     PLAYER_ERROR("could not add power interface");
00249     SetError(-1);
00250     return;
00251   }
00252 
00253   // Read options from the configuration file
00254   const char* portname = cf->ReadFilename(section, "portname", "ttyS0");
00255   int baudrate = cf->ReadInt(section, "baudrate", 38400);
00256 
00257   // let's just create the config file wherever we are:
00258   static FILE* config_file;
00259   config_file = fopen("garcia_api.config", "a+");
00260 
00261   fprintf(config_file, "portname=%s\n", portname);
00262   fprintf(config_file, "baudrate=%i\n", baudrate);
00263 
00264   mSpeed = static_cast<float>(cf->ReadFloat(section, "speed", 0.7f));
00265   mPitch = static_cast<float>(cf->ReadFloat(section, "pitch", 0.6f));
00266   mVolume = static_cast<float>(cf->ReadFloat(section, "volume", 1.0f));
00267 
00268   fclose(config_file);
00269 
00270   return;
00271 }
00272 
00273 GarciaDriver::~GarciaDriver()
00274 {
00275   // get rid of the Acroname config file
00276   //remove("garcia_api.config");
00277 }
00278 
00280 // Set up the device.  Return 0 if things go well, and -1 otherwise.
00281 int
00282 GarciaDriver::Setup()
00283 {
00284 
00285   cout << "Setting up Garcia driver" << flush;
00286   mGarcia = new acpGarcia;
00287 
00288   while (!mGarcia->getNamedValue("active")->getBoolVal())
00289   {
00290     cout << "." << flush;
00291     nanosleep(&NSLEEP_TIME, NULL);
00292   }
00293 
00294   // enable the IR sensors
00295   acpValue enable(1);
00296   mGarcia->setNamedValue("front-ranger-enable", &enable);
00297   mGarcia->setNamedValue("side-ranger-enable", &enable);
00298   mGarcia->setNamedValue("rear-ranger-enable", &enable);
00299 
00300 
00301   puts("finished!");
00302 
00303   // Start the device thread; spawns a new thread and executes
00304   // GarciaDriver::Main(), which contains the main loop for the driver.
00305   StartThread();
00306 
00307   return(0);
00308 }
00309 
00310 
00312 // Shutdown the device
00313 int
00314 GarciaDriver::Shutdown()
00315 {
00316   puts("Shutting Garcia driver down");
00317 
00318   // Stop and join the driver thread
00319   StopThread();
00320 
00321   // Here you would shut the device down by, for example, closing a
00322   // serial port.
00323 
00324   delete mGarcia;
00325 
00326   puts("Garcia driver has been shutdown");
00327 
00328   return(0);
00329 }
00330 
00332 // Main function for device thread
00333 void
00334 GarciaDriver::Main()
00335 {
00336 
00337   // The main loop; interact with the device here
00338   for(;;)
00339   {
00340     // test if we are supposed to cancel
00341     pthread_testcancel();
00342 
00343     // Go to sleep for a while (this is a polling loop)
00344     nanosleep(&NSLEEP_TIME, NULL);
00345 
00346     // Process incoming messages
00347     ProcessMessages();
00348 
00349     // Write outgoing data
00350     RefreshData();
00351 
00352   }
00353   return;
00354 }
00355 
00356 // Process an incoming message
00357 int
00358 GarciaDriver::ProcessMessage(QueuePointer & resp_queue,
00359                              player_msghdr* hdr,
00360                              void* data)
00361 {
00362   assert(resp_queue);
00363   assert(hdr);
00364   assert(data);
00365 
00366   if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD,
00367                            PLAYER_POSITION2D_CMD_POS, mPos2dAddr))
00368   {
00369     assert(hdr->size == sizeof(player_position2d_cmd_pos_t));
00370     ProcessPos2dPosCmd(hdr, *reinterpret_cast<player_position2d_cmd_pos_t *>(data));
00371     return(0);
00372   }
00373   if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD,
00374                            PLAYER_POSITION2D_CMD_VEL, mPos2dAddr))
00375   {
00376     assert(hdr->size == sizeof(player_position2d_cmd_vel_t));
00377     ProcessPos2dVelCmd(hdr, *reinterpret_cast<player_position2d_cmd_vel_t *>(data));
00378     return(0);
00379   }
00380   else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD,
00381                                 PLAYER_SPEECH_CMD_SAY, mSpeechAddr))
00382   {
00383     assert(hdr->size == sizeof(player_speech_cmd_t));
00384     ProcessSpeechCommand(hdr, *reinterpret_cast<player_speech_cmd_t *>(data));
00385     return(0);
00386   }
00387   else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_DATA,
00388                                 PLAYER_DIO_CMD_VALUES, mDioAddr))
00389   {
00390     assert(hdr->size == sizeof(player_dio_cmd_t));
00391     ProcessDioCommand(hdr, *reinterpret_cast<player_dio_cmd_t *>(data));
00392     return(0);
00393   }
00394   else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
00395                                 PLAYER_POSITION2D_REQ_GET_GEOM, mPos2dAddr))
00396   {
00397     ProcessPos2dGeomReq(hdr);
00398     return(0);
00399   }
00400   else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
00401                                 PLAYER_IR_REQ_POSE, mIrAddr))
00402   {
00403     ProcessIrPoseReq(hdr);
00404     return(0);
00405   }
00406   else
00407   {
00408     PLAYER_ERROR1("GarciaDriver received unknown message: %s", hdr->type);
00409   }
00410 
00411   return -1;
00412 }
00413 
00414 void
00415 GarciaDriver::ProcessPos2dPosCmd(player_msghdr_t* hdr,
00416                                  player_position2d_cmd_pos_t &data)
00417 {
00418   printf("Position commands currently not implemented\n");
00419 
00420 /*
00421   // this code could be used to implement the position control,
00422   // but it will need to be modified
00423 
00424   double rho(0),alpha(0),beta(0);
00425   double delta_x(0),delta_y(0);
00426   double v, omega;
00427   // To be locally exponentially stable:
00428   //  k_rho  > 0
00429   //  k_beta < 0
00430   //  k_alpha-k_rho > 0
00431 
00432   delta_x = x-mPosX;
00433   delta_y = y-mPosY;
00434 
00435   // If we're within 1 cm, stop (for now)
00436   if ((fabs(delta_x) > mTranslateDeadzone)||
00437       (fabs(delta_y) > mTranslateDeadzone)||
00438       (fabs(mPosTheta-theta) > mRotateDeadzone))
00439   {
00440     rho   = sqrt(pow(delta_x,2) + pow(delta_y,2));
00441 
00442     if (fabs(atan2(delta_y, delta_x) - mPosTheta) < M_PI/2)
00443     {
00444 
00445       alpha = atan2(delta_y,delta_x) - mPosTheta;
00446       alpha = fmod(alpha, M_PI_2); // M_PI/2 == M_PI_2
00447 
00448       beta  = -fmod(alpha,M_PI) - mPosTheta + theta;
00449       beta  = fmod(beta, M_PI);
00450 
00451       v     = mKRho * rho;
00452       omega = mKAlpha * alpha + mKBeta*beta;
00453     }
00454     else
00455     {
00456       alpha = atan2(-delta_y,-delta_x) - mPosTheta;
00457       alpha = fmod(alpha, M_PI_2); // M_PI/2 == M_PI_2
00458 
00459       beta  = -alpha - mPosTheta + theta;
00460       beta  = fmod(beta, M_PI);
00461 
00462       v     = -mKRho * rho;
00463       omega = mKAlpha * alpha + mKBeta*beta;
00464     }
00465 
00466     SetTargetVelocity(v, omega);
00467   }
00468   else
00469     SetTargetVelocity(0,0);
00470 */
00471 
00472 }
00473 
00474 void
00475 GarciaDriver::ProcessPos2dVelCmd(player_msghdr_t* hdr,
00476                                  player_position2d_cmd_vel_t &data)
00477 {
00478   double v(data.vel.px);
00479   double omega(data.vel.pa);
00480 
00481   acpValue vl(static_cast<float>(v - mWheelBase*omega/2.0));
00482   acpValue vr(static_cast<float>(v + mWheelBase*omega/2.0));
00483 
00484   mGarcia->setNamedValue("damped-speed-left", &vl);
00485   mGarcia->setNamedValue("damped-speed-right", &vr);
00486 
00487   // do we have to do this each time, or only once?
00488   acpObject* behavior;
00489   behavior = mGarcia->createNamedBehavior("null", "vel");
00490   mGarcia->queueBehavior(behavior);
00491 }
00492 
00493 void
00494 GarciaDriver::ProcessSpeechCommand(player_msghdr_t* hdr,
00495                                    player_speech_cmd_t &data)
00496 {
00497   // todo, there is currently a problem if we receive messages too quickly
00498   cout << data.string << endl;
00499 
00500   acpValue phrase(data.string);
00501   acpObject* behavior;
00502 
00503   behavior = mGarcia->createNamedBehavior("say", data.string);
00504   behavior->setNamedValue("phrase", &phrase);
00505   behavior->setNamedValue("speed", &mSpeed);
00506   behavior->setNamedValue("pitch", &mPitch);
00507   behavior->setNamedValue("volume", &mVolume);
00508   mGarcia->queueBehavior(behavior);
00509 }
00510 
00511 void
00512 GarciaDriver::ProcessDioCommand(player_msghdr_t* hdr,
00513                                 player_dio_cmd_t &data)
00514 {
00515   PLAYER_WARN("Garcia driver currently doesn't support DIO commands");
00516 }
00517 
00518 void
00519 GarciaDriver::ProcessPos2dGeomReq(player_msghdr_t* hdr)
00520 {
00521   player_position2d_geom_t geom;
00522 
00523   geom.pose.px = 0.03; // [m]
00524   geom.pose.py = 0.00; // [m]
00525   geom.pose.pa = 0;    // [rad]
00526   geom.size.sl = mLength;  // [m]
00527   geom.size.sw = mWidth;  // [m]
00528 
00529   Publish(mPos2dAddr,
00530           PLAYER_MSGTYPE_RESP_ACK,
00531           PLAYER_POSITION2D_REQ_GET_GEOM,
00532           &geom, sizeof(geom), NULL);
00533 }
00534 
00535 void
00536 GarciaDriver::ProcessIrPoseReq(player_msghdr_t* hdr)
00537 {
00538   player_pose_t poses[6] = {{ 0.105, 0.045, M_PI/6}, //   front-left
00539                             { 0.105,-0.045,-M_PI/6}, //   front-right
00540                             { 0.080, 0.020, M_PI_2}, //   side-left
00541                             { 0.080,-0.020,-M_PI_2}, //   side-right
00542                             {-0.050, 0.070, M_PI},   //   rear-left
00543                             {-0.050,-0.070,-M_PI}};  //   rear-right
00544 
00545   player_ir_pose_t pose;
00546   pose.poses_count = 6;
00547   pose.poses = new double[pose.poses_count];
00548   memcpy(pose.poses, poses, 6*sizeof(player_pose3d_t));
00549 
00550   Publish(mIrAddr,
00551           PLAYER_MSGTYPE_RESP_ACK,
00552           PLAYER_IR_REQ_POSE,
00553           &pose);
00554   delete [] pose.poses;
00555 
00556 }
00557 
00558 void
00559 GarciaDriver::RefreshData()
00560 {
00561   // how do we update these?
00562   mPos2dData.pos.px  = 0.0;
00563   mPos2dData.pos.py  = 0.0;
00564   mPos2dData.pos.pa  = 0.0;
00565 
00566   mPos2dData.vel.px  = 0.0;
00567   mPos2dData.vel.py  = 0.0;
00568   mPos2dData.vel.pa  = 0.0;
00569 
00570   Publish(mPos2dAddr,
00571           PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE,
00572           reinterpret_cast<void*>(&mPos2dData), sizeof(mPos2dData), NULL);
00573 
00574   // update the IR data
00575   mIrData.voltages_count = 0;
00576   mIrData.ranges_count = 6;
00577   mIrData.ranges = new double[mIrData.ranges_count];
00578   
00579   mIrData.ranges[0] = mGarcia->getNamedValue("front-ranger-left")->getFloatVal();
00580   mIrData.ranges[1] = mGarcia->getNamedValue("front-ranger-right")->getFloatVal();
00581   mIrData.ranges[2] = mGarcia->getNamedValue("side-ranger-left")->getFloatVal();
00582   mIrData.ranges[3] = mGarcia->getNamedValue("side-ranger-right")->getFloatVal();
00583   mIrData.ranges[4] = mGarcia->getNamedValue("rear-ranger-left")->getFloatVal();
00584   mIrData.ranges[5] = mGarcia->getNamedValue("rear-ranger-right")->getFloatVal();
00585 
00586   Publish(mIrAddr,
00587           PLAYER_MSGTYPE_DATA, PLAYER_IR_DATA_RANGES,
00588           reinterpret_cast<void*>(&mIrData));
00589   delete [] mIrData.ranges;
00590 
00591   // do we currently have a dio device?
00592   static int dio_test = 0;
00593   mDioData.count = 16;
00594   mDioData.digin = ++dio_test;
00595 
00596   Publish(mDioAddr,
00597           PLAYER_MSGTYPE_DATA, PLAYER_DIO_DATA_VALUES,
00598           reinterpret_cast<void*>(&mDioData), sizeof(mDioData), NULL);
00599 
00600   mPowerData.valid = PLAYER_POWER_MASK_VOLTS | PLAYER_POWER_MASK_PERCENT;
00601   mPowerData.volts = mGarcia->getNamedValue("battery-voltage")->getFloatVal();
00602   mPowerData.percent = mGarcia->getNamedValue("battery-level")->getFloatVal();
00603 
00604   Publish(mPowerAddr,
00605           PLAYER_MSGTYPE_DATA, PLAYER_POWER_DATA_STATE,
00606           reinterpret_cast<void*>(&mPowerData), sizeof(mPowerData), NULL);
00607 }

Last updated 12 September 2005 21:38:45