traxbot_driverTest.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2012, ISR University of Coimbra.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of the ISR University of Coimbra nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: André Araújo, 2012
00036 *********************************************************************/
00037 
00038 
00040 //              TRAXBOT ROS DRIVE TESTS
00042 
00043 
00044 // STD LIB
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #include <math.h>
00048 #include <string.h>
00049 #include <unistd.h>
00050 
00051 
00052 
00053 // ROS LIB
00054 #include <ros/ros.h>                            // Includes all the headers necessary to use the most common public pieces of the ROS system.
00055 #include <ros/time.h>
00056 #include <std_msgs/String.h>
00057 #include <std_msgs/Float32.h>
00058 #include <std_msgs/Int8.h>
00059 #include <std_msgs/Int16.h>
00060 #include <std_msgs/Bool.h>
00061 #include <std_msgs/Empty.h>
00062 #include <geometry_msgs/Point32.h>
00063 #include <geometry_msgs/Pose2D.h>
00064 
00065 #define PI 3.1415
00066 
00067 float info_battery, info_driverF;
00068 int info_temp, range_msg1, range_msg2, range_msg3, encoderRead1, encoderRead2;
00069 
00070 int x=0, y=0, xTemp=0 , yTemp=0;
00071 float teta=0, tetaTemp=0;                       // global pose
00072 
00073 int xFinal=0, yFinal=0;
00074 float tetaFinal=0;                      // final pose
00075 
00076 float dist=0,alfa=0,phi=0;          // auxiliary variables of final pose
00077 
00078 float r_wheel=39.0, r_robot=185.0;   // robot's dimensions in [mm]
00079 
00080 int vMove = 25,  vRotate = 20;       // set speeds 
00081 
00082 
00083 int reactiveRange = 35;                  // range sonar limit 
00084 
00085 int samples = 10;
00086 float sonar1Samples[10], sonar2Samples[10], sonar3Samples[10]; 
00087 int counter1 = 0, counter2 = 0, counter3 = 0;
00088 
00089 /* Define publisher topics */
00090 
00091 // TraxBot INFO
00092 ros::Publisher pub_traxbotInfo;
00093 ros::Publisher pub_sonars;
00094 
00095 
00096 // TraxBot MOTORS
00097 ros::Publisher pub_moveMotors; 
00098 ros::Publisher pub_stopMotors;
00099 ros::Publisher pub_encodersReset; 
00100 ros::Publisher pub_encodersRead;
00101 
00102 // Driver
00103 ros::Publisher pub_odometry;
00104 
00105 
00106 /* Define subscriber topics */
00107 
00108 // TraxBot INFO  
00109 ros::Subscriber sub_driverFirmware;
00110 ros::Subscriber sub_batteryPower;
00111 ros::Subscriber sub_driverTemperature;
00112 
00113 // TraxBot MOTORS
00114 ros::Subscriber sub_encoderRead1;
00115 ros::Subscriber sub_encoderRead2;
00116 
00117 // SONARS
00118 ros::Subscriber sub_range1;
00119 ros::Subscriber sub_range2;
00120 ros::Subscriber sub_range3;
00121 
00122  
00123 float median(int n, float x[]) {                        // Median function to filter sonars reads  (n samples, x[] tab of values)
00124     float temp;
00125     int i, j;
00126     // the following two loops sort the array x in ascending order
00127     for(i=0; i<n-1; i++) {
00128         for(j=i+1; j<n; j++) {
00129             if(x[j] < x[i]) {
00130                 // swap elements
00131                 temp = x[i];
00132                 x[i] = x[j];
00133                 x[j] = temp;
00134             }
00135         }
00136     }
00137  
00138     if(n%2==0) {
00139         // if there is an even number of elements, return mean of the two elements in the middle
00140         return((x[n/2] + x[n/2 - 1]) / 2.0);
00141     } else {
00142         // else return the element in the middle
00143         return x[n/2];
00144     }
00145 }
00146 
00147 
00148 void enable_encodersRead() {    // Publish an empty msg to enable encoder 1 and 2 readings
00149 
00150   std_msgs::Empty enable1;
00151   pub_encodersRead.publish(enable1);
00152   ros::spinOnce();
00153 //   ROS_INFO("ENVIEI MSG ENCODERS");
00154 }
00155 
00156 
00157 void enable_encodersReset() {   // Publish an empty msg to enable reset encoders
00158   
00159   std_msgs::Empty enable2;
00160   pub_encodersReset.publish(enable2);
00161   ros::spinOnce();
00162   printf("ENCODERS RESET\n");
00163 }
00164 
00165 
00166 void enable_stopMotors() {      // Publish an empty msg to enable stop motors
00167   
00168   std_msgs::Empty enable3;
00169   pub_stopMotors.publish(enable3);
00170   ros::spinOnce();
00171   printf("STOP MOTORS\n");
00172 
00173 }
00174 
00175 void enable_infoData() {        // Publish an empty msg to enable arduino to send info data
00176   
00177   std_msgs::Empty enable4;
00178   pub_traxbotInfo.publish(enable4);
00179   ros::spinOnce();
00180 }
00181 
00182 
00183 
00184 void encoder1_readCB(const std_msgs::Int16::ConstPtr& pulses1) {                // Read subscribed msg of encoder 1 pulses
00185   
00186   encoderRead1 = pulses1->data; 
00187 //   ROS_INFO("ENCODER 1 CALLBACK: [%d]", encoderRead1);
00188 }
00189 
00190 void encoder2_readCB(const std_msgs::Int16::ConstPtr& pulses2) {                // Read subscribed msg of encoder 2 pulses
00191   
00192   encoderRead2 = pulses2->data;
00193 //   ROS_INFO("ENCODER 2 CALLBACK: [%d]", encoderRead2);
00194 }
00195 
00196 void batteryPowerCB(const std_msgs::Float32::ConstPtr& battery) {       // Read subscribed msg of battery info
00197 
00198   info_battery = battery->data;
00199 }
00200 
00201 void firmwareVersionCB(const std_msgs::Float32::ConstPtr& firmwareV) {  // Read subscribed msg of Omni3MD firmware version
00202 
00203   info_driverF = firmwareV->data;
00204 }
00205 
00206 void temperatureCB(const std_msgs::Int8::ConstPtr& temp) {      // Read subscribed msg of temperature info
00207 
00208   info_temp = temp->data;
00209 }
00210 
00211 void sonar1CB(const std_msgs::Int16::ConstPtr& sonar1) {        // Read subscribed msg of sonar 1 range
00212 
00213   range_msg1 = sonar1->data;
00214   
00215   sonar1Samples[counter1] = sonar1->data;               // Filter values
00216  
00217   if (counter1 == 0) {
00218    
00219    range_msg1 = sonar1Samples[0];
00220   
00221   }
00222   
00223   counter1++;
00224   
00225   if ( counter1 >= samples) {
00226       counter1=0;
00227       range_msg1 = int(floor(median(samples, sonar1Samples)));
00228   }
00229   
00230 }
00231 
00232 void sonar2CB(const std_msgs::Int16::ConstPtr& sonar2) {        // Read subscribed msg of sonar 2 range
00233 
00234   range_msg2 = sonar2->data;
00235   
00236   sonar2Samples[counter2] = sonar2->data;               // Filter values
00237  
00238   if (counter2 == 0) {
00239    
00240    range_msg2 = sonar2Samples[0];
00241   }
00242   
00243   counter2++;
00244   
00245   if ( counter2 >= samples) {
00246       counter2=0;
00247       range_msg2 = int(floor(median(samples, sonar2Samples)));
00248   }
00249   
00250 }
00251 
00252 void sonar3CB(const std_msgs::Int16::ConstPtr& sonar3) {        // Read subscribed msg of sonar 3 range
00253 
00254   range_msg3 = sonar3->data;
00255   
00256   
00257   sonar3Samples[counter3] = abs(sonar3->data);          // Filter values
00258  
00259   if (counter3 == 0) {
00260    
00261    range_msg3 = sonar3Samples[0];
00262   }
00263   
00264   counter3++;
00265   
00266   if ( counter3 >= samples) {
00267       counter3 = 0;
00268     range_msg3 = int(floor(median(samples, sonar3Samples)));
00269   }
00270   
00271   //ROS_INFO("Sonar 3: [%d]", range_msg3);
00272 }
00273 
00274 
00275 void moveMotors(int speed1, int speed2, int way) {                      // Move motors
00276   
00277   geometry_msgs::Point32 move;
00278   
00279   move.x = speed1;              // set speed motor 1   0 to 100
00280   move.y = speed2;              // set speed motor 2   0 to 100
00281   move.z = way;                 // 0= linear move,  1= rotate CCW (counterclockwise)   2= rotate CW (clockwise)
00282   
00283   pub_moveMotors.publish(move);
00284   ros::spinOnce();
00285   printf("START MOTORS\n");
00286  
00287 }
00288 
00289 bool powerCheck( float batteryValue) {
00290   bool check;
00291 
00292   if (batteryValue<=2) {
00293     
00294     check=0;
00295   } else {
00296     check=1;
00297   }
00298   
00299  return check;
00300    
00301 }
00302 
00303 float pulse2dist (int pulse) {          // Pulse to cm
00304  
00305  return ((pulse*1000)/11600); //11270 3cm  //11500 1cm //robot2
00306   
00307 }
00308 
00309 
00310 int encodersRead(){
00311   
00312   enable_encodersRead();
00313   ros::spinOnce();
00314   int enco1 = abs(encoderRead1);
00315   int enco2 = abs(encoderRead2);
00316   int enco=round((enco1+enco2)/2.0);
00317   
00318   return enco;
00319 }
00320 
00321 
00322 void calcOdometryDist(float dist, float alfa) {
00323   
00324   geometry_msgs::Pose2D odm;
00325   float D = dist;
00326   
00327   teta = tetaTemp + alfa;
00328         
00329   if (teta < -180) {
00330      teta+=360;
00331   }else if (teta > 180){
00332      teta-=360;         
00333   }
00334 
00335   x = xTemp + round(D*cos(teta * (PI/180)));
00336   y = yTemp + round(D*sin(teta * (PI/180)));
00337         
00338   tetaTemp = teta;
00339   xTemp = x;
00340   yTemp = y;
00341   
00342   odm.x = x;
00343   odm.y = y;
00344   odm.theta = teta;
00345   
00346   pub_odometry.publish(odm);
00347   ros::spinOnce();
00348 
00349   printf("GLOBAL ODOMETRY UPDATED x:%d y:%d theta:%f\n",x,y,teta);
00350 }
00351 
00352 
00353 void move(float dist, int speed1, int speed2)
00354 {
00355   long poss1=0, poss_dist=0, poss1_buf=0;
00356   int cnt = 0;
00357   
00358   printf("START MOVE()\n");
00359   
00360   poss_dist = dist;
00361   printf("Goal position %ld mm\n", poss_dist);
00362  
00363   moveMotors(speed1, speed2, 0);
00364   
00365   
00366   while(poss1 < poss_dist){                               // Start loop to drive motors forward
00367 
00368     usleep(100000);                                       // Very important: delay time necessary  to dont congest msgs
00369 
00370     poss1 = pulse2dist ( encodersRead() );
00371     printf("Actual distance: %ld\n",poss1);
00372     
00373     calcOdometryDist((poss1-poss1_buf), 0);
00374     poss1_buf = poss1;
00375   }
00376   
00377   printf("ARRIVE TO GOAL with more %d mm.\n", (poss1-poss_dist));
00378   
00379   usleep(100000);
00380   enable_stopMotors();
00381   ros::spinOnce();
00382 
00383   usleep(100000);
00384   enable_encodersReset();
00385   ros::spinOnce();
00386   
00387   while (cnt<5) {
00388     usleep(100000);
00389     enable_encodersRead();
00390     ros::spinOnce();
00391     ++cnt;
00392   }
00393   
00394   printf("FINISH MOVE()\n");
00395  
00396 } // END move()
00397 
00398 
00399 void rotate(float angle, int speed){
00400   
00401   int poss_dist=0, cnt=0, direction=1;
00402   float ang = 0, ang_buf=0;
00403   
00404   printf("START ROTATE()\n");
00405    
00406   if (angle != 0) {    
00407 
00408     poss_dist=((1750.0*angle)/360.0)*(r_robot/r_wheel);   
00409     
00410     printf("Goal position %d pulses. %f degrees\n", poss_dist,angle);
00411     
00412   
00413     while(abs(ang) <= abs(angle)){                       // Start loop to turn motors
00414       ++cnt;
00415       usleep(100000);                                     // Very important: delay time necessary  to dont congest msgs
00416       
00417       ang=(r_wheel/r_robot)*(poss_dist/abs(poss_dist))*encodersRead()*360.0/1750.0;
00418       
00419       printf("Actual angle: %f\n", ang);
00420       
00421        if (cnt<2) {
00422       
00423         if (poss_dist>0 ) {
00424           moveMotors(speed,speed,1);
00425           printf("Turn Left\n");
00426         } else {
00427           moveMotors(speed,speed,2);
00428           printf("Turn Right\n");
00429         }
00430       }
00431       
00432       calcOdometryDist(0.0, (ang-ang_buf));             // Update odometry
00433       ang_buf = ang;
00434       
00435     } // end while
00436   
00437   } // end 1st if
00438   
00439   if (ang <0 && ang!=0) {                       // Compensar VER NOS OUTROS ROBOS
00440       ang=ang+5;
00441       calcOdometryDist(0.0, (ang-ang_buf));     
00442   }
00443   
00444   if (ang >0 && ang!=0) {
00445       ang=ang-5;
00446       calcOdometryDist(0.0, (ang-ang_buf));
00447    }
00448   // calcOdometryDist(0.0, ang);
00449   printf("ARRIVE TO GOAL with more %f degrees\n", (ang-angle));
00450   
00451   usleep(100000);
00452   enable_stopMotors();
00453   ros::spinOnce();
00454   
00455   
00456   usleep(100000);
00457   enable_encodersReset();
00458   ros::spinOnce();
00459   
00460   cnt=0;
00461   while (cnt<5) {
00462     usleep(100000);
00463     enable_encodersRead();
00464     ros::spinOnce();
00465     ++cnt;
00466   }
00467   
00468   printf("FINISH ROTATE()\n");
00469 }
00470 
00471 
00472 void goTo(int x, int y, float teta, int xFinal, int yFinal, float tetaFinal){
00473    
00474   printf("START GO TO()\n");
00475   
00476   dist=sqrt(pow(xFinal-x,2)+pow(yFinal-y,2));
00477   alfa=atan2((yFinal-y),(xFinal-x))*180.0/PI;
00478   phi=alfa-teta;
00479               
00480   //1- ROTATE INTO THE FINAL POINT DIRECTION
00481   if (abs(phi)>180)
00482   {
00483    phi=phi-(abs(phi)/phi)*360.0;
00484   }
00485                   
00486                   
00487   printf("PHI ROTATION: %d \n", phi);
00488   rotate(phi,vRotate);
00489 
00490   //2- MOVE IN A STRAIGHT LINE
00491   printf("LINEAR MOVE: %d \n", dist);
00492   move(dist,vMove,vMove);
00493 
00494                 
00495   //3- ROTATE TO FINAL POSE
00496   phi=tetaFinal-alfa;
00497                           
00498   if (tetaFinal==0){ tetaFinal=190;}
00499                  
00500   if ((tetaFinal>-180) && (tetaFinal<=180))  {
00501     printf("FINAL ROTATION: %d \n", phi);
00502     rotate(phi,vRotate);
00503     teta=tetaFinal;
00504         
00505   }else{
00506       teta=alfa;
00507   }
00508   
00509   printf("FINISH GO TO()\n");                   
00510 }
00511 
00512 
00513 void squareTest(int side_width, int way, int cycles) {
00514   
00515   printf("START SQUARE TEST()\n");
00516   
00517   int cnt = 0;
00518   
00519   while (cnt < cycles) {
00520     
00521     switch (way) {      // way=0  CW (clockwise)      way=1  CCW (counterclockwise) 
00522     
00523       case 0:
00524   
00525         goTo(x,y,teta,0,side_width,0);
00526         goTo(x,y,teta,side_width,side_width,0);
00527         goTo(x,y,teta,side_width,0,0);
00528         goTo(x,y,teta,0,0,0);
00529         
00530 
00531         break;
00532     
00533       case 1:
00534         goTo(x,y,teta,side_width,0,0);
00535         goTo(x,y,teta,side_width,side_width,0);
00536         goTo(x,y,teta,0,side_width,0);
00537         goTo(x,y,teta,0,0,0);
00538           
00539         break;
00540       
00541       default:
00542         break;
00543     }
00544     ++cnt;
00545   }
00546   
00547   
00548   printf("FINISH SQUARE TEST()\n");
00549   
00550 }
00551 
00552 
00553 void reactiveNavigation() {
00554   
00555   int cnt = 0;
00556   
00557   while(cnt < 30000){                               // Start loop to drive motors forward
00558 
00559    moveMotors(vMove, vMove, 0);
00560    usleep(10000);                                         // Very important: delay time necessary  to dont congest msgs
00561    ros::spinOnce();     //IMPORTANT     
00562 
00563 
00564     ROS_INFO("Moving... Sonar1: [%d], Sonar2: [%d], Sonar3: [%d]\n",range_msg1,range_msg2,range_msg3);
00565     
00566     while (range_msg1 <= reactiveRange || range_msg2 <= reactiveRange || range_msg3 <= reactiveRange ) {
00567       
00568 
00569       ROS_INFO("Obstacle detected... Sonar1: [%d], Sonar2: [%d], Sonar3: [%d]\n",range_msg1,range_msg2,range_msg3);
00570       ros::spinOnce();
00571       
00572       
00573       if (range_msg3 <= range_msg2) {
00574         
00575          
00576                 while (range_msg1<=reactiveRange || range_msg3<=reactiveRange) {
00577                         usleep(10000);
00578                         rotate(10,vRotate);
00579 
00580                         ROS_INFO("ROTATION LEFT... Sonar1: [%d], Sonar2: [%d], Sonar3: [%d]\n",range_msg1,range_msg2,range_msg3);
00581                         ros::spinOnce();
00582                 }
00583  
00584           
00585                 } else  {
00586  
00587                 while (range_msg1<=reactiveRange || range_msg2<=reactiveRange) {
00588                       usleep(10000);
00589                       rotate(-10,vRotate);
00590                       ROS_INFO("ROTATION RIGHT... Sonar1: [%d], Sonar2: [%d], Sonar3: [%d]\n",range_msg1,range_msg2,range_msg3);
00591                       ros::spinOnce();
00592                 }
00593       }
00594       
00595      }
00596     ++cnt;
00597   }
00598   
00599   usleep(100000);
00600   enable_stopMotors();
00601   ros::spinOnce();
00602 
00603   usleep(100000);
00604   enable_encodersReset();
00605   ros::spinOnce();
00606   
00607 }
00608 
00609 
00610 void stepTest() {
00611         
00612         goTo(x,y,teta,400,0,0);
00613         goTo(x,y,teta,400,400,0);
00614         goTo(x,y,teta,800,400,0);
00615         goTo(x,y,teta,800,800,0);       
00616         goTo(x,y,teta,1200,800,0);
00617         goTo(x,y,teta,1200,1200,0);
00618 }
00619 
00620 
00621 int main(int argc, char** argv)
00622 {
00623   ros::init(argc, argv, "Traxbot_DriverTest");
00624   ros::NodeHandle nh;
00625 
00626   ROS_INFO("ROS in TraxBot: Start ROS driver test...");    // ROS_INFO(), replacement for printf/cout   
00627    
00628   
00629   /* Subscribe topics */
00630   sub_range1 = nh.subscribe("/sonar_traxbot_front", 1, sonar1CB);  
00631   sub_range2 = nh.subscribe("/sonar_traxbot_right", 1, sonar2CB);  
00632   sub_range3 = nh.subscribe("/sonar_traxbot_left", 1, sonar3CB);  
00633   sub_encoderRead1 = nh.subscribe("/encoderRead1", 1, encoder1_readCB);  
00634   sub_encoderRead2 = nh.subscribe("/encoderRead2", 1, encoder2_readCB);  
00635   sub_batteryPower = nh.subscribe("/batteryPower", 1, batteryPowerCB);  
00636   sub_driverTemperature = nh.subscribe("/driverTemperature", 1, temperatureCB);  
00637   sub_driverFirmware = nh.subscribe("/driverFirmware", 1, firmwareVersionCB);  
00638 
00639   /* Advertise topics */
00640   pub_moveMotors = nh.advertise<geometry_msgs::Point32>("/moveMotors", 1);
00641   pub_traxbotInfo = nh.advertise<std_msgs::Empty>("/traxbotInfo", 1);
00642   pub_sonars = nh.advertise<std_msgs::Empty>("/sonars", 1);
00643   pub_stopMotors = nh.advertise<std_msgs::Empty>("/stopMotors", 1);
00644   pub_encodersReset = nh.advertise<std_msgs::Empty>("/encodersReset", 1);
00645   pub_encodersRead = nh.advertise<std_msgs::Empty>("/encodersRead", 1);
00646   pub_odometry = nh.advertise<geometry_msgs::Pose2D>("/odometry", 1);
00647 
00648   ros::Rate loop_rate(10); //0.01 segundos 
00649   
00650   int count=0;
00651  
00652   
00653   
00654   while( ros::ok()){
00655     
00656     
00657     if (count <= 1) {           
00658       enable_encodersReset();
00659       enable_stopMotors();
00660     }
00661 
00662     if (count == 150) {
00663       
00664 
00665 //      move(distance, vMove, vMove);
00666 //      rotate(angle, vRotate);
00667 //      goTo(int x, int y, float teta, int xFinal, int yFinal, float tetaFinal)
00668 //      squareTest(1000, 0, 1);
00669 //      reactiveNavigation();
00670 //      stepTest();
00671       
00672     }
00673     
00674     printf("count: %d\n",count); 
00675     ++count;
00676     ros::spinOnce();
00677     loop_rate.sleep();
00678     
00679   }
00680    
00681 
00682 
00683     ROS_INFO("DONE");
00684 
00685 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


traxbot_robot
Author(s): André Gonçalves Araújo
autogenerated on Fri Feb 1 2013 13:21:12