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
00127 #include <sys/types.h>
00128 #include <netinet/in.h>
00129 #include <sys/stat.h>
00130 #include <fcntl.h>
00131 #include <string.h>
00132 #include <errno.h>
00133 #include <unistd.h>
00134 #include <math.h>
00135
00136 #define PLAYER_ENABLE_MSG 0
00137
00138 #include "player.h"
00139 #include "error.h"
00140 #include "driver.h"
00141 #include "drivertable.h"
00142
00143 #include "rmp_frame.h"
00144 #include "segwayrmp.h"
00145
00146
00147
00148
00149
00150 #define RMP_TIMEOUT_CYCLES 20 // about 400ms
00151
00152
00154
00155 Driver* SegwayRMP_Init(ConfigFile* cf, int section)
00156 {
00157
00158 return ((Driver*) (new SegwayRMP(cf, section)));
00159 }
00160
00161
00163
00164 void SegwayRMP_Register(DriverTable* table)
00165 {
00166 table->AddDriver("segwayrmp", SegwayRMP_Init);
00167 }
00168
00169
00171
00172 SegwayRMP::SegwayRMP(ConfigFile* cf, int section)
00173 : Driver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN)
00174 {
00175 memset(&this->position_id, 0, sizeof(player_devaddr_t));
00176 memset(&this->position3d_id, 0, sizeof(player_devaddr_t));
00177 memset(&this->power_id, 0, sizeof(player_devaddr_t));
00178
00179
00180 if(cf->ReadDeviceAddr(&(this->position_id), section, "provides",
00181 PLAYER_POSITION2D_CODE, -1, NULL) == 0)
00182 {
00183 if(this->AddInterface(this->position_id) != 0)
00184 {
00185 this->SetError(-1);
00186 return;
00187 }
00188 }
00189
00190
00191 if(cf->ReadDeviceAddr(&(this->position3d_id), section, "provides",
00192 PLAYER_POSITION3D_CODE, -1, NULL) == 0)
00193 {
00194 if(this->AddInterface(this->position3d_id) != 0)
00195 {
00196 this->SetError(-1);
00197 return;
00198 }
00199 }
00200
00201
00202 if(cf->ReadDeviceAddr(&(this->power_id), section, "provides",
00203 PLAYER_POWER_CODE, -1, NULL) == 0)
00204 {
00205 if(this->AddInterface(this->power_id) != 0)
00206 {
00207 this->SetError(-1);
00208 return;
00209 }
00210 }
00211
00212 this->canio = NULL;
00213 this->caniotype = cf->ReadString(section, "canio", "kvaser");
00214 this->max_xspeed = (int) (1000.0 * cf->ReadLength(section, "max_xspeed", 0.5));
00215 if(this->max_xspeed < 0)
00216 this->max_xspeed = -this->max_xspeed;
00217 this->max_yawspeed = (int) (RTOD(cf->ReadAngle(section, "max_yawspeed", 40)));
00218 if(this->max_yawspeed < 0)
00219 this->max_yawspeed = -this->max_yawspeed;
00220
00221 return;
00222 }
00223
00224
00225 SegwayRMP::~SegwayRMP()
00226 {
00227 return;
00228 }
00229
00230 int
00231 SegwayRMP::Setup()
00232 {
00233
00234 #if 0
00235 if (this->position_id.code)
00236 ClearCommand(this->position_id);
00237 if (this->position3d_id.code)
00238 ClearCommand(this->position3d_id);
00239 #endif
00240
00241 PLAYER_MSG0(2, "CAN bus initializing");
00242
00243 if(!strcmp(this->caniotype, "kvaser"))
00244 assert(this->canio = new CANIOKvaser);
00245 else
00246 {
00247 PLAYER_ERROR1("Unknown CAN I/O type: \"%s\"", this->caniotype);
00248 return(-1);
00249 }
00250
00251
00252 if(this->canio->Init(BAUD_500K) < 0)
00253 {
00254 PLAYER_ERROR("error on CAN Init");
00255 return(-1);
00256 }
00257
00258
00259 this->odom_x = this->odom_y = this->odom_yaw = 0.0;
00260
00261 this->curr_xspeed = this->curr_yawspeed = 0.0;
00262 this->motor_allow_enable = false;
00263 this->motor_enabled = false;
00264 this->firstread = true;
00265 this->timeout_counter = 0;
00266
00267 this->StartThread();
00268
00269 return(0);
00270 }
00271
00272 int
00273 SegwayRMP::Shutdown()
00274 {
00275 PLAYER_MSG0(2, "Shutting down CAN bus");
00276 fflush(stdout);
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 StopThread();
00287
00288
00289 CanPacket pkt;
00290
00291 MakeVelocityCommand(&pkt,0,0);
00292 Write(pkt);
00293
00294
00295 canio->Shutdown();
00296 delete canio;
00297 canio = NULL;
00298
00299 return(0);
00300 }
00301
00302
00303 void
00304 SegwayRMP::Main()
00305 {
00306
00307
00308
00309
00310
00311 CanPacket pkt;
00312
00313
00314 bool first;
00315
00316 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
00317 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
00318
00319 first = true;
00320 PLAYER_MSG0(2, "starting main loop");
00321
00322 for(;;)
00323 {
00324 pthread_testcancel();
00325 ProcessMessages();
00326
00327 if(Read() < 0)
00328 {
00329 PLAYER_ERROR("Read() errored; bailing");
00330 pthread_exit(NULL);
00331 }
00332
00333
00334 if (first)
00335 {
00336 first = false;
00337 PLAYER_MSG0(2, "got data from rmp");
00338 }
00339
00340
00341
00342
00343 Publish(this->position_id, PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE,
00344 &this->position_data, sizeof(this->position_data), NULL);
00345 Publish(this->position3d_id, PLAYER_MSGTYPE_DATA, PLAYER_POSITION3D_DATA_STATE,
00346 &this->position3d_data, sizeof(this->position3d_data), NULL);
00347 Publish(this->power_id, PLAYER_MSGTYPE_DATA, PLAYER_POWER_DATA_STATE,
00348 &this->power_data, sizeof(this->power_data), NULL);
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 timeout_counter++;
00417
00418 if(timeout_counter >= RMP_TIMEOUT_CYCLES)
00419 {
00420 if(curr_xspeed || curr_yawspeed)
00421 {
00422 PLAYER_WARN("timeout exceeded without new commands; stopping robot");
00423 curr_xspeed = 0;
00424 curr_yawspeed = 0;
00425 }
00426
00427
00428 timeout_counter = RMP_TIMEOUT_CYCLES;
00429 }
00430
00431 if(!motor_enabled)
00432 {
00433 curr_xspeed = 0;
00434 curr_yawspeed = 0;
00435 }
00436
00437
00438 MakeVelocityCommand(&pkt,static_cast<int> (curr_xspeed),static_cast<int> (curr_yawspeed));
00439 if(Write(pkt) < 0)
00440 PLAYER_ERROR("error on write");
00441 }
00442 }
00443
00444 int
00445 SegwayRMP::ProcessMessage(QueuePointer & resp_queue,
00446 player_msghdr * hdr,
00447 void * data)
00448 {
00451
00452
00453 if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD,
00454 PLAYER_POSITION2D_CMD_VEL,
00455 this->position_id))
00456 {
00457 player_position2d_cmd_vel_t* cmd = (player_position2d_cmd_vel_t*)data;
00458 this->curr_xspeed = cmd->vel.px * 1000.0;
00459 this->curr_yawspeed = cmd->vel.pa * 180.0/M_PI;
00460 this->motor_enabled = cmd->state & this->motor_allow_enable;
00461 this->timeout_counter = 0;
00462 return 0;
00463 }
00464
00465 if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD,
00466 PLAYER_POSITION3D_CMD_SET_VEL,
00467 this->position3d_id))
00468 {
00469 player_position3d_cmd_vel_t* cmd = (player_position3d_cmd_vel_t*)data;
00470 this->curr_xspeed = cmd->vel.px * 1000.0;
00471 this->curr_yawspeed = cmd->vel.pyaw * 180.0/M_PI;
00472 this->motor_enabled = cmd->state & this->motor_allow_enable;
00473 this->timeout_counter = 0;
00474 return 0;
00475 }
00476
00477 if (hdr->type == PLAYER_MSGTYPE_REQ && hdr->addr.interf == position_id.interf
00478 && hdr->addr.index == position_id.index)
00479 {
00480 return HandlePositionConfig(resp_queue, hdr->subtype, data, hdr->size);
00481 }
00482
00483 if (hdr->type == PLAYER_MSGTYPE_REQ && hdr->addr.interf == position3d_id.interf
00484 && hdr->addr.index == position3d_id.index)
00485 {
00486 return HandlePosition3DConfig(resp_queue, hdr->subtype, data, hdr->size);
00487 }
00488
00489
00490
00491 return(-1);
00492 }
00493
00494
00495
00496
00497 int
00498 SegwayRMP::HandlePositionConfig(QueuePointer &client, uint32_t subtype, void* buffer, size_t len)
00499 {
00500 uint16_t rmp_cmd,rmp_val;
00501
00502 CanPacket pkt;
00503
00504 switch(subtype)
00505 {
00506 case PLAYER_POSITION2D_REQ_MOTOR_POWER:
00507
00508
00509
00510
00511 if(((char *) buffer)[0])
00512 this->motor_allow_enable = true;
00513 else
00514 this->motor_allow_enable = false;
00515
00516 printf("SEGWAYRMP: motors state: %d\n", this->motor_allow_enable);
00517
00518 Publish(position_id, client, PLAYER_MSGTYPE_RESP_ACK,subtype);
00519 return 0;
00520
00521 case PLAYER_POSITION2D_REQ_GET_GEOM:
00522 player_position2d_geom_t geom;
00523 geom.pose.px = 0;
00524 geom.pose.py = 0;
00525 geom.pose.pa = 0;
00526 geom.size.sw = 0.508;
00527 geom.size.sl = 0.610;
00528
00529 Publish(position_id, client, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_GET_GEOM, &geom, sizeof(geom),NULL);
00530 return 0;
00531
00532 case PLAYER_POSITION2D_REQ_RESET_ODOM:
00533
00534
00535 MakeStatusCommand(&pkt, (uint16_t)RMP_CAN_CMD_RST_INT,
00536 (uint16_t)RMP_CAN_RST_ALL);
00537 if(Write(pkt) < 0)
00538 {
00539 Publish(position_id, client, PLAYER_MSGTYPE_RESP_NACK,PLAYER_POSITION2D_REQ_RESET_ODOM);
00540 }
00541 else
00542 {
00543
00544 if (Write(pkt) < 0) {
00545 Publish(position_id, client, PLAYER_MSGTYPE_RESP_NACK,PLAYER_POSITION2D_REQ_RESET_ODOM);
00546 } else {
00547 Publish(position_id, client, PLAYER_MSGTYPE_RESP_ACK,PLAYER_POSITION2D_REQ_RESET_ODOM);
00548 }
00549 }
00550
00551 odom_x = odom_y = odom_yaw = 0.0;
00552 firstread = true;
00553
00554
00555 return(0);
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 default:
00701 printf("segwayrmp received unknown config request %d\n",
00702 subtype);
00703
00704
00705 break;
00706 }
00707
00708
00709 return(-1);
00710 }
00711
00712
00713
00714
00715 int
00716 SegwayRMP::HandlePosition3DConfig(QueuePointer &client, uint32_t subtype, void* buffer, size_t len)
00717 {
00718 switch(subtype)
00719 {
00720 case PLAYER_POSITION3D_REQ_MOTOR_POWER:
00721
00722
00723
00724
00725 if(((char*)buffer)[0])
00726 this->motor_allow_enable = true;
00727 else
00728 this->motor_allow_enable = false;
00729
00730 printf("SEGWAYRMP: motors state: %d\n", this->motor_allow_enable);
00731
00732 Publish(this->position3d_id, client, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION3D_REQ_MOTOR_POWER);
00733 return 0;
00734
00735 default:
00736 printf("segwayrmp received unknown config request %d\n",
00737 subtype);
00738 }
00739
00740
00741 return(-1);
00742 }
00743
00744
00745 int
00746 SegwayRMP::Read()
00747 {
00748 CanPacket pkt;
00749 int channel;
00750 int ret;
00751 rmp_frame_t data_frame[2];
00752
00753
00754
00755
00756 data_frame[0].ready = 0;
00757 data_frame[1].ready = 0;
00758
00759
00760 for(channel = 0; channel < DUALCAN_NR_CHANNELS; channel++)
00761 {
00762 ret=0;
00763
00764 while((ret = canio->ReadPacket(&pkt, channel)) >= 0)
00765 {
00766
00767
00768
00769
00770 data_frame[channel].AddPacket(pkt);
00771
00772
00773
00774 if(data_frame[channel].IsReady())
00775 {
00776
00777
00778
00779 if(channel == 1)
00780 {
00781 UpdateData(&data_frame[channel]);
00782 }
00783
00784 data_frame[channel].ready = 0;
00785 break;
00786 }
00787 }
00788
00789 if (ret < 0)
00790 {
00791 PLAYER_ERROR2("error (%d) reading packet on channel %d",
00792 ret, channel);
00793 }
00794 }
00795
00796 return(0);
00797 }
00798
00799 void
00800 SegwayRMP::UpdateData(rmp_frame_t * data_frame)
00801 {
00802 int delta_lin_raw, delta_ang_raw;
00803 double delta_lin, delta_ang;
00804 double tmp;
00805
00806
00807
00808
00809 delta_lin_raw = Diff(this->last_raw_foreaft,
00810 data_frame->foreaft,
00811 this->firstread);
00812 this->last_raw_foreaft = data_frame->foreaft;
00813
00814 delta_ang_raw = Diff(this->last_raw_yaw,
00815 data_frame->yaw,
00816 this->firstread);
00817 this->last_raw_yaw = data_frame->yaw;
00818
00819 delta_lin = (double)delta_lin_raw / (double)RMP_COUNT_PER_M;
00820 delta_ang = DTOR((double)delta_ang_raw /
00821 (double)RMP_COUNT_PER_REV * 360.0);
00822
00823
00824 this->odom_x += delta_lin * cos(this->odom_yaw);
00825 this->odom_y += delta_lin * sin(this->odom_yaw);
00826 this->odom_yaw += delta_ang;
00827
00828
00829 this->odom_yaw = atan2(sin(this->odom_yaw), cos(this->odom_yaw));
00830 if (this->odom_yaw < 0)
00831 this->odom_yaw += 2 * M_PI;
00832
00833
00834 this->position_data.pos.px = this->odom_x;
00835 this->position_data.pos.py = this->odom_y;
00836 this->position_data.pos.pa = this->odom_yaw;
00837
00838
00839
00840 this->position_data.vel.px = ((double)data_frame->left_dot +
00841 (double)data_frame->right_dot) /
00842 (double)RMP_COUNT_PER_M_PER_S
00843 / 2.0;
00844
00845
00846 this->position_data.vel.py = 0;
00847
00848
00849
00850
00851 this->position_data.vel.pa =
00852 DTOR(-(double)data_frame->yaw_dot / (double)RMP_COUNT_PER_DEG_PER_S);
00853
00854 this->position_data.stall = 0;
00855
00856
00857 this->position3d_data.pos.px = this->odom_x;
00858 this->position3d_data.pos.py = this->odom_y;
00859
00860 this->position3d_data.pos.pz = 0;
00861
00863
00864
00865 tmp = NORMALIZE(DTOR((double)data_frame->roll /
00866 (double)RMP_COUNT_PER_DEG));
00867 if(tmp < 0)
00868 tmp += 2*M_PI;
00869 this->position3d_data.pos.proll = tmp;
00870
00871
00872 tmp = NORMALIZE(DTOR((double)data_frame->pitch /
00873 (double)RMP_COUNT_PER_DEG));
00874 if(tmp < 0)
00875 tmp += 2*M_PI;
00876 this->position3d_data.pos.ppitch = tmp;
00877
00878 this->position3d_data.pos.pyaw = tmp;
00879
00880
00881
00882 this->position3d_data.vel.px =
00883 ((double)data_frame->left_dot +
00884 (double)data_frame->right_dot) /
00885 (double)RMP_COUNT_PER_M_PER_S
00886 / 2.0;
00887
00888 this->position3d_data.vel.py = 0;
00889 this->position3d_data.vel.pz = 0;
00890
00891 this->position3d_data.vel.proll =
00892 (double)data_frame->roll_dot /
00893 (double)RMP_COUNT_PER_DEG_PER_S * M_PI / 180;
00894 this->position3d_data.vel.ppitch =
00895 (double)data_frame->pitch_dot /
00896 (double)RMP_COUNT_PER_DEG_PER_S * M_PI / 180;
00897
00898
00899
00900
00901
00902 this->position3d_data.vel.pyaw =
00903 (double)(data_frame->right_dot - data_frame->left_dot) /
00904 (RMP_COUNT_PER_M_PER_S * RMP_GEOM_WHEEL_SEP * M_PI);
00905
00906
00907
00908
00909
00910 this->position3d_data.stall = 0;
00911
00912
00913
00914
00915 this->power_data.volts =
00916 data_frame->battery * 72;
00917
00918 firstread = false;
00919 }
00920
00921
00922 int
00923 SegwayRMP::Write(CanPacket& pkt)
00924 {
00925 return(canio->WritePacket(pkt));
00926 }
00927
00928
00929
00930 void
00931 SegwayRMP::MakeStatusCommand(CanPacket* pkt, uint16_t cmd, uint16_t val)
00932 {
00933 int16_t trans,rot;
00934
00935 pkt->id = RMP_CAN_ID_COMMAND;
00936 pkt->PutSlot(2, cmd);
00937
00938
00939
00940 pkt->PutByte(6, val);
00941 pkt->PutByte(7, val);
00942
00943 trans = (int16_t) rint((double)this->curr_xspeed *
00944 (double)RMP_COUNT_PER_MM_PER_S);
00945
00946 if(trans > RMP_MAX_TRANS_VEL_COUNT)
00947 trans = RMP_MAX_TRANS_VEL_COUNT;
00948 else if(trans < -RMP_MAX_TRANS_VEL_COUNT)
00949 trans = -RMP_MAX_TRANS_VEL_COUNT;
00950
00951 rot = (int16_t) rint((double)this->curr_yawspeed *
00952 (double)RMP_COUNT_PER_DEG_PER_SS);
00953
00954 if(rot > RMP_MAX_ROT_VEL_COUNT)
00955 rot = RMP_MAX_ROT_VEL_COUNT;
00956 else if(rot < -RMP_MAX_ROT_VEL_COUNT)
00957 rot = -RMP_MAX_ROT_VEL_COUNT;
00958
00959
00960 pkt->PutSlot(0,(uint16_t)trans);
00961 pkt->PutSlot(1,(uint16_t)rot);
00962
00963 if(cmd)
00964 {
00965 printf("SEGWAYIO: STATUS: cmd: %02x val: %02x pkt: %s\n",
00966 cmd, val, pkt->toString());
00967 }
00968 }
00969
00970
00971
00972
00973 void
00974 SegwayRMP::MakeVelocityCommand(CanPacket* pkt,
00975 int32_t xspeed,
00976 int32_t yawspeed)
00977 {
00978 pkt->id = RMP_CAN_ID_COMMAND;
00979 pkt->PutSlot(2, (uint16_t)RMP_CAN_CMD_NONE);
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989 if(xspeed > this->max_xspeed)
00990 {
00991 PLAYER_WARN2("xspeed thresholded! (%d > %d)", xspeed, this->max_xspeed);
00992 xspeed = this->max_xspeed;
00993 }
00994 else if(xspeed < -this->max_xspeed)
00995 {
00996 PLAYER_WARN2("xspeed thresholded! (%d < %d)", xspeed, -this->max_xspeed);
00997 xspeed = -this->max_xspeed;
00998 }
00999
01000 this->curr_xspeed = xspeed;
01001
01002 int16_t trans = (int16_t) rint((double)xspeed *
01003 (double)RMP_COUNT_PER_MM_PER_S);
01004
01005 if(trans > RMP_MAX_TRANS_VEL_COUNT)
01006 trans = RMP_MAX_TRANS_VEL_COUNT;
01007 else if(trans < -RMP_MAX_TRANS_VEL_COUNT)
01008 trans = -RMP_MAX_TRANS_VEL_COUNT;
01009
01010 if(yawspeed > this->max_yawspeed)
01011 {
01012 PLAYER_WARN2("yawspeed thresholded! (%d > %d)",
01013 yawspeed, this->max_yawspeed);
01014 yawspeed = this->max_yawspeed;
01015 }
01016 else if(yawspeed < -this->max_yawspeed)
01017 {
01018 PLAYER_WARN2("yawspeed thresholded! (%d < %d)",
01019 yawspeed, -this->max_yawspeed);
01020 yawspeed = -this->max_yawspeed;
01021 }
01022 this->curr_yawspeed = yawspeed;
01023
01024
01025
01026
01027 int16_t rot = (int16_t) rint((double)yawspeed *
01028 (double)RMP_COUNT_PER_DEG_PER_S);
01029
01030 if(rot > RMP_MAX_ROT_VEL_COUNT)
01031 rot = RMP_MAX_ROT_VEL_COUNT;
01032 else if(rot < -RMP_MAX_ROT_VEL_COUNT)
01033 rot = -RMP_MAX_ROT_VEL_COUNT;
01034
01035 pkt->PutSlot(0, (uint16_t)trans);
01036 pkt->PutSlot(1, (uint16_t)rot);
01037 }
01038
01039 void
01040 SegwayRMP::MakeShutdownCommand(CanPacket* pkt)
01041 {
01042 pkt->id = RMP_CAN_ID_SHUTDOWN;
01043
01044 printf("SEGWAYIO: SHUTDOWN: pkt: %s\n",
01045 pkt->toString());
01046 }
01047
01048
01049
01050 int
01051 SegwayRMP::Diff(uint32_t from, uint32_t to, bool first)
01052 {
01053 int diff1, diff2;
01054 static uint32_t max = (uint32_t)pow(2,32)-1;
01055
01056
01057 if(first)
01058 return(0);
01059
01060 diff1 = to - from;
01061
01062
01063 if(to > from)
01064 diff2 = -(from + max - to);
01065 else
01066 diff2 = max - from + to;
01067
01068 if(abs(diff1) < abs(diff2))
01069 return(diff1);
01070 else
01071 return(diff2);
01072 }