Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages | Examples

joydriveThreaded.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
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 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "Aria.h"
00027 
00028 /*
00029   This program just drives the robot around with a joystick.
00030 
00031   This example shows an example of a program making a thread for its own use 
00032   (reading the joystick and driving the robot), having the robot run in its
00033   own thread, and then keeping its main thread to itself.  Demonstrates the
00034   thread locking that must be done for threads to work safely.  If you don't
00035   know or understand threading, or you don't need threading, you probably 
00036   shouldn't do it this way, as it is more complicated.
00037 */
00038 
00039 /*
00040   This class creates its own thread, and then runs in the thread, controlling
00041   the robot with the joystick.
00042 */
00043 class Joydrive : public ArASyncTask
00044 {
00045 public:
00046   // constructor
00047   Joydrive(ArRobot *robot);
00048   // empty destructor
00049   ~Joydrive(void) {}
00050 
00051   // the function to run in the new thread, this just is called once, so 
00052   // only return when you want th ethread to exit
00053   virtual void * runThread(void *arg);
00054 
00055 protected:
00056   // joystick handler
00057   ArJoyHandler myJoyHandler;
00058   // robot pointer
00059   ArRobot *myRobot;
00060 };
00061 
00062 // a nice simple constructor
00063 Joydrive::Joydrive(ArRobot *robot)
00064 {
00065   setThreadName("Joydrive");
00066   // set the robot pointer
00067   myRobot = robot;
00068   // initialize the joystick
00069   myJoyHandler.init();
00070   // set up the joystick so we'll get the speeds out we want
00071   myJoyHandler.setSpeeds(40, 700);
00072 
00073   // see if we have a joystick, and let the users know
00074   if (myJoyHandler.haveJoystick())
00075   {
00076     printf("Have a joystick\n\n");
00077   }
00078   // if we don't have a joystick, then bomb out
00079   else
00080   {
00081     printf("Do not have a joystick, set up the joystick then rerun the program\n\n");
00082     Aria::shutdown();
00083     exit(0);    
00084   }
00085 
00086   // this is what creates are own thread, its from the ArASyncTask
00087   create();
00088 }
00089 
00090 // this is the function called in the new thread
00091 void *Joydrive::runThread(void *arg)
00092 {
00093   threadStarted();
00094 
00095   int trans, rot;
00096 
00097   // only run while running, ie play nice and pay attention to the thread 
00098   //being shutdown
00099   while (myRunning)
00100   {
00101     // lock the robot before touching it
00102     myRobot->lock();
00103     if (!myRobot->isConnected())
00104     {
00105       myRobot->unlock();
00106       break;
00107     }
00108     // print out some information about the robot
00109     printf("\rx %6.1f  y %6.1f  tth  %6.1f vel %7.1f mpacs %3d   ", 
00110        myRobot->getX(), myRobot->getY(), myRobot->getTh(), 
00111        myRobot->getVel(), myRobot->getMotorPacCount());
00112     fflush(stdout);
00113     // if one of the joystick buttons is pushed, drive the robot
00114     if (myJoyHandler.haveJoystick() && (myJoyHandler.getButton(1) ||
00115                     myJoyHandler.getButton(2)))
00116     {
00117       // get out the values from the joystick
00118       myJoyHandler.getAdjusted(&rot, &trans);
00119       // drive the robot
00120       myRobot->setVel(trans);
00121       myRobot->setRotVel(-rot);
00122     }
00123     // if no buttons are pushed stop the robot
00124     else
00125     {
00126       myRobot->setVel(0);
00127       myRobot->setRotVel(0);
00128     }
00129     // unlock the robot, so everything else can run
00130     myRobot->unlock();
00131     // now take a little nap
00132     ArUtil::sleep(50);
00133   }
00134   // return out here, means the thread is done
00135   return NULL;
00136 }
00137 
00138 /*
00139   This is a connection handler, fairly simple, but quite useful, esp when
00140   the robot is running in another thread. 
00141 */
00142 class ConnHandler
00143 {
00144 public:
00145   // constructor
00146   ConnHandler(ArRobot *robot, Joydrive *jd);
00147     // Destructor, its just empty
00148   ~ConnHandler(void) {}
00149   // to be called if the connection was made
00150   void connected(void);
00151   // to call if the connection failed
00152   void connFail(void);
00153   // to be called if the connection was lost
00154   void disconnected(void);
00155 protected:
00156   // robot pointer
00157   ArRobot *myRobot;
00158   // pointer to joydrive
00159   Joydrive *myJoydrive;
00160   // the functor callbacks
00161   ArFunctorC<ConnHandler> *myConnectedCB;
00162   ArFunctorC<ConnHandler> *myConnFailCB;
00163   ArFunctorC<ConnHandler> *myDisconnectedCB;
00164 
00165 };
00166 
00167 // the mythical constructor
00168 ConnHandler::ConnHandler(ArRobot *robot, Joydrive *jd) 
00169 {
00170   // set the pointers
00171   myRobot = robot;
00172   myJoydrive = jd;
00173 
00174   // now create the functor callbacks, then set them on the robot
00175   myConnectedCB = new ArFunctorC<ConnHandler>(this, &ConnHandler::connected);
00176   myRobot->addConnectCB(myConnectedCB, ArListPos::FIRST);
00177   myConnFailCB = new ArFunctorC<ConnHandler>(this, &ConnHandler::connFail);
00178   myRobot->addFailedConnectCB(myConnFailCB, ArListPos::FIRST);
00179   myDisconnectedCB = new ArFunctorC<ConnHandler>(this, 
00180                          &ConnHandler::disconnected);
00181   myRobot->addDisconnectNormallyCB(myDisconnectedCB, ArListPos::FIRST);
00182   myRobot->addDisconnectOnErrorCB(myDisconnectedCB, ArListPos::FIRST);
00183 }
00184 
00185 // when we connect turn off the sonar, turn on the motors, and disable amigobot
00186 // sound
00187 void ConnHandler::connected(void)
00188 {
00189   myRobot->comInt(ArCommands::SONAR, 0);
00190   myRobot->comInt(ArCommands::ENABLE, 1);
00191   myRobot->comInt(ArCommands::SOUNDTOG, 0);
00192 }
00193 
00194 // just exit if we failed to connect
00195 void ConnHandler::connFail(void)
00196 {
00197   printf("Failed to connect.\n");
00198   myRobot->stopRunning();
00199   myJoydrive->stopRunning();
00200   Aria::shutdown();
00201   return;
00202 }
00203 
00204 // if we lost connection then exit
00205 void ConnHandler::disconnected(void)
00206 {
00207   printf("Lost connection\n");
00208   myRobot->stopRunning();
00209   myJoydrive->stopRunning();
00210   Aria::shutdown();
00211   return;
00212 }
00213 
00214 int main(int argc, char **argv) 
00215 {
00216   std::string str;
00217   int ret;
00218 
00219   // connection to the robot
00220   ArTcpConnection con;
00221   // the robot
00222   ArRobot robot;
00223   
00224   // ake the joydrive object, which also creates its own thread
00225   Joydrive joyd(&robot);
00226   
00227   // the connection handler
00228   ConnHandler ch(&robot, &joyd);
00229 
00230   // init aria, which will make a dedicated signal handling thread
00231   Aria::init(Aria::SIGHANDLE_THREAD);
00232 
00233   // open the connection with default args, exit if it fails
00234   if ((ret = con.open()) != 0)
00235   {
00236     str = con.getOpenMessage(ret);
00237     printf("Open failed: %s\n", str.c_str());
00238     Aria::shutdown();
00239     return 1;
00240   }
00241 
00242 
00243   // set the connection on the robot
00244   robot.setDeviceConnection(&con);
00245 
00246   // run the robot in its own thread
00247   robot.runAsync(false);
00248   
00249   // have the robot connect asyncronously (so its loop is still running)
00250   // if this fails it means that the robot isn't running in its own thread
00251   if (!robot.asyncConnect())
00252   {
00253     printf(
00254     "asyncConnect failed because robot is not running in its own thread.\n");
00255     Aria::shutdown();
00256     return 1;
00257   }
00258 
00259   // now we just wait for the robot to be done running
00260   printf("Waiting for the robot's run to exit.\n");
00261   robot.waitForRunExit();
00262   // then we exit
00263   printf("exiting main\n");
00264   Aria::shutdown();
00265   return 0;
00266 }
00267 
00268 

Generated on Tue Feb 20 10:51:42 2007 for Aria by  doxygen 1.4.0