khepera.cc

00001 /*
00002  *  Player - One Hell of a Robot Server
00003  *  Copyright (C) 2000  
00004  *     Brian Gerkey, Kasper Stoy, Richard Vaughan, & Andrew Howard
00005  *
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  */
00022 
00023 /* Copyright (C) 2004
00024  *   Toby Collett, University of Auckland Robotics Group
00025  */
00026 
00027 
00107 #include <fcntl.h>
00108 #include <signal.h>
00109 #include <sys/stat.h>
00110 #include <sys/types.h>
00111 #include <stdio.h>
00112 #include <string.h>
00113 #include <termios.h>
00114 #include <unistd.h>
00115 #include <math.h>
00116 #include <stdlib.h>  /* for abs() */
00117 #include <netinet/in.h>
00118 #include <ctype.h>
00119 
00120 #include <assert.h>
00121 
00122 #include <khepera.h>
00123 
00124 #include <libplayercore/playercore.h>
00125 #include <libplayerxdr/playerxdr.h>
00126 
00127 // we need to debug different things at different times
00128 //#define DEBUG_POS
00129 //#define DEBUG_SERIAL
00130 #define DEBUG_CONFIG
00131 
00132 // useful macros
00133 #define DEG2RAD(x) (((double)(x))*0.01745329251994)
00134 #define RAD2DEG(x) (((double)(x))*57.29577951308232)
00135 
00136 //#define DEG2RAD_FIX(x) ((x) * 17453)
00137 //#define RAD2DEG_FIX(x) ((x) * 57295780)
00138 #define DEG2RAD_FIX(x) ((x) * 174)
00139 #define RAD2DEG_FIX(x) ((x) * 572958)
00140 
00141 
00142 /* initialize the driver.
00143  *
00144  * returns: pointer to new REBIR object
00145  */
00146 Driver*
00147 Khepera_Init(ConfigFile *cf, int section)
00148 {
00149   return (Driver *) new Khepera( cf, section);
00150 }
00151 
00152 /* register the Khepera IR driver in the drivertable
00153  *
00154  * returns: 
00155  */
00156 void
00157 Khepera_Register(DriverTable *table) 
00158 {
00159   table->AddDriver("khepera", Khepera_Init);
00160 }
00161 
00162 int Khepera::ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr, void * data)
00163 {
00164         assert(hdr);
00165         assert(data);
00166 
00167         if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_IR_REQ_POSE, ir_addr))
00168         {
00169                 Publish(ir_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, hdr->subtype, &geometry->ir, sizeof(geometry->ir));
00170                 return 0;
00171         }
00172         else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL, position_addr))
00173         {
00174                 player_position2d_cmd_vel_t * poscmd = reinterpret_cast<player_position2d_cmd_vel_t *> (data);
00175 
00176                 // need to calculate the left and right velocities
00177                 int transvel = static_cast<int> (static_cast<int> (poscmd->vel.px) * geometry->encoder_res);
00178                 int rotvel = static_cast<int> (static_cast<int> (poscmd->vel.pa) * geometry->encoder_res * geometry->position.size.sw* geometry->scale);
00179                 int leftvel = transvel - rotvel;
00180                 int rightvel = transvel + rotvel;
00181 
00182                 // now we set the speed
00183                 if (this->motors_enabled) 
00184                         SetSpeed(leftvel,rightvel);
00185                 else 
00186                         SetSpeed(0,0);
00187                 return 0;
00188         }
00189         else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_GET_GEOM, position_addr))
00190         {
00191                 Publish(position_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, hdr->subtype, &geometry->position, sizeof(geometry->position));
00192                 return 0;
00193         }
00194         else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, position_addr))
00195         {
00196                 this->motors_enabled = ((player_position2d_power_config_t *)data)->state;
00197                 Publish(position_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK,hdr->subtype);
00198                 return 0;
00199         }
00200         else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, position_addr))
00201         {
00202                 Publish(position_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK,hdr->subtype);
00203                 return 0;
00204         }
00205         else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_RESET_ODOM, position_addr))
00206         {
00207                 ResetOdometry();
00208                 Publish(position_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK,hdr->subtype);
00209                 return 0;
00210         }
00211         else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SET_ODOM, position_addr))
00212         {
00213                 Publish(position_addr, resp_queue, PLAYER_MSGTYPE_RESP_NACK,hdr->subtype);
00214                 return 0;
00215         }
00216 
00217         return -1;
00218 }
00219 
00220 Khepera::Khepera(ConfigFile *cf, int section) : Driver(cf, section)
00221 {
00222   // zero ids, so that we'll know later which interfaces were requested
00223   memset(&position_addr, 0, sizeof(this->position_addr));
00224   memset(&ir_addr, 0, sizeof(ir_addr));
00225 
00226   this->position_subscriptions = this->ir_subscriptions = 0;
00227 
00228   // Do we create a robot position interface?
00229   if(cf->ReadDeviceAddr(&(this->position_addr), section, "provides", 
00230                       PLAYER_POSITION2D_CODE, -1, NULL) == 0)
00231   {
00232     if(this->AddInterface(this->position_addr) != 0)
00233     {
00234       this->SetError(-1);    
00235       return;
00236     }
00237   }
00238 
00239   // Do we create an ir interface?
00240   if(cf->ReadDeviceAddr(&(this->ir_addr), section, "provides", 
00241                       PLAYER_IR_CODE, -1, NULL) == 0)
00242   {
00243     if(this->AddInterface(this->ir_addr) != 0)
00244     {
00245       this->SetError(-1);    
00246       return;
00247     }
00248   }
00249 
00250   // Read config file options
00251   geometry = new player_khepera_geom_t;
00252   geometry->PortName= NULL;
00253   geometry->scale = 0;
00254 
00255   //set up the poll parameters... used for the comms
00256   // over the serial port to the Kam
00257   //write_pfd.events = POLLOUT;
00258   //read_pfd.events = POLLIN;
00259 
00260   // now we have to look up our parameters.  this should be given as an argument
00261   if (geometry->PortName == NULL)
00262     geometry->PortName = strdup(cf->ReadString(section, "port", KHEPERA_DEFAULT_SERIAL_PORT));
00263   if (geometry->scale == 0)
00264     geometry->scale = cf->ReadFloat(section, "scale_factor", KHEPERA_DEFAULT_SCALE);
00265 
00266   geometry->encoder_res = cf->ReadFloat(section,"encoder_res", KHEPERA_DEFAULT_ENCODER_RES);
00267 
00268   // Load position config
00269   geometry->position.pose.px = cf->ReadTupleFloat(section,"position_pose",0,0) * geometry->scale;
00270   geometry->position.pose.py = cf->ReadTupleFloat(section,"position_pose",1,0) * geometry->scale;
00271   geometry->position.pose.pyaw = cf->ReadTupleFloat(section,"position_pose",2,0) * geometry->scale;
00272 
00273   // load dimension of the base
00274   geometry->position.size.sw = cf->ReadTupleFloat(section,"position_size",0,57) * geometry->scale;
00275   geometry->position.size.sl = cf->ReadTupleFloat(section,"position_size",1,57) * geometry->scale;
00276 
00277   // load ir geometry config
00278   geometry->ir.poses_count = (cf->ReadInt(section,"ir_pose_count", 8));
00279   geometry->ir.poses = new player_pose3d_t[geometry->ir.poses_count];
00280   if (geometry->ir.poses_count == 8 && cf->ReadTupleFloat(section,"ir_poses",0,-1) == -1)
00281   {
00282     // load the default ir geometry
00283     geometry->ir.poses[0].px = 10/1000*geometry->scale;
00284     geometry->ir.poses[0].py = 24/1000*geometry->scale;
00285     geometry->ir.poses[0].pyaw = DTOR(90);
00286 
00287     geometry->ir.poses[1].px = 19/1000*geometry->scale;
00288     geometry->ir.poses[1].py = 17/1000*geometry->scale;
00289     geometry->ir.poses[1].pyaw = DTOR(45);
00290 
00291     geometry->ir.poses[2].px = 25/1000*geometry->scale;
00292     geometry->ir.poses[2].py = 6/1000*geometry->scale;
00293     geometry->ir.poses[2].pyaw = DTOR(0);
00294 
00295     geometry->ir.poses[3].px = 25/1000*geometry->scale;
00296     geometry->ir.poses[3].py = -6/1000*geometry->scale;
00297     geometry->ir.poses[3].pyaw = DTOR(0);
00298 
00299     geometry->ir.poses[4].px = 19/1000*geometry->scale;
00300     geometry->ir.poses[4].py = -17/1000*geometry->scale;
00301     geometry->ir.poses[4].pyaw = DTOR(-45);
00302 
00303     geometry->ir.poses[5].px = 10/1000*geometry->scale;
00304     geometry->ir.poses[5].py = -24/1000*geometry->scale;
00305     geometry->ir.poses[5].pyaw = DTOR(-90);
00306 
00307     geometry->ir.poses[6].px = -24/1000*geometry->scale;
00308     geometry->ir.poses[6].py = -10/1000*geometry->scale;
00309     geometry->ir.poses[6].pyaw = DTOR(180);
00310 
00311     geometry->ir.poses[7].px = -24/1000*geometry->scale;
00312     geometry->ir.poses[7].py = 10/1000*geometry->scale;
00313     geometry->ir.poses[7].pyaw = DTOR(180);
00314   }
00315   else
00316   {
00317     // laod geom from config file
00318     for (unsigned int i = 0; i < geometry->ir.poses_count; ++i)
00319     {
00320       geometry->ir.poses[i].px = cf->ReadTupleFloat(section,"ir_poses",3*i,0)*geometry->scale;
00321       geometry->ir.poses[i].py = cf->ReadTupleFloat(section,"ir_poses",3*i+1,0)*geometry->scale;
00322       geometry->ir.poses[i].pyaw = cf->ReadTupleFloat(section,"ir_poses",3*i+2,0);
00323     }                           
00324   }
00325   // laod ir calibration from config file
00326   geometry->ir_calib_a = new double[geometry->ir.poses_count];
00327   geometry->ir_calib_b = new double[geometry->ir.poses_count];
00328   for (unsigned int i = 0; i < geometry->ir.poses_count; ++i)
00329   {
00330     geometry->ir_calib_a[i] = cf->ReadTupleFloat(section,"ir_calib_a", i, KHEPERA_DEFAULT_IR_CALIB_A);
00331     geometry->ir_calib_b[i] = cf->ReadTupleFloat(section,"ir_calib_b", i, KHEPERA_DEFAULT_IR_CALIB_B);
00332   }
00333 
00334   // zero position counters
00335   last_lpos = 0;
00336   last_rpos = 0;
00337   last_x_f=0;
00338   last_y_f=0;
00339   last_theta = 0.0;
00340   
00341   
00342 }
00343 
00344 Khepera::~Khepera()
00345 {
00346   delete geometry->ir.poses;
00347   delete geometry->ir_calib_a;
00348   delete geometry->ir_calib_b;
00349   delete geometry;
00350 }
00351 
00352 int 
00353 Khepera::Subscribe(player_devaddr_t addr)
00354 {
00355   int setupResult;
00356 
00357   // do the subscription
00358   if((setupResult = Driver::Subscribe(addr)) == 0)
00359   {
00360     // also increment the appropriate subscription counter
00361     switch(addr.interf)
00362     {
00363       case PLAYER_POSITION2D_CODE:
00364         this->position_subscriptions++;
00365         break;
00366       case PLAYER_IR_CODE:
00367         this->ir_subscriptions++;
00368         break;
00369     }
00370   }
00371 
00372   return(setupResult);
00373 }
00374 
00375 int 
00376 Khepera::Unsubscribe(player_devaddr_t addr)
00377 {
00378   int shutdownResult;
00379 
00380   // do the unsubscription
00381   if((shutdownResult = Driver::Unsubscribe(addr)) == 0)
00382   {
00383     // also decrement the appropriate subscription counter
00384     switch(addr.interf)
00385     {
00386       case PLAYER_POSITION2D_CODE:
00387         assert(--this->position_subscriptions >= 0);
00388         break;
00389       case PLAYER_IR_CODE:
00390         assert(--this->ir_subscriptions >= 0);
00391         break;
00392     }
00393   }
00394 
00395   return(shutdownResult);
00396 }
00397 
00398 /* called the first time a client connects
00399  *
00400  * returns: 0 on success
00401  */
00402 int 
00403 Khepera::Setup()
00404 {
00405   // open and initialize the serial to -> Khepera  
00406   printf("Khepera: connection initializing (%s)...", this->khepera_serial_port);
00407   fflush(stdout);
00408   Serial = new KheperaSerial(geometry->PortName,KHEPERA_BAUDRATE);
00409   if (Serial == NULL || !Serial->Open())
00410   {
00411     return 1;
00412   }
00413   printf("Done\n");
00414 
00415   refresh_last_position = false;
00416   motors_enabled = false;
00417   velocity_mode = true;
00418   direct_velocity_control = false;
00419 
00420   desired_heading = 0;
00421 
00422   /* now spawn reading thread */
00423   StartThread();
00424   return(0);
00425 }
00426 
00427 
00428 int 
00429 Khepera::Shutdown()
00430 {
00431   printf("Khepera: SHUTDOWN\n");
00432   StopThread();
00433 
00434   // Killing the thread seems to leave out serial
00435   // device in a bad state, need to fix this,
00436   // till them we just dont stop the robot
00437   // which is theoretically quite bad...but this is the khepera...
00438   // it cant do that much damage its only 7cm across
00439   //SetSpeed(0,0);
00440   delete Serial;
00441   Serial = NULL;
00442 
00443   return(0);
00444 }
00445 
00446 void 
00447 Khepera::Main()
00448 {
00449   int last_position_subscrcount=0;
00450 
00451   pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
00452 
00453   while (1) 
00454   {
00455     // we want to reset the odometry and enable the motors if the first 
00456     // client just subscribed to the position device, and we want to stop 
00457     // and disable the motors if the last client unsubscribed.
00458     if(!last_position_subscrcount && this->position_subscriptions)
00459     {
00460       printf("Khepera: first pos sub. turn off and reset\n");
00461       // then first sub for pos, so turn off motors and reset odom
00462       SetSpeed(0,0);
00463       ResetOdometry();
00464 
00465     } 
00466     else if(last_position_subscrcount && !(this->position_subscriptions))
00467     {
00468       // last sub just unsubbed
00469       printf("Khepera: last pos sub gone\n");
00470       SetSpeed(0,0);
00471     }
00472     last_position_subscrcount = this->position_subscriptions;
00473 
00474 
00475         ProcessMessages();
00476     pthread_testcancel();
00477 
00478     // now lets get new data...
00479     UpdateData();
00480 
00481     pthread_testcancel();
00482   }
00483   pthread_exit(NULL);
00484 }
00485 
00486 
00487 
00488 /* this will update the data that is sent to clients
00489  * just call separate functions to take care of it
00490  *
00491  * returns:
00492  */
00493 void
00494 Khepera::UpdateData()
00495 {
00496   player_position2d_data_t position_data;
00497   player_ir_data_t ir_data;
00498   ir_data.ranges_count = geometry->ir.poses_count;
00499   ir_data.voltages_count = geometry->ir.poses_count;
00500   ir_data.ranges = new float[ir_data.ranges_count];
00501   ir_data.voltages = new float[ir_data.voltages_count];
00502 
00503   UpdatePosData(&position_data);
00504 
00505   // put position data
00506   Publish(position_addr,PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE, (unsigned char *) &position_data, sizeof(player_position2d_data_t),NULL);
00507 
00508   UpdateIRData(&ir_data);
00509 
00510   // put ir data
00511   Publish(position_addr,PLAYER_MSGTYPE_DATA, PLAYER_IR_DATA_RANGES, (unsigned char *) &ir_data, sizeof(ir_data),NULL);
00512   player_ir_data_t_cleanup(&ir_data);
00513 }
00514 
00515 /* this will update the IR part of the client data
00516  * it entails reading the currently active IR sensors
00517  * and then changing their state to off and turning on
00518  * 2 new IRs.  
00519  *
00520  * returns:
00521  */
00522 void
00523 Khepera::UpdateIRData(player_ir_data_t * d)
00524 {
00525   ReadAllIR(d);
00526 
00527   for (unsigned int i =0; i < geometry->ir.poses_count; i++) 
00528   {
00529     d->ranges[i] = geometry->scale * geometry->ir_calib_a[i] * pow(d->voltages[i],geometry->ir_calib_b[i]);
00530     d->voltages[i] = d->voltages[i];
00531   }
00532 }
00533 
00534   
00535 /* this will update the position data.  this entails odometry, etc
00536  */ 
00537 void
00538 Khepera::UpdatePosData(player_position2d_data_t *d)
00539 {
00540   // calculate position data
00541   int pos_left, pos_right;
00542   Khepera::ReadPos(&pos_left, &pos_right);
00543   int change_left = pos_left - last_lpos;
00544   int change_right = pos_right - last_rpos;
00545   last_lpos = pos_left;
00546   last_rpos = pos_right;
00547 
00548   double transchange = (change_left + change_right) * geometry->encoder_res / 2;
00549   double rotchange = (change_left - change_right) * geometry->encoder_res / 2;
00550 
00551   double dx,dy,Theta;
00552   double r = geometry->position.size.sw*geometry->scale/2;
00553 
00554   if (transchange == 0)
00555   {
00556     Theta = 360 * rotchange/(2 * M_PI * r);     
00557     dx = dy= 0;
00558   }
00559   else if (rotchange == 0)
00560   {
00561     dx = transchange;
00562     dy = 0;
00563     Theta = 0;
00564   }
00565   else
00566   {
00567     Theta = 360 * rotchange/(2 * M_PI * r);
00568     double R = transchange * r / rotchange;
00569     dy = R - R*cos(Theta*M_PI/180);
00570     dx = R*sin(Theta*M_PI/180);
00571   }
00572 
00573   // add code to read in the speed data
00574   int left_vel, right_vel;
00575   Khepera::ReadSpeed(&left_vel, &right_vel);
00576   double lv = left_vel * geometry->encoder_res;
00577   double rv = right_vel * geometry->encoder_res;
00578   double trans_vel = 100 * (lv + rv)/2;
00579   double rot_vel = (lv - rv)/2;
00580   double rot_vel_deg = 100 * 360 * rot_vel/(2 * M_PI * r);
00581 
00582   // now write data
00583   double rad_Theta = DTOR(yaw);
00584   x+=(dx*cos(rad_Theta) + dy*sin(rad_Theta));
00585   y+=(dy*cos(rad_Theta) + dx*sin(rad_Theta));
00586   d->pos.px = x/geometry->scale;
00587   d->pos.py = y/geometry->scale;
00588   yaw += Theta;
00589   while (yaw > 360) yaw -= 360;
00590   while (yaw < 0) yaw += 360;
00591   d->pos.pa = DTOR(yaw);
00592   d->vel.px = trans_vel/geometry->scale;
00593   d->vel.pa = DTOR(rot_vel_deg);
00594 }
00595 
00596 /* this will set the odometry to a given position
00597  * ****NOTE: assumes that the arguments are in network byte order!*****
00598  *
00599  * returns: 
00600  */
00601 int
00602 Khepera::ResetOdometry()
00603 {
00604   printf("Reset Odometry\n");
00605   int Values[2];
00606   Values[0] = 0;
00607   Values[1] = 0;
00608   if (Serial->KheperaCommand('G',2,Values,0,NULL) < 0)
00609     return -1;
00610 
00611   last_lpos = 0;
00612   last_rpos = 0;
00613 
00614   player_position2d_data_t data;
00615   memset(&data,0,sizeof(player_position2d_data_t));
00616   Publish(position_addr, PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE, &data, sizeof(data),NULL);
00617 
00618   x=y=yaw=0;
00619   return 0;
00620 }
00621 
00622 
00623 /* this will read the given AD channel
00624  *
00625  * returns: the value of the AD channel
00626  */
00627 /*unsigned short
00628 REB::ReadAD(int channel) 
00629 {
00630   char buf[64];
00631 
00632   sprintf(buf, "I,%d\r", channel);
00633   write_command(buf, strlen(buf), sizeof(buf));
00634   
00635   return atoi(&buf[2]);
00636 }*/
00637 
00638 /* reads all the IR values at once.  stores them
00639  * in the uint16_t array given as arg ir
00640  *
00641  * returns: 
00642  */
00643 int
00644 Khepera::ReadAllIR(player_ir_data_t* d)
00645 {
00646   int * Values;
00647 
00648   Values = new int [geometry->ir.poses_count];
00649   if(Serial->KheperaCommand('N',0,NULL,geometry->ir.poses_count,Values) < 0)
00650     return -1;                  
00651   for (unsigned int i=0; i< geometry->ir.poses_count; ++i)
00652   {
00653     d->voltages[i] = static_cast<short> (Values[i]);
00654   }
00655   delete [] Values;
00656   return 0;
00657 }
00658 
00659 /* this will set the desired speed for the given motor mn
00660  *
00661  * returns:
00662  */
00663 int
00664 Khepera::SetSpeed(int speed1, int speed2)
00665 {
00666         int Values[2];
00667         Values[0] = speed1;
00668         Values[1] = speed2;
00669         return Serial->KheperaCommand('D',2,Values,0,NULL);
00670 }
00671 
00672 /* reads the current speed of motor mn
00673  *
00674  * returns: the speed of mn
00675  */
00676 int
00677 Khepera::ReadSpeed(int * left,int * right)
00678 {
00679         int Values[2];
00680         if (Serial->KheperaCommand('E',0,NULL,2,Values) < 0)
00681                 return -1;
00682         *left = Values[0];
00683         *right = Values[1];
00684         return 0;
00685 }
00686 
00687 /* this sets the desired position motor mn should go to
00688  *
00689  * returns:
00690  */
00691 /*void
00692 REB::SetPos(int mn, int pos)
00693 {
00694   char buf[64];
00695   
00696   sprintf(buf,"C,%c,%d\r", '0'+mn,pos);
00697 
00698   write_command(buf, strlen(buf), sizeof(buf));
00699 }*/
00700 
00701 /* this sets the position counter of motor mn to the given value
00702  *
00703  * returns:
00704  */
00705 int
00706 Khepera::SetPosCounter(int pos1, int pos2)
00707 {
00708         int Values[2];
00709         Values[0] = pos1;
00710         Values[1] = pos2;
00711         return Serial->KheperaCommand('G',2,Values,0,NULL);
00712 }
00713 
00714 /* this will read the current value of the position counter
00715  * for motor mn
00716  *
00717  * returns: the current position for mn
00718  */
00719 int
00720 Khepera::ReadPos(int * pos1, int * pos2)
00721 {
00722         int Values[2];
00723         if (Serial->KheperaCommand('H',0,NULL,2,Values) < 0)
00724                 return -1;
00725         *pos1 = Values[0];
00726         *pos2 = Values[1];
00727         return 0;
00728 }
00729 
00730 /* this will configure the position PID for motor mn
00731  * using paramters Kp, Ki, and Kd
00732  *
00733  * returns:
00734  */
00735 /*void
00736 REB::ConfigPosPID(int mn, int kp, int ki, int kd)
00737 { 
00738   char buf[64];
00739 
00740   sprintf(buf, "F,%c,%d,%d,%d\r", '0'+mn, kp,ki,kd);
00741   write_command(buf, strlen(buf), sizeof(buf));
00742 }*/
00743 
00744 /* this will configure the speed PID for motor mn
00745  *
00746  * returns:
00747  */
00748 /*void
00749 REB::ConfigSpeedPID(int mn, int kp, int ki, int kd)
00750 {
00751   char buf[64];
00752   
00753   sprintf(buf, "A,%c,%d,%d,%d\r", '0'+mn, kp,ki,kd);
00754   
00755   write_command(buf, strlen(buf), sizeof(buf));
00756 }*/
00757 
00758 /* this will set the speed profile for motor mn
00759  * it takes the max velocity and acceleration
00760  *
00761  * returns:
00762  */
00763 /*void
00764 REB::ConfigSpeedProfile(int mn, int speed, int acc)
00765 {
00766   char buf[64];
00767   
00768   sprintf(buf, "J,%c,%d,%d\r", '0'+mn, speed,acc);
00769   write_command(buf, strlen(buf), sizeof(buf));
00770 }*/
00771 
00772 /* this will read the status of the motion controller.
00773  * mode is set to 1 if in position mode, 0 if velocity mode
00774  * error is set to the position/speed error
00775  *
00776  * returns: target status: 1 is on target, 0 is not on target
00777  */
00778 /*unsigned char
00779 Khepera::ReadStatus(int mn, int *mode, int *error)
00780 {
00781   char buf[64];
00782 
00783   sprintf(buf, "K,%c\r", '0'+mn);
00784   //write_command(buf, strlen(buf), sizeof(buf));
00785 
00786   // buf now has the form "k,target,mode,error"
00787   int target;
00788 
00789   sscanf(buf, "k,%d,%d,%d", &target, mode, error);
00790 
00791   return (unsigned char)target;
00792 }*/

Last updated 12 September 2005 21:38:45