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
00078 #if HAVE_CONFIG_H
00079 #include <config.h>
00080 #endif
00081
00082 #include <fcntl.h>
00083 #include <signal.h>
00084 #include <sys/stat.h>
00085 #include <sys/types.h>
00086 #include <stdio.h>
00087 #include <string.h>
00088 #include <unistd.h>
00089 #include <math.h>
00090 #include <stdlib.h>
00091 #include <netinet/in.h>
00092 #include <termios.h>
00093
00094 #include <libplayercore/playercore.h>
00095 #include <replace/replace.h>
00096 #include "clodbuster.h"
00097 #include "packet.h"
00098
00099
00100 Driver* ClodBuster_Init( ConfigFile* cf, int section)
00101 {
00102 return((Driver*)(new ClodBuster( cf, section)));
00103 }
00104
00105
00106 void
00107 ClodBuster_Register(DriverTable* table)
00108 {
00109 table->AddDriver("clodbuster", ClodBuster_Init);
00110 }
00111
00112
00113 ClodBuster::ClodBuster( ConfigFile* cf, int section)
00114 : Driver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_POSITION2D_CODE)
00115 {
00116 clodbuster_fd = -1;
00117
00118 speedDemand=0, turnRateDemand=0;
00119
00120
00121 strncpy(clodbuster_serial_port,
00122 cf->ReadString(section, "port", DEFAULT_CLODBUSTER_PORT),
00123 sizeof(clodbuster_serial_port));
00124
00125
00126 CountsPerRev = 408;
00127 WheelRadius = 0.076;
00128 WheelBase = .2921;
00129 WheelSeparation = .275;
00130 Kenc = 2*M_PI*WheelRadius/CountsPerRev;
00131 LoopFreq = 5;
00132
00133
00134
00135
00136 Kv = new PIDGains(-10,-20.0,0.0,LoopFreq);
00137 Kw = new PIDGains(-5,-20.0,0.0,LoopFreq);
00138 }
00139
00140 ClodBuster::~ClodBuster()
00141 {
00142 delete Kv;
00143 delete Kw;
00144 }
00145
00146 int ClodBuster::Setup()
00147 {
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 struct termios term;
00158
00159
00160 int flags;
00161
00162
00163 printf("clodbuster connection initializing (%s)...",clodbuster_serial_port);
00164 fflush(stdout);
00165
00166 if((clodbuster_fd = open(clodbuster_serial_port,
00167 O_RDWR | O_SYNC, S_IRUSR | S_IWUSR )) < 0 )
00168 {
00169 perror("ClodBuster::Setup():open():");
00170 return(1);
00171 }
00172
00173 if( tcgetattr( clodbuster_fd, &term ) < 0 )
00174 {
00175 perror("ClodBuster::Setup():tcgetattr():");
00176 close(clodbuster_fd);
00177 clodbuster_fd = -1;
00178 return(1);
00179 }
00180
00181 cfmakeraw( &term );
00182 term.c_cc[VTIME] = 10;
00183 term.c_cc[VMIN] = 0;
00184
00185 cfsetispeed(&term, B38400);
00186 cfsetospeed(&term, B38400);
00187
00188 if( tcsetattr( clodbuster_fd, TCSAFLUSH, &term ) < 0 )
00189 {
00190 perror("ClodBuster::Setup():tcsetattr():");
00191 close(clodbuster_fd);
00192 clodbuster_fd = -1;
00193 return(1);
00194 }
00195
00196 if( tcflush( clodbuster_fd, TCIOFLUSH ) < 0 )
00197 {
00198 perror("ClodBuster::Setup():tcflush():");
00199 close(clodbuster_fd);
00200 clodbuster_fd = -1;
00201 return(1);
00202 }
00203
00204 if((flags = fcntl(clodbuster_fd, F_GETFL)) < 0)
00205 {
00206 perror("ClodBuster::Setup():fcntl()");
00207 close(clodbuster_fd);
00208 clodbuster_fd = -1;
00209 return(1);
00210 }
00211
00212 flags &= ~O_NONBLOCK;
00213 fcntl(clodbuster_fd, F_SETFL, flags);
00214
00215
00216 usleep(CLODBUSTER_CYCLETIME_USEC);
00217
00218 GRASPPacket packet;
00219
00220 packet.Build(SET_SLEEP_MODE,SLEEP_MODE_OFF);
00221 packet.Send(clodbuster_fd);
00222
00223 ResetRawPositions();
00224
00225 direct_command_control = true;
00226
00227
00228 StartThread();
00229 return(0);
00230 }
00231
00232 int ClodBuster::Shutdown()
00233 {
00234 GRASPPacket packet;
00235
00236 if(clodbuster_fd == -1)
00237 {
00238 return(0);
00239 }
00240
00241 StopThread();
00242
00243 packet.Build(SET_SLEEP_MODE,SLEEP_MODE_OFF);
00244 packet.Send(clodbuster_fd);
00245 usleep(CLODBUSTER_CYCLETIME_USEC);
00246
00247 close(clodbuster_fd);
00248 clodbuster_fd = -1;
00249 puts("ClodBuster has been shutdown");
00250
00251 return(0);
00252 }
00253
00255
00256 int ClodBuster::ProcessMessage (QueuePointer &resp_queue, player_msghdr * hdr, void * data)
00257 {
00258
00259 assert(hdr);
00260 assert(data);
00261
00262 if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SET_ODOM, device_addr))
00263 {
00264 assert(hdr->size == sizeof(player_position2d_set_odom_req_t));
00265 player_position2d_set_odom_req_t & set_odom_req = *((player_position2d_set_odom_req_t*)data);
00266
00267 this->position_data.pos = set_odom_req.pose;
00268
00269 Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_SET_ODOM);
00270 return 0;
00271 }
00272
00273 if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_GET_GEOM, device_addr))
00274 {
00275 player_position2d_geom_t geom={{0}};
00276
00277
00278 geom.pose.px = -0.1;
00279 geom.pose.py = 0;
00280 geom.pose.pyaw = 0;
00281 geom.size.sw = 0.5;
00282 geom.size.sl = 0.45;
00283
00284 Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_GET_GEOM, &geom, sizeof(geom));
00285 return 0;
00286 }
00287
00288 if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, device_addr))
00289 {
00290 assert(hdr->size == sizeof(player_position2d_power_config_t));
00291 player_position2d_power_config_t & power_config = *((player_position2d_power_config_t*)data);
00292 GRASPPacket packet;
00293
00294 if(power_config.state==1)
00295 packet.Build(SET_SLEEP_MODE,SLEEP_MODE_OFF);
00296 else
00297 packet.Build(SET_SLEEP_MODE,SLEEP_MODE_ON);
00298
00299 packet.Send(clodbuster_fd);
00300
00301 Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_MOTOR_POWER);
00302 return 0;
00303 }
00304
00305
00306
00307
00308
00309 if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, device_addr))
00310 {
00311 assert(hdr->size == sizeof(player_position2d_velocity_mode_config_t));
00312 player_position2d_velocity_mode_config_t & velmode_config = *((player_position2d_velocity_mode_config_t*)data);
00313
00314 if(velmode_config.value)
00315 direct_command_control = false;
00316 else
00317 direct_command_control = true;
00318
00319 Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_VELOCITY_MODE);
00320 return 0;
00321 }
00322
00323 if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_RESET_ODOM, device_addr))
00324 {
00325 ResetRawPositions();
00326
00327 Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_RESET_ODOM);
00328 return 0;
00329 }
00330
00331 if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SPEED_PID, device_addr))
00332 {
00333 assert(hdr->size == sizeof(player_position2d_speed_pid_req_t));
00334 player_position2d_speed_pid_req_t & pid = *((player_position2d_speed_pid_req_t*)data);
00335
00336 kp = static_cast<int> (pid.kp);
00337 ki = static_cast<int> (pid.ki);
00338 kd = static_cast<int> (pid.kd);
00339
00340 Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_SPEED_PID);
00341 return 0;
00342 }
00343
00344 if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL, device_addr))
00345 {
00346 assert(hdr->size == sizeof(player_position2d_cmd_vel_t));
00347 player_position2d_cmd_vel_t & command = *((player_position2d_cmd_vel_t*)data);
00348
00349 newmotorspeed = false;
00350 if( speedDemand != (int) command.vel.px)
00351 newmotorspeed = true;
00352 speedDemand = (int) command.vel.px;
00353
00354 newmotorturn = false;
00355 if(turnRateDemand != (int) command.vel.pa)
00356 newmotorturn = true;
00357 turnRateDemand = (int) command.vel.pa;
00358
00359 return 0;
00360 }
00361
00362 return -1;
00363 }
00364
00365 void
00366 ClodBuster::Main()
00367 {
00368
00369
00370
00371
00372
00373
00374 GetGraspBoardParams();
00375
00376
00377 int uVmax=max_limits[SET_SERVO_THROTTLE];
00378 int uVmin=min_limits[SET_SERVO_THROTTLE];
00379 int uV0=center_limits[SET_SERVO_THROTTLE];
00380 int uWmax=max_limits[SET_SERVO_FRONTSTEER];
00381 int uWmin=min_limits[SET_SERVO_FRONTSTEER];
00382 int uW0=center_limits[SET_SERVO_FRONTSTEER];
00383 float uV = uV0, uW=uW0, errV[3]={0}, errW[3]={0}, uVlast=uV0, uWlast=uW0,V;
00384
00385 printf("V max min centre %d %d %d\n",uVmax,uVmin,uV0);
00386 printf("W max min centre %d %d %d\n",uWmax,uWmin,uW0);
00387
00388 for(;;)
00389 {
00390 ProcessMessages();
00391 pthread_testcancel();
00392
00393
00394 encoder_measurement = ReadEncoders();
00395
00396 DifferenceEncoders();
00397 IntegrateEncoders();
00398
00399
00400 old_encoder_measurement = encoder_measurement;
00401
00402 Publish(device_addr,PLAYER_MSGTYPE_DATA,PLAYER_POSITION2D_DATA_STATE,(void*)&this->position_data,
00403 sizeof(player_position2d_data_t),NULL);
00404
00405
00406
00407
00408
00409
00410 if(!direct_command_control)
00411 {
00412
00413
00414
00415 unsigned char v,w;
00416 v = SetServo(SET_SERVO_THROTTLE,speedDemand);
00417 w = SetServo(SET_SERVO_FRONTSTEER,turnRateDemand);
00418 printf("The vel/turn command numbers : v:%d (%u) w:%d (%u)\n",center_limits[SET_SERVO_THROTTLE]+speedDemand,v,center_limits[SET_SERVO_FRONTSTEER]+turnRateDemand,w);
00419
00420
00421 }
00422 else
00423 {
00424
00425
00426 errV[0] = EncV - speedDemand*1e-3;
00427 errW[0] = EncOmega - turnRateDemand*M_PI/180.0;
00428
00429
00430 uV = uVlast + Kv->K1()*errV[0] + + Kv->K2()*errV[1] + Kv->K3()*errV[2];
00431 if (uV > uVmax)
00432 {
00433 uV = uVmax;
00434 printf("+V control saturated!\n");
00435 }
00436 if (uV < uVmin)
00437 {
00438 uV = uVmin;
00439 printf("-V control saturated!\n");
00440 }
00441 printf("V loop err: %f, u = %f, r = %f, x = %f\n",errV[0], uV,speedDemand*1e-3,EncV);
00442
00443 if (fabs(EncV) > .0125)
00444 {
00445 if (fabs(EncV) <.1)
00446 if (EncV <.1)
00447 V = -.1;
00448 else
00449 V = .1;
00450 else
00451 V = EncV;
00452
00453 uW = uWlast - WheelBase/V*(Kw->K1()*errW[0] + + Kw->K2()*errW[1] + Kw->K3()*errW[2]);
00454
00455 }
00456 else
00457 {
00458
00459 uW = uW0;
00460 uWlast = uW0;
00461 for (int i=0;i<3;i++)
00462 errW[i] = 0.;
00463 }
00464 if (uW > uWmax)
00465 {
00466 uW = uWmax;
00467 printf("+W control saturated!\n");
00468 }
00469 if (uW < uWmin)
00470 {
00471 uW = uWmin;
00472 printf("-W control saturated!\n");
00473 }
00474 printf("W loop err: %f, u = %f, r = %f, x = %f\n",errW[0], uW,turnRateDemand*M_PI/180.0,EncOmega);
00475
00476
00477 SetServo(SET_SERVO_THROTTLE,(unsigned char) uV);
00478 SetServo(SET_SERVO_FRONTSTEER,(unsigned char) uW);
00479
00480 for (int i=1;i<3;i++)
00481 {
00482 errW[i] = errW[i-1];
00483 errV[i] = errV[i-1];
00484 }
00485 uVlast = uV;
00486 uWlast = uW;
00487
00488 }
00489 usleep(200000);
00490 }
00491 pthread_exit(NULL);
00492 }
00493
00494 void
00495 ClodBuster::ResetRawPositions()
00496 {
00497 encoder_offset=ReadEncoders();
00498 }
00499
00500 clodbuster_encoder_data_t ClodBuster::ReadEncoders()
00501 { GRASPPacket packet,rpacket;
00502 clodbuster_encoder_data_t temp;
00503
00504 packet.Build(ECHO_ENCODER_COUNTS_TS);
00505 packet.Send(clodbuster_fd);
00506
00507 rpacket.Receive(clodbuster_fd,ECHO_ENCODER_COUNTS_TS);
00508 rpacket.size=rpacket.retsize;
00509 rpacket.PrintHex();
00510
00511
00512 temp.left = (rpacket.packet[0]<<16)|(rpacket.packet[1]<<8)|(rpacket.packet[2]);
00513 if (rpacket.packet[0] & 0x80)
00514 temp.left |= 0xff<<24;
00515 temp.right = (rpacket.packet[3]<<16)|(rpacket.packet[4]<<8)|(rpacket.packet[5]);
00516 if (rpacket.packet[3] & 0x80)
00517 temp.right |= 0xff<<24;
00518
00519
00520
00521
00522 temp.time_count = (rpacket.packet[6] << 24)|(rpacket.packet[7] <<16)|(rpacket.packet[8]<<8)|(rpacket.packet[9]);
00523
00524 return temp;
00525
00526 }
00527
00528 void ClodBuster::GetGraspBoardParams()
00529 {
00530 GRASPPacket packet,rpacket;
00531 packet.Build(ECHO_MAX_SERVO_LIMITS);
00532 packet.Send(clodbuster_fd);
00533 printf("Servo Limit Enquiry: ");
00534
00535 packet.PrintHex();
00536
00537 rpacket.Receive(clodbuster_fd,ECHO_MAX_SERVO_LIMITS);
00538
00539 memcpy(max_limits,rpacket.packet,8);
00540 rpacket.size = rpacket.retsize;
00541
00542 rpacket.PrintHex();
00543
00544 packet.Build(ECHO_MIN_SERVO_LIMITS);
00545 packet.Send(clodbuster_fd);
00546 printf("Servo Limit Enquiry: ");
00547
00548 packet.PrintHex();
00549
00550 rpacket.Receive(clodbuster_fd,ECHO_MIN_SERVO_LIMITS);
00551 rpacket.size = rpacket.retsize;
00552
00553 rpacket.PrintHex();
00554 memcpy(min_limits,rpacket.packet,8);
00555 packet.Build(ECHO_CEN_SERVO_LIMITS);
00556 packet.Send(clodbuster_fd);
00557 printf("Servo Limit Enquiry: ");
00558
00559 packet.PrintHex();
00560
00561 rpacket.Receive(clodbuster_fd,ECHO_CEN_SERVO_LIMITS);
00562
00563 memcpy(center_limits,rpacket.packet,8);
00564 rpacket.size = rpacket.retsize;
00565
00566 rpacket.PrintHex();
00567 }
00568
00569 unsigned char
00570 ClodBuster::SetServo(unsigned char chan, int value)
00571 {
00572 GRASPPacket spacket;
00573 unsigned char cmd;
00574 int demanded = center_limits[chan]+value/10;
00575
00576 if (demanded > max_limits[chan])
00577 cmd = (unsigned char) max_limits[chan];
00578 else if (demanded < min_limits[chan])
00579 cmd = (unsigned char) min_limits[chan];
00580 else
00581 cmd = (unsigned char)demanded;
00582 spacket.Build(chan,cmd);
00583 spacket.Send(clodbuster_fd);
00584
00585
00586 return(cmd);
00587 }
00588 void
00589 ClodBuster::SetServo(unsigned char chan, unsigned char cmd)
00590 {
00591 GRASPPacket spacket;
00592 spacket.Build(chan,cmd);
00593 spacket.Send(clodbuster_fd);
00594
00595 }
00596
00597 void ClodBuster::IntegrateEncoders()
00598 {
00599
00600 float dEr = encoder_measurement.right-old_encoder_measurement.right;
00601 float dEl = encoder_measurement.left-old_encoder_measurement.left;
00602 float L = Kenc*(dEr+dEl)*.5;
00603 float D = Kenc*(dEr-dEl)/WheelSeparation;
00604 float Phi = this->position_data.pos.pa+0.5*D;
00605
00606 this->position_data.pos.px += L*cos(Phi);
00607 this->position_data.pos.py += L*sin(Phi);
00608 this->position_data.pos.pa += D;
00609 }
00610
00611 void ClodBuster::DifferenceEncoders()
00612 {
00613 float dEr = encoder_measurement.right-old_encoder_measurement.right;
00614 float dEl = encoder_measurement.left-old_encoder_measurement.left;
00615 int64_t dtc = encoder_measurement.time_count-old_encoder_measurement.time_count;
00616 if (dtc< -2147483648LL)
00617 {
00618 dtc += 4294967296LL;
00619 printf("encoder timer rollover caught\n");
00620 }
00621 float dt = dtc*1.6e-6;
00622 if (dt < 20e-3)
00623 printf("dt way too short %f s\n",dt);
00624 else if (dt > 2.0/LoopFreq)
00625 printf("dt way too long %f s\n",dt);
00626
00627 EncV = Kenc*(dEr+dEl)*.5/dt;
00628 EncOmega = Kenc*(dEr-dEl)/WheelSeparation/dt;
00629 EncVleft = dEl/dt;
00630 EncVright = dEr/dt;
00631 printf("EncV = %f, EncW = %f, dt = %f\n",EncV,EncOmega*180/M_PI,dt);
00632
00633 }