00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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>
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
00128
00129
00130 #define DEBUG_CONFIG
00131
00132
00133 #define DEG2RAD(x) (((double)(x))*0.01745329251994)
00134 #define RAD2DEG(x) (((double)(x))*57.29577951308232)
00135
00136
00137
00138 #define DEG2RAD_FIX(x) ((x) * 174)
00139 #define RAD2DEG_FIX(x) ((x) * 572958)
00140
00141
00142
00143
00144
00145
00146 Driver*
00147 Khepera_Init(ConfigFile *cf, int section)
00148 {
00149 return (Driver *) new Khepera( cf, section);
00150 }
00151
00152
00153
00154
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
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
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
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
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
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
00251 geometry = new player_khepera_geom_t;
00252 geometry->PortName= NULL;
00253 geometry->scale = 0;
00254
00255
00256
00257
00258
00259
00260
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
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
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
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
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
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
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
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
00358 if((setupResult = Driver::Subscribe(addr)) == 0)
00359 {
00360
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
00381 if((shutdownResult = Driver::Unsubscribe(addr)) == 0)
00382 {
00383
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
00399
00400
00401
00402 int
00403 Khepera::Setup()
00404 {
00405
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
00423 StartThread();
00424 return(0);
00425 }
00426
00427
00428 int
00429 Khepera::Shutdown()
00430 {
00431 printf("Khepera: SHUTDOWN\n");
00432 StopThread();
00433
00434
00435
00436
00437
00438
00439
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
00456
00457
00458 if(!last_position_subscrcount && this->position_subscriptions)
00459 {
00460 printf("Khepera: first pos sub. turn off and reset\n");
00461
00462 SetSpeed(0,0);
00463 ResetOdometry();
00464
00465 }
00466 else if(last_position_subscrcount && !(this->position_subscriptions))
00467 {
00468
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
00479 UpdateData();
00480
00481 pthread_testcancel();
00482 }
00483 pthread_exit(NULL);
00484 }
00485
00486
00487
00488
00489
00490
00491
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
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
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
00516
00517
00518
00519
00520
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
00536
00537 void
00538 Khepera::UpdatePosData(player_position2d_data_t *d)
00539 {
00540
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
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
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
00597
00598
00599
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
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
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
00660
00661
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
00673
00674
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
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
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
00715
00716
00717
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
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792