p2os.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 /*
00024  * $Id: p2os.cc 6566 2008-06-14 01:00:19Z thjc $
00025  *
00026  *   the P2OS device.  it's the parent device for all the P2 'sub-devices',
00027  *   like gripper, position, sonar, etc.  there's a thread here that
00028  *   actually interacts with P2OS via the serial line.  the other
00029  *   "devices" communicate with this thread by putting into and getting
00030  *   data out of shared buffers.
00031  */
00032 
00308 #ifdef HAVE_CONFIG_H
00309   #include "config.h"
00310 #endif
00311 
00312 #include "p2os.h"
00313 #include <libplayerxdr/playerxdr.h>
00314 
00315 #include <fcntl.h>
00316 #include <signal.h>
00317 #include <sys/stat.h>
00318 #include <sys/types.h>
00319 #include <stddef.h>
00320 #include <stdio.h>
00321 #include <string.h>
00322 #include <strings.h>
00323 #include <unistd.h>
00324 #include <math.h>
00325 #include <stdlib.h>  /* for abs() */
00326 #include <netinet/in.h>
00327 #include <termios.h>
00328 #include <sys/socket.h>
00329 #include <netinet/tcp.h>
00330 #include <netdb.h>
00331 
00332 Driver*
00333 P2OS_Init(ConfigFile* cf, int section)
00334 {
00335   return (Driver*)(new P2OS(cf,section));
00336 }
00337 
00338 void P2OS_Register(DriverTable* table)
00339 {
00340   table->AddDriver("p2os", P2OS_Init);
00341 }
00342 
00343 P2OS::P2OS(ConfigFile* cf, int section)
00344         : Driver(cf,section,true,PLAYER_MSGQUEUE_DEFAULT_MAXLEN)
00345 {
00346   // zero ids, so that we'll know later which interfaces were requested
00347   memset(&this->position_id, 0, sizeof(player_devaddr_t));
00348   memset(&this->sonar_id, 0, sizeof(player_devaddr_t));
00349   memset(&this->aio_id, 0, sizeof(player_devaddr_t));
00350   memset(&this->dio_id, 0, sizeof(player_devaddr_t));
00351   memset(&this->gripper_id, 0, sizeof(player_devaddr_t));
00352   memset(&this->bumper_id, 0, sizeof(player_devaddr_t));
00353   memset(&this->power_id, 0, sizeof(player_devaddr_t));
00354   memset(&this->compass_id, 0, sizeof(player_devaddr_t));
00355   memset(&this->gyro_id, 0, sizeof(player_devaddr_t));
00356   memset(&this->blobfinder_id, 0, sizeof(player_devaddr_t));
00357   memset(&this->audio_id, 0, sizeof(player_devaddr_t));
00358   memset(&this->actarray_id, 0, sizeof(player_devaddr_t));
00359   memset(&this->limb_id, 0, sizeof(player_devaddr_t));
00360 
00361   this->position_subscriptions = this->sonar_subscriptions = this->actarray_subscriptions = 0;
00362   this->pulse = -1;
00363 
00364   // intialise members
00365   sippacket = NULL;
00366 
00367   // Do we create a robot position interface?
00368   if(cf->ReadDeviceAddr(&(this->position_id), section, "provides",
00369                         PLAYER_POSITION2D_CODE, -1, NULL) == 0)
00370   {
00371     if(this->AddInterface(this->position_id) != 0)
00372     {
00373       this->SetError(-1);
00374       return;
00375     }
00376   }
00377 
00378   // Do we create a compass position interface?
00379   if(cf->ReadDeviceAddr(&(this->compass_id), section, "provides",
00380                         PLAYER_POSITION2D_CODE, -1, "compass") == 0)
00381   {
00382     if(this->AddInterface(this->compass_id) != 0)
00383     {
00384       this->SetError(-1);
00385       return;
00386     }
00387   }
00388 
00389   // Do we create a gyro position interface?
00390   if(cf->ReadDeviceAddr(&(this->gyro_id), section, "provides",
00391                         PLAYER_POSITION2D_CODE, -1, "gyro") == 0)
00392   {
00393     if(this->AddInterface(this->gyro_id) != 0)
00394     {
00395       this->SetError(-1);
00396       return;
00397     }
00398   }
00399 
00400 
00401   // Do we create a sonar interface?
00402   if(cf->ReadDeviceAddr(&(this->sonar_id), section, "provides",
00403                       PLAYER_SONAR_CODE, -1, NULL) == 0)
00404   {
00405     if(this->AddInterface(this->sonar_id) != 0)
00406     {
00407       this->SetError(-1);
00408       return;
00409     }
00410   }
00411 
00412 
00413   // Do we create an aio interface?
00414   if(cf->ReadDeviceAddr(&(this->aio_id), section, "provides",
00415                       PLAYER_AIO_CODE, -1, NULL) == 0)
00416   {
00417     if(this->AddInterface(this->aio_id) != 0)
00418     {
00419       this->SetError(-1);
00420       return;
00421     }
00422   }
00423 
00424   // Do we create a dio interface?
00425   if(cf->ReadDeviceAddr(&(this->dio_id), section, "provides",
00426                       PLAYER_DIO_CODE, -1, NULL) == 0)
00427   {
00428     if(this->AddInterface(this->dio_id) != 0)
00429     {
00430       this->SetError(-1);
00431       return;
00432     }
00433   }
00434 
00435   // Do we create a gripper interface?
00436   if(cf->ReadDeviceAddr(&(this->gripper_id), section, "provides",
00437                       PLAYER_GRIPPER_CODE, -1, "gripper") == 0)
00438   {
00439     if(this->AddInterface(this->gripper_id) != 0)
00440     {
00441       this->SetError(-1);
00442       return;
00443     }
00444   }
00445 
00446   // Do we create an actarray interface for the gripper lift?
00447   if(cf->ReadDeviceAddr(&(this->lift_id), section, "provides",
00448      PLAYER_ACTARRAY_CODE, -1, "lift") == 0)
00449   {
00450     if(this->AddInterface(this->lift_id) != 0)
00451     {
00452       this->SetError(-1);
00453       return;
00454     }
00455   }
00456 
00457   // Do we create a bumper interface?
00458   if(cf->ReadDeviceAddr(&(this->bumper_id), section, "provides",
00459                       PLAYER_BUMPER_CODE, -1, NULL) == 0)
00460   {
00461     if(this->AddInterface(this->bumper_id) != 0)
00462     {
00463       this->SetError(-1);
00464       return;
00465     }
00466   }
00467 
00468   // Do we create a power interface?
00469   if(cf->ReadDeviceAddr(&(this->power_id), section, "provides",
00470                       PLAYER_POWER_CODE, -1, NULL) == 0)
00471   {
00472     if(this->AddInterface(this->power_id) != 0)
00473     {
00474       this->SetError(-1);
00475       return;
00476     }
00477   }
00478 
00479   // Do we create a blobfinder interface?
00480   if(cf->ReadDeviceAddr(&(this->blobfinder_id), section, "provides",
00481                       PLAYER_BLOBFINDER_CODE, -1, NULL) == 0)
00482   {
00483     if(this->AddInterface(this->blobfinder_id) != 0)
00484     {
00485       this->SetError(-1);
00486       return;
00487     }
00488   }
00489 
00490   // Do we create a audio interface?
00491   if(cf->ReadDeviceAddr(&(this->audio_id), section, "provides",
00492                       PLAYER_AUDIO_CODE, -1, NULL) == 0)
00493   {
00494     if(this->AddInterface(this->audio_id) != 0)
00495     {
00496       this->SetError(-1);
00497       return;
00498     }
00499   }
00500 
00501   // Do we create a limb interface?
00502   if(cf->ReadDeviceAddr(&(this->limb_id), section, "provides", PLAYER_LIMB_CODE, -1, NULL) == 0)
00503   {
00504     if(this->AddInterface(this->limb_id) != 0)
00505     {
00506       this->SetError(-1);
00507       return;
00508     }
00509     // If we do, we need a kinematics calculator
00510     kineCalc = new KineCalc;
00511   }
00512   else
00513     kineCalc = NULL;
00514 
00515   // Do we create an arm gripper interface?
00516   if(cf->ReadDeviceAddr(&(this->armgripper_id), section, "provides", PLAYER_GRIPPER_CODE, -1, "armgrip") == 0)
00517   {
00518     if(this->AddInterface(this->armgripper_id) != 0)
00519     {
00520       this->SetError(-1);
00521       return;
00522     }
00523   }
00524 
00525   // Do we create an actarray interface? Note that if we have a limb or arm gripper interface,
00526   // this implies an actarray interface
00527   if((cf->ReadDeviceAddr(&(this->actarray_id), section, "provides", PLAYER_ACTARRAY_CODE, -1, "arm") == 0) ||
00528       this->limb_id.interf || this->armgripper_id.interf)
00529   {
00530     if(this->AddInterface(this->actarray_id) != 0)
00531     {
00532       this->SetError(-1);
00533       return;
00534     }
00535     // Stop actarray messages in the queue from being overwritten
00536     this->InQueue->AddReplaceRule (this->actarray_id, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_POS, false);
00537     this->InQueue->AddReplaceRule (this->actarray_id, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_SPEED, false);
00538     this->InQueue->AddReplaceRule (this->actarray_id, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_HOME, false);
00539   }
00540 
00541   // build the table of robot parameters.
00542   ::initialize_robot_params();
00543 
00544   // Read config file options
00545   this->bumpstall = cf->ReadInt(section,"bumpstall",-1);
00546   this->pulse = cf->ReadFloat(section,"pulse",-1);
00547   this->rot_kp = cf->ReadInt(section, "rot_kp", -1);
00548   this->rot_kv = cf->ReadInt(section, "rot_kv", -1);
00549   this->rot_ki = cf->ReadInt(section, "rot_ki", -1);
00550   this->trans_kp = cf->ReadInt(section, "trans_kp", -1);
00551   this->trans_kv = cf->ReadInt(section, "trans_kv", -1);
00552   this->trans_ki = cf->ReadInt(section, "trans_ki", -1);
00553 
00554   this->psos_serial_port = cf->ReadString(section,"port",DEFAULT_P2OS_PORT);
00555   //this->psos_use_tcp = cf->ReadBool(section, "use_tcp", false); // TODO after ReadBool added
00556   this->psos_use_tcp = cf->ReadInt(section, "use_tcp", 0);
00557   this->psos_tcp_host = cf->ReadString(section, "tcp_remote_host", DEFAULT_P2OS_TCP_REMOTE_HOST);
00558   this->psos_tcp_port = cf->ReadInt(section, "tcp_remote_port", DEFAULT_P2OS_TCP_REMOTE_PORT);
00559   this->radio_modemp = cf->ReadInt(section, "radio", 0);
00560   this->joystickp = cf->ReadInt(section, "joystick", 0);
00561   this->direct_wheel_vel_control =
00562           cf->ReadInt(section, "direct_wheel_vel_control", 1);
00563   this->motor_max_speed = (int)rint(1e3 * cf->ReadLength(section,
00564                                                          "max_xspeed",
00565                                                          MOTOR_DEF_MAX_SPEED));
00566   this->motor_max_turnspeed = (int)rint(RTOD(cf->ReadAngle(section,
00567                                                          "max_yawspeed",
00568                                                          MOTOR_DEF_MAX_TURNSPEED)));
00569   this->motor_max_trans_accel = (short)rint(1e3 *
00570                                             cf->ReadLength(section,
00571                                                            "max_xaccel", 0));
00572   this->motor_max_trans_decel = (short)rint(1e3 *
00573                                             cf->ReadLength(section,
00574                                                            "max_xdecel", 0));
00575   this->motor_max_rot_accel = (short)rint(RTOD(cf->ReadAngle(section,
00576                                                              "max_yawaccel",
00577                                                              0)));
00578   this->motor_max_rot_decel = (short)rint(RTOD(cf->ReadAngle(section,
00579                                                              "max_yawdecel",
00580                                                              0)));
00581 
00582   this->use_vel_band = cf->ReadInt(section, "use_vel_band", 0);
00583 
00584   // Gripper configuration
00585   gripperPose.px = cf->ReadTupleFloat(section, "gripper_pose", 0, 0.0f);
00586   gripperPose.py = cf->ReadTupleFloat(section, "gripper_pose", 1, 0.0f);
00587   gripperPose.pz = cf->ReadTupleFloat(section, "gripper_pose", 2, 0.0f);
00588   gripperPose.proll = cf->ReadTupleFloat(section, "gripper_pose", 3, 0.0f);
00589   gripperPose.ppitch = cf->ReadTupleFloat(section, "gripper_pose", 4, 0.0f);
00590   gripperPose.pyaw = cf->ReadTupleFloat(section, "gripper_pose", 5, 0.0f);
00591   gripperOuterSize.sw = cf->ReadTupleFloat(section, "gripper_outersize", 0, 0.315f);
00592   gripperOuterSize.sl = cf->ReadTupleFloat(section, "gripper_outersize", 1, 0.195f);
00593   gripperOuterSize.sh = cf->ReadTupleFloat(section, "gripper_outersize", 2, 0.035f);
00594   gripperInnerSize.sw = cf->ReadTupleFloat(section, "gripper_innersize", 0, 0.205f);
00595   gripperInnerSize.sl = cf->ReadTupleFloat(section, "gripper_innersize", 1, 0.095f);
00596   gripperInnerSize.sh = cf->ReadTupleFloat(section, "gripper_innersize", 2, 0.035f);
00597 
00598   // Arm gripper configuration
00599   armGripperOuterSize.sw = cf->ReadTupleFloat(section, "armgrip_outersize", 0, 0.09f);
00600   armGripperOuterSize.sl = cf->ReadTupleFloat(section, "armgrip_outersize", 1, 0.09f);
00601   armGripperOuterSize.sh = cf->ReadTupleFloat(section, "armgrip_outersize", 2, 0.041f);
00602   armGripperInnerSize.sw = cf->ReadTupleFloat(section, "armgrip_innersize", 0, 0.054f);
00603   armGripperInnerSize.sl = cf->ReadTupleFloat(section, "armgrip_innersize", 1, 0.025f);
00604   armGripperInnerSize.sh = cf->ReadTupleFloat(section, "armgrip_innersize", 2, 1.0f);
00605 
00606   // Actarray configuration
00607   // Offsets
00608   aaLengths[0] = cf->ReadTupleFloat(section, "aa_offsets", 1, 0.06875f);
00609   aaLengths[1] = cf->ReadTupleFloat(section, "aa_offsets", 2, 0.16f);
00610   aaLengths[2] = cf->ReadTupleFloat(section, "aa_offsets", 3, 0.0925f);
00611   aaLengths[3] = cf->ReadTupleFloat(section, "aa_offsets", 4, 0.05f);
00612   aaLengths[4] = cf->ReadTupleFloat(section, "aa_offsets", 5, 0.085f);
00613   aaLengths[5] = cf->ReadTupleFloat(section, "aa_offsets", 0, 0.0f);
00614   // Orientations default: all zeros
00615   for (int ii = 0; ii < 18; ii++)
00616   {
00617     aaOrients[ii] = cf->ReadTupleFloat(section, "aa_orients", ii, 0.0f);
00618   }
00619   // Joint 0 default: (0, 0, 1)
00620   aaAxes[0] = cf->ReadTupleFloat(section, "aa_axes", 0, 0.0f);
00621   aaAxes[1] = cf->ReadTupleFloat(section, "aa_axes", 1, 0.0f);
00622   aaAxes[2] = cf->ReadTupleFloat(section, "aa_axes", 2, -1.0f);
00623   // Joint 1 default: (0, 1, 0)
00624   aaAxes[3] = cf->ReadTupleFloat(section, "aa_axes", 3, 0.0f);
00625   aaAxes[4] = cf->ReadTupleFloat(section, "aa_axes", 4, -1.0f);
00626   aaAxes[5] = cf->ReadTupleFloat(section, "aa_axes", 5, 0.0f);
00627   // Joint 2 default: (0, 1, 0)
00628   aaAxes[6] = cf->ReadTupleFloat(section, "aa_axes", 6, 0.0f);
00629   aaAxes[7] = cf->ReadTupleFloat(section, "aa_axes", 7, -1.0f);
00630   aaAxes[8] = cf->ReadTupleFloat(section, "aa_axes", 8, 0.0f);
00631   // Joint 3 default: (1, 0, 0)
00632   aaAxes[9] = cf->ReadTupleFloat(section, "aa_axes", 9, 1.0f);
00633   aaAxes[10] = cf->ReadTupleFloat(section, "aa_axes", 10, 0.0f);
00634   aaAxes[11] = cf->ReadTupleFloat(section, "aa_axes", 11, 0.0f);
00635   // Joint 4 default: (0, 1, 0)
00636   aaAxes[12] = cf->ReadTupleFloat(section, "aa_axes", 12, 0.0f);
00637   aaAxes[13] = cf->ReadTupleFloat(section, "aa_axes", 13, 1.0f);
00638   aaAxes[14] = cf->ReadTupleFloat(section, "aa_axes", 14, 0.0f);
00639   // Joint 5 default: (0, 0, 1)
00640   aaAxes[15] = cf->ReadTupleFloat(section, "aa_axes", 15, 0.0f);
00641   aaAxes[16] = cf->ReadTupleFloat(section, "aa_axes", 16, 0.0f);
00642   aaAxes[17] = cf->ReadTupleFloat(section, "aa_axes", 17, 1.0f);
00643   // Joint base position, orientation
00644   aaBasePos.px = cf->ReadTupleFloat(section, "aa_basepos", 0, 0.105f);
00645   aaBasePos.py = cf->ReadTupleFloat(section, "aa_basepos", 1, 0.0f);
00646   aaBasePos.pz = cf->ReadTupleFloat(section, "aa_basepos", 2, 0.3185f);
00647   aaBaseOrient.proll = cf->ReadTupleFloat(section, "aa_baseorient", 0, 0.0f);
00648   aaBaseOrient.ppitch = cf->ReadTupleFloat(section, "aa_baseorient", 1, 0.0f);
00649   aaBaseOrient.pyaw = cf->ReadTupleFloat(section, "aa_baseorient", 2, 0.0f);
00650   // Limb configuration
00651   if(kineCalc)
00652   {
00653     limb_data.state = PLAYER_LIMB_STATE_IDLE;
00654     armOffsetX = cf->ReadTupleFloat(section, "limb_pos", 0, 0.105f);
00655     armOffsetY = cf->ReadTupleFloat(section, "limb_pos", 1, 0.0f);
00656     armOffsetZ = cf->ReadTupleFloat(section, "limb_pos", 2, 0.3185f);
00657     double temp1 = cf->ReadTupleFloat(section, "limb_links", 0, 0.06875f);
00658     double temp2 = cf->ReadTupleFloat(section, "limb_links", 1, 0.16f);
00659     double temp3 = cf->ReadTupleFloat(section, "limb_links", 2, 0.0f);
00660     double temp4 = cf->ReadTupleFloat(section, "limb_links", 3, 0.13775f);
00661     double temp5 = cf->ReadTupleFloat(section, "limb_links", 4, 0.11321f);
00662     kineCalc->SetLinkLengths (temp1, temp2, temp3, temp4, temp5);
00663     kineCalc->SetOffset (0, cf->ReadTupleFloat(section, "limb_offsets", 0, 0.0f));
00664     kineCalc->SetOffset (0, cf->ReadTupleFloat(section, "limb_offsets", 1, 0.0f));
00665     kineCalc->SetOffset (0, cf->ReadTupleFloat(section, "limb_offsets", 2, 0.0f));
00666     kineCalc->SetOffset (0, cf->ReadTupleFloat(section, "limb_offsets", 3, 0.0f));
00667     kineCalc->SetOffset (0, cf->ReadTupleFloat(section, "limb_offsets", 4, 0.0f));
00668   }
00669 
00670   this->psos_fd = -1;
00671 
00672   sentGripperCmd = false;
00673   sentArmGripperCmd = true;
00674   lastGripperCmd = lastLiftCmd = lastArmGripperCmd = lastActArrayCmd = 255;
00675   memset (&lastLiftPosCmd, 0, sizeof (player_actarray_position_cmd_t));
00676   memset (&lastActArrayPosCmd, 0, sizeof (player_actarray_position_cmd_t));
00677 }
00678 
00679 int P2OS::Setup()
00680 {
00681   int i;
00682   // this is the order in which we'll try the possible baud rates. we try 9600
00683   // first because most robots use it, and because otherwise the radio modem
00684   // connection code might not work (i think that the radio modems operate at
00685   // 9600).
00686   int bauds[] = {B9600, B38400, B19200, B115200, B57600};
00687   int numbauds = sizeof(bauds);
00688   int currbaud = 0;
00689 
00690   struct termios term;
00691   unsigned char command;
00692   P2OSPacket packet, receivedpacket;
00693   int flags=0;
00694   bool sent_close = false;
00695   enum
00696   {
00697     NO_SYNC,
00698     AFTER_FIRST_SYNC,
00699     AFTER_SECOND_SYNC,
00700     READY
00701   } psos_state;
00702 
00703   psos_state = NO_SYNC;
00704 
00705   char name[20], type[20], subtype[20];
00706   int cnt;
00707 
00708 
00709   if(this->psos_use_tcp)
00710   {
00711 
00712     // TCP socket:
00713 
00714     printf("P2OS connecting to remote host (%s:%d)... ", this->psos_tcp_host, this->psos_tcp_port);
00715     fflush(stdout);
00716     if( (this->psos_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
00717     {
00718       perror("P2OS::Setup():socket():");
00719       return(1);
00720     }
00721     //printf("created socket %d.\nLooking up hostname...\n", this->psos_fd);
00722     struct hostent* h = gethostbyname(this->psos_tcp_host);
00723     if(!h)
00724     {
00725       perror("Error looking up hostname or address %s:");
00726       return(1);
00727     }
00728     struct sockaddr_in addr;
00729     assert((size_t)h->h_length <= sizeof(addr.sin_addr));
00730     //printf("gethostbyname returned address %d length %d.\n", * h->h_addr, h->h_length);
00731     memcpy(&(addr.sin_addr), h->h_addr, h->h_length);
00732     //printf("copied address to addr.sin_addr.s_addr=%d\n", addr.sin_addr.s_addr);
00733     addr.sin_family = AF_INET;
00734     addr.sin_port = htons(this->psos_tcp_port);
00735     printf("Found host address, connecting...");
00736     fflush(stdout);
00737     if(connect(this->psos_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
00738     {
00739       perror("Error Connecting to remote host (P2OS::Setup()::connect()):");
00740       return(1);
00741     }
00742     fcntl(this->psos_fd, F_SETFL, O_SYNC | O_NONBLOCK);
00743     if((flags = fcntl(this->psos_fd, F_GETFL)) < 0)
00744     {
00745       perror("P2OS::Setup():fcntl()");
00746       close(this->psos_fd);
00747       this->psos_fd = -1;
00748       return(1);
00749     }
00750     assert(flags & O_NONBLOCK);
00751     printf("TCP socket connection is OK... ");
00752     fflush(stdout);
00753   }
00754   else
00755   {
00756 
00757     // Serial port:
00758 
00759     printf("P2OS connection opening serial port %s...",this->psos_serial_port);
00760     fflush(stdout);
00761 
00762     if((this->psos_fd = open(this->psos_serial_port,
00763                      O_RDWR | O_SYNC | O_NONBLOCK, S_IRUSR | S_IWUSR )) < 0 )
00764     {
00765       perror("P2OS::Setup():open():");
00766       return(1);
00767     }
00768 
00769     if(tcgetattr( this->psos_fd, &term ) < 0 )
00770     {
00771       perror("P2OS::Setup():tcgetattr():");
00772       close(this->psos_fd);
00773       this->psos_fd = -1;
00774       return(1);
00775     }
00776 
00777     cfmakeraw( &term );
00778     cfsetispeed(&term, bauds[currbaud]);
00779     cfsetospeed(&term, bauds[currbaud]);
00780 
00781 #if defined (__APPLE__)
00782                /* CLOCAL:      Local connection (no modem control) */
00783                /* CREAD:       Enable the receiver */
00784                term.c_cflag |= (CLOCAL | CREAD);
00785 
00786                /* PARENB:      Use NO parity */
00787                /* CSTOPB:      Use 1 stop bit */
00788                /* CSIZE:       Next two constants: */
00789                /* CS8:         Use 8 data bits */
00790                term.c_cflag &= ~PARENB;
00791                term.c_cflag &= ~CSTOPB;
00792                term.c_cflag &= ~CSIZE;
00793                term.c_cflag |= CS8;
00794 
00795                /* IGNPAR:      Ignore bytes with parity errors */
00796                /* ICRNL:       Map CR to NL (otherwise a CR input on  the other computer will not terminate input) */
00797                term.c_iflag |= (IGNPAR | IGNBRK);
00798 
00799                /* No flags at all for output control  */
00800                term.c_oflag = 0;
00801 
00802                /* IXON:        Disable software flow control  (incoming) */
00803                /* IXOFF:       Disable software flow control  (outgoing) */
00804                /* IXANY:       Disable software flow control (any  character can start flow control */
00805                term.c_iflag &= ~(IXON | IXOFF | IXANY);
00806 
00807                /* NO FLAGS AT ALL FOR LFLAGS */
00808                term.c_lflag = 0;
00809 
00810                /* Clean the modem line and activate new port  settings */
00811                tcflush(this->psos_fd, TCIOFLUSH);
00812                if (tcsetattr(this->psos_fd, TCSANOW, &term) < 0) {
00813                        perror("P2OS::Setup():tcsetattr()");
00814                        close(this->psos_fd);
00815                        this->psos_fd = -1;
00816                        return(1);
00817                }
00818 #else
00819     if(tcsetattr(this->psos_fd, TCSAFLUSH, &term ) < 0)
00820     {
00821       perror("P2OS::Setup():tcsetattr():");
00822       close(this->psos_fd);
00823       this->psos_fd = -1;
00824       return(1);
00825     }
00826 
00827     if(tcflush(this->psos_fd, TCIOFLUSH ) < 0)
00828     {
00829       perror("P2OS::Setup():tcflush():");
00830       close(this->psos_fd);
00831       this->psos_fd = -1;
00832       return(1);
00833     }
00834 
00835     if((flags = fcntl(this->psos_fd, F_GETFL)) < 0)
00836     {
00837       perror("P2OS::Setup():fcntl()");
00838       close(this->psos_fd);
00839       this->psos_fd = -1;
00840       return(1);
00841     }
00842 #endif
00843 
00844     // radio modem initialization code, courtesy of Kim Jinsuck
00845     //   <jinsuckk@cs.tamu.edu>
00846     if(this->radio_modemp)
00847     {
00848       puts("Initializing radio modem...");
00849       write(this->psos_fd, "WMS2\r", 5);
00850 
00851       usleep(50000);
00852       char modem_buf[50];
00853       int buf_len = read(this->psos_fd, modem_buf, 5);          // get "WMS2"
00854       modem_buf[buf_len]='\0';
00855       printf("wireless modem response = %s\n", modem_buf);
00856 
00857       usleep(10000);
00858       // get "\n\rConnecting..." --> \n\r is my guess
00859       buf_len = read(this->psos_fd, modem_buf, 14);
00860       modem_buf[buf_len]='\0';
00861       printf("wireless modem response = %s\n", modem_buf);
00862 
00863       // wait until get "Connected to address 2"
00864       int modem_connect_try = 10;
00865       while(strstr(modem_buf, "ected to addres") == NULL)
00866       {
00867         puts("Initializing radio modem...");
00868         write(this->psos_fd, "WMS2\r", 5);
00869 
00870         usleep(50000);
00871         char modem_buf[50];
00872         int buf_len = read(this->psos_fd, modem_buf, 5);          // get "WMS2"
00873         modem_buf[buf_len]='\0';
00874         printf("wireless modem response = %s\n", modem_buf);
00875         // if "Partner busy!"
00876         if(modem_buf[2] == 'P')
00877         {
00878           printf("Please reset partner modem and try again\n");
00879           return(1);
00880         }
00881         // if "\n\rPartner not found!"
00882         if(modem_buf[0] == 'P')
00883         {
00884           printf("Please check partner modem and try again\n");
00885           return(1);
00886         }
00887         if(modem_connect_try-- == 0)
00888         {
00889           usleep(300000);
00890           buf_len = read(this->psos_fd, modem_buf, 40);
00891           modem_buf[buf_len]='\0';
00892           printf("wireless modem response = %s\n", modem_buf);
00893           // if "Partner busy!"
00894           if(modem_buf[2] == 'P')
00895           {
00896             printf("Please reset partner modem and try again\n");
00897             return(1);
00898           }
00899           // if "\n\rPartner not found!"
00900           if(modem_buf[0] == 'P')
00901           {
00902             printf("Please check partner modem and try again\n");
00903             return(1);
00904           }
00905           if(modem_connect_try-- == 0)
00906           {
00907             puts("Failed to connect radio modem, Trying direct connection...");
00908             break;
00909           }
00910         }
00911       }
00912     }
00913     printf("Connected to robot device, handshaking with P2OS...");
00914     fflush(stdout);
00915   }// end TCP socket or serial port.
00916 
00917   // Sync:
00918 
00919   int num_sync_attempts = 3;
00920   while(psos_state != READY)
00921   {
00922     switch(psos_state)
00923     {
00924       case NO_SYNC:
00925         command = SYNC0;
00926         packet.Build(&command, 1);
00927         packet.Send(this->psos_fd);
00928         usleep(P2OS_CYCLETIME_USEC);
00929         break;
00930       case AFTER_FIRST_SYNC:
00931         printf("turning off NONBLOCK mode...\n");
00932         if(fcntl(this->psos_fd, F_SETFL, flags ^ O_NONBLOCK) < 0)
00933         {
00934           perror("P2OS::Setup():fcntl()");
00935           close(this->psos_fd);
00936           this->psos_fd = -1;
00937           return(1);
00938         }
00939         command = SYNC1;
00940         packet.Build(&command, 1);
00941         packet.Send(this->psos_fd);
00942         break;
00943       case AFTER_SECOND_SYNC:
00944         command = SYNC2;
00945         packet.Build(&command, 1);
00946         packet.Send(this->psos_fd);
00947         break;
00948       default:
00949         puts("P2OS::Setup():shouldn't be here...");
00950         break;
00951     }
00952     usleep(P2OS_CYCLETIME_USEC);
00953 
00954     if(receivedpacket.Receive(this->psos_fd))
00955     {
00956       if((psos_state == NO_SYNC) && (num_sync_attempts >= 0))
00957       {
00958         num_sync_attempts--;
00959         usleep(P2OS_CYCLETIME_USEC);
00960         continue;
00961       }
00962       else
00963       {
00964         // couldn't connect; try different speed.
00965         if(++currbaud < numbauds)
00966         {
00967           cfsetispeed(&term, bauds[currbaud]);
00968           cfsetospeed(&term, bauds[currbaud]);
00969           if( tcsetattr(this->psos_fd, TCSAFLUSH, &term ) < 0 )
00970           {
00971             perror("P2OS::Setup():tcsetattr():");
00972             close(this->psos_fd);
00973             this->psos_fd = -1;
00974             return(1);
00975           }
00976 
00977           if(tcflush(this->psos_fd, TCIOFLUSH ) < 0 )
00978           {
00979             perror("P2OS::Setup():tcflush():");
00980             close(this->psos_fd);
00981             this->psos_fd = -1;
00982             return(1);
00983           }
00984           num_sync_attempts = 3;
00985           continue;
00986         }
00987         else
00988         {
00989           // tried all speeds; bail
00990           break;
00991         }
00992       }
00993     }
00994 
00995     switch(receivedpacket.packet[3])
00996     {
00997       case SYNC0:
00998         psos_state = AFTER_FIRST_SYNC;
00999         break;
01000       case SYNC1:
01001         psos_state = AFTER_SECOND_SYNC;
01002         break;
01003       case SYNC2:
01004         psos_state = READY;
01005         break;
01006       default:
01007         // maybe P2OS is still running from last time.  let's try to CLOSE
01008         // and reconnect
01009         if(!sent_close)
01010         {
01011           //puts("sending CLOSE");
01012           command = CLOSE;
01013           packet.Build( &command, 1);
01014           packet.Send(this->psos_fd);
01015           sent_close = true;
01016           usleep(2*P2OS_CYCLETIME_USEC);
01017           tcflush(this->psos_fd,TCIFLUSH);
01018           psos_state = NO_SYNC;
01019         }
01020         break;
01021     }
01022     usleep(P2OS_CYCLETIME_USEC);
01023   }
01024 
01025   if(psos_state != READY)
01026   {
01027     if(this->psos_use_tcp)
01028     printf("Couldn't synchronize with P2OS.\n"
01029            "  Most likely because the robot is not connected %s %s\n",
01030            this->psos_use_tcp ? "to the ethernet-serial bridge device " : "to the serial port",
01031            this->psos_use_tcp ? this->psos_tcp_host : this->psos_serial_port);
01032     close(this->psos_fd);
01033     this->psos_fd = -1;
01034     return(1);
01035   }
01036 
01037   cnt = 4;
01038   cnt += sprintf(name, "%s", &receivedpacket.packet[cnt]);
01039   cnt++;
01040   cnt += sprintf(type, "%s", &receivedpacket.packet[cnt]);
01041   cnt++;
01042   cnt += sprintf(subtype, "%s", &receivedpacket.packet[cnt]);
01043   cnt++;
01044 
01045 
01046   command = OPEN;
01047   packet.Build(&command, 1);
01048   packet.Send(this->psos_fd);
01049   usleep(P2OS_CYCLETIME_USEC);
01050 
01051   command = PULSE;
01052   packet.Build(&command, 1);
01053   packet.Send(this->psos_fd);
01054   usleep(P2OS_CYCLETIME_USEC);
01055 
01056   printf("Done.\n   Connected to %s, a %s %s\n", name, type, subtype);
01057 
01058   // now, based on robot type, find the right set of parameters
01059   for(i=0;i<PLAYER_NUM_ROBOT_TYPES;i++)
01060   {
01061     if(!strcasecmp(PlayerRobotParams[i].Class,type) &&
01062        !strcasecmp(PlayerRobotParams[i].Subclass,subtype))
01063     {
01064       param_idx = i;
01065       break;
01066     }
01067   }
01068   if(i == PLAYER_NUM_ROBOT_TYPES)
01069   {
01070     fputs("P2OS: Warning: couldn't find parameters for this robot; "
01071             "using defaults\n",stderr);
01072     param_idx = 0;
01073   }
01074 
01075   // first, receive a packet so we know we're connected.
01076   if(!this->sippacket)
01077     this->sippacket = new SIP(param_idx);
01078 
01079   this->sippacket->x_offset = 0;
01080   this->sippacket->y_offset = 0;
01081   this->sippacket->angle_offset = 0;
01082 
01083   SendReceive((P2OSPacket*)NULL,false);
01084 
01085   // turn off the sonars at first
01086   this->ToggleSonarPower(0);
01087 
01088   if(this->joystickp)
01089   {
01090     // enable joystick control
01091     P2OSPacket js_packet;
01092     unsigned char js_command[4];
01093     js_command[0] = JOYDRIVE;
01094     js_command[1] = ARGINT;
01095     js_command[2] = 1;
01096     js_command[3] = 0;
01097     js_packet.Build(js_command, 4);
01098     this->SendReceive(&js_packet,false);
01099   }
01100 
01101   if(this->blobfinder_id.interf)
01102     CMUcamReset(false);
01103 
01104   if(this->gyro_id.interf)
01105   {
01106     // request that gyro data be sent each cycle
01107     P2OSPacket gyro_packet;
01108     unsigned char gyro_command[4];
01109     gyro_command[0] = GYRO;
01110     gyro_command[1] = ARGINT;
01111     gyro_command[2] = 1;
01112     gyro_command[3] = 0;
01113     gyro_packet.Build(gyro_command, 4);
01114     this->SendReceive(&gyro_packet,false);
01115   }
01116 
01117   if (this->actarray_id.interf)
01118   {
01119     // Start a continuous stream of ARMpac packets
01120     P2OSPacket aaPacket;
01121     unsigned char aaCmd[4];
01122     aaCmd[0] = ARM_STATUS;
01123     aaCmd[1] = ARGINT;
01124     aaCmd[2] = 2;
01125     aaCmd[3] = 0;
01126     aaPacket.Build (aaCmd, 4);
01127     SendReceive (&aaPacket,false);
01128     // Ask for an ARMINFOpac packet too
01129     aaCmd[0] = ARM_INFO;
01130     aaPacket.Build (aaCmd, 1);
01131     SendReceive (&aaPacket,false);
01132   }
01133 
01134   // if requested, set max accel/decel limits
01135   P2OSPacket accel_packet;
01136   unsigned char accel_command[4];
01137   if(this->motor_max_trans_accel > 0)
01138   {
01139     accel_command[0] = SETA;
01140     accel_command[1] = ARGINT;
01141     accel_command[2] = this->motor_max_trans_accel & 0x00FF;
01142     accel_command[3] = (this->motor_max_trans_accel & 0xFF00) >> 8;
01143     accel_packet.Build(accel_command, 4);
01144     this->SendReceive(&accel_packet,false);
01145   }
01146 
01147   if(this->motor_max_trans_decel < 0)
01148   {
01149     accel_command[0] = SETA;
01150     accel_command[1] = ARGNINT;
01151     accel_command[2] = abs(this->motor_max_trans_decel) & 0x00FF;
01152     accel_command[3] = (abs(this->motor_max_trans_decel) & 0xFF00) >> 8;
01153     accel_packet.Build(accel_command, 4);
01154     this->SendReceive(&accel_packet,false);
01155   }
01156   if(this->motor_max_rot_accel > 0)
01157   {
01158     accel_command[0] = SETRA;
01159     accel_command[1] = ARGINT;
01160     accel_command[2] = this->motor_max_rot_accel & 0x00FF;
01161     accel_command[3] = (this->motor_max_rot_accel & 0xFF00) >> 8;
01162     accel_packet.Build(accel_command, 4);
01163     this->SendReceive(&accel_packet,false);
01164   }
01165   if(this->motor_max_rot_decel < 0)
01166   {
01167     accel_command[0] = SETRA;
01168     accel_command[1] = ARGNINT;
01169     accel_command[2] = abs(this->motor_max_rot_decel) & 0x00FF;
01170     accel_command[3] = (abs(this->motor_max_rot_decel) & 0xFF00) >> 8;
01171     accel_packet.Build(accel_command, 4);
01172     this->SendReceive(&accel_packet,false);
01173   }
01174 
01175 
01176   // if requested, change PID settings
01177   P2OSPacket pid_packet;
01178   unsigned char pid_command[4];
01179   if(this->rot_kp >= 0)
01180   {
01181     pid_command[0] = ROTKP;
01182     pid_command[1] = ARGINT;
01183     pid_command[2] = this->rot_kp & 0x00FF;
01184     pid_command[3] = (this->rot_kp & 0xFF00) >> 8;
01185     pid_packet.Build(pid_command, 4);
01186     this->SendReceive(&pid_packet);
01187   }
01188   if(this->rot_kv >= 0)
01189   {
01190     pid_command[0] = ROTKV;
01191     pid_command[1] = ARGINT;
01192     pid_command[2] = this->rot_kv & 0x00FF;
01193     pid_command[3] = (this->rot_kv & 0xFF00) >> 8;
01194     pid_packet.Build(pid_command, 4);
01195     this->SendReceive(&pid_packet);
01196   }
01197   if(this->rot_ki >= 0)
01198   {
01199     pid_command[0] = ROTKI;
01200     pid_command[1] = ARGINT;
01201     pid_command[2] = this->rot_ki & 0x00FF;
01202     pid_command[3] = (this->rot_ki & 0xFF00) >> 8;
01203     pid_packet.Build(pid_command, 4);
01204     this->SendReceive(&pid_packet);
01205   }
01206   if(this->trans_kp >= 0)
01207   {
01208     pid_command[0] = TRANSKP;
01209     pid_command[1] = ARGINT;
01210     pid_command[2] = this->trans_kp & 0x00FF;
01211     pid_command[3] = (this->trans_kp & 0xFF00) >> 8;
01212     pid_packet.Build(pid_command, 4);
01213     this->SendReceive(&pid_packet);
01214   }
01215   if(this->trans_kv >= 0)
01216   {
01217     pid_command[0] = TRANSKV;
01218     pid_command[1] = ARGINT;
01219     pid_command[2] = this->trans_kv & 0x00FF;
01220     pid_command[3] = (this->trans_kv & 0xFF00) >> 8;
01221     pid_packet.Build(pid_command, 4);
01222     this->SendReceive(&pid_packet);
01223   }
01224   if(this->trans_ki >= 0)
01225   {
01226     pid_command[0] = TRANSKI;
01227     pid_command[1] = ARGINT;
01228     pid_command[2] = this->trans_ki & 0x00FF;
01229     pid_command[3] = (this->trans_ki & 0xFF00) >> 8;
01230     pid_packet.Build(pid_command, 4);
01231     this->SendReceive(&pid_packet);
01232   }
01233 
01234 
01235   // if requested, change bumper-stall behavior
01236   // 0 = don't stall
01237   // 1 = stall on front bumper contact
01238   // 2 = stall on rear bumper contact
01239   // 3 = stall on either bumper contact
01240   if(this->bumpstall >= 0)
01241   {
01242     if(this->bumpstall > 3)
01243       PLAYER_ERROR1("ignoring bumpstall value %d; should be 0, 1, 2, or 3",
01244                     this->bumpstall);
01245     else
01246     {
01247       PLAYER_MSG1(1, "setting bumpstall to %d", this->bumpstall);
01248       P2OSPacket bumpstall_packet;;
01249       unsigned char bumpstall_command[4];
01250       bumpstall_command[0] = BUMP_STALL;
01251       bumpstall_command[1] = ARGINT;
01252       bumpstall_command[2] = (unsigned char)this->bumpstall;
01253       bumpstall_command[3] = 0;
01254       bumpstall_packet.Build(bumpstall_command, 4);
01255       this->SendReceive(&bumpstall_packet,false);
01256     }
01257   }
01258 
01259 
01260   // TODO: figure out what the right behavior here is
01261 #if 0
01262   // zero position command buffer
01263   player_position_cmd_t zero;
01264   memset(&zero,0,sizeof(player_position_cmd_t));
01265   this->PutCommand(this->position_id,(void*)&zero,
01266                    sizeof(player_position_cmd_t),NULL);
01267 #endif
01268 
01269   /* now spawn reading thread */
01270   this->StartThread();
01271   return(0);
01272 }
01273 
01274 int P2OS::Shutdown()
01275 {
01276   unsigned char command[20],buffer[20];
01277   P2OSPacket packet;
01278 
01279   memset(buffer,0,20);
01280 
01281   if(this->psos_fd == -1)
01282     return(0);
01283 
01284   this->StopThread();
01285 
01286   command[0] = STOP;
01287   packet.Build(command, 1);
01288   packet.Send(this->psos_fd);
01289   usleep(P2OS_CYCLETIME_USEC);
01290 
01291   command[0] = CLOSE;
01292   packet.Build(command, 1);
01293   packet.Send(this->psos_fd);
01294   usleep(P2OS_CYCLETIME_USEC);
01295 
01296   close(this->psos_fd);
01297   this->psos_fd = -1;
01298   puts("P2OS has been shutdown");
01299   delete this->sippacket;
01300   this->sippacket = NULL;
01301 
01302   return(0);
01303 }
01304 
01305 P2OS::~P2OS (void)
01306 {
01307   player_position2d_data_t_cleanup(&p2os_data.position);
01308   player_sonar_data_t_cleanup (&p2os_data.sonar);
01309   player_gripper_data_t_cleanup (&p2os_data.gripper);
01310   player_gripper_data_t_cleanup (&p2os_data.armGripper);
01311   player_power_data_t_cleanup (&p2os_data.power);
01312   player_bumper_data_t_cleanup (&p2os_data.bumper);
01313   player_dio_data_t_cleanup (&p2os_data.dio);
01314   player_aio_data_t_cleanup (&p2os_data.aio);
01315   player_blobfinder_data_t_cleanup (&p2os_data.blobfinder);
01316   player_position2d_data_t_cleanup (&p2os_data.compass);
01317   player_position2d_data_t_cleanup (&p2os_data.gyro);
01318   player_actarray_data_t_cleanup (&p2os_data.lift);
01319   player_actarray_data_t_cleanup (&p2os_data.actArray);
01320 
01321   if (kineCalc)
01322   {
01323     delete kineCalc;
01324     kineCalc = NULL;
01325   }
01326 }
01327 
01328 int
01329 P2OS::Subscribe(player_devaddr_t id)
01330 {
01331   int setupResult;
01332 
01333   // do the subscription
01334   if((setupResult = Driver::Subscribe(id)) == 0)
01335   {
01336     // also increment the appropriate subscription counter
01337     if(Device::MatchDeviceAddress(id, this->position_id))
01338       this->position_subscriptions++;
01339     else if(Device::MatchDeviceAddress(id, this->sonar_id))
01340       this->sonar_subscriptions++;
01341     else if(Device::MatchDeviceAddress(id, this->actarray_id) ||
01342             Device::MatchDeviceAddress(id, this->limb_id) ||
01343             Device::MatchDeviceAddress(id, this->armgripper_id))
01344       // We use the actarray subscriptions count for the limb and arm gripper
01345       // interfaces too since they're the same physical hardware
01346       this->actarray_subscriptions++;
01347   }
01348 
01349   return(setupResult);
01350 }
01351 
01352 int
01353 P2OS::Unsubscribe(player_devaddr_t id)
01354 {
01355   int shutdownResult;
01356 
01357   // do the unsubscription
01358   if((shutdownResult = Driver::Unsubscribe(id)) == 0)
01359   {
01360     // also decrement the appropriate subscription counter
01361     if(Device::MatchDeviceAddress(id, this->position_id))
01362     {
01363       this->position_subscriptions--;
01364       assert(this->position_subscriptions >= 0);
01365     }
01366     else if(Device::MatchDeviceAddress(id, this->sonar_id))
01367     {
01368       this->sonar_subscriptions--;
01369       assert(this->sonar_subscriptions >= 0);
01370     }
01371     else if(Device::MatchDeviceAddress(id, this->actarray_id) ||
01372             Device::MatchDeviceAddress(id, this->limb_id) ||
01373             Device::MatchDeviceAddress(id, this->armgripper_id))
01374     {
01375       // We use the actarray subscriptions count for the limb
01376       // interface too since they're the same physical hardware
01377       this->actarray_subscriptions--;
01378       assert(this->actarray_subscriptions >= 0);
01379     }
01380   }
01381 
01382   return(shutdownResult);
01383 }
01384 
01385 void
01386 P2OS::StandardSIPPutData(double timestampStandardSIP)
01387 {
01388   // put odometry data
01389   this->Publish(this->position_id,
01390                 PLAYER_MSGTYPE_DATA,
01391                 PLAYER_POSITION2D_DATA_STATE,
01392                 (void*)&(this->p2os_data.position),
01393                 sizeof(player_position2d_data_t),
01394                 &timestampStandardSIP);
01395 
01396   // put sonar data
01397   this->Publish(this->sonar_id,
01398                 PLAYER_MSGTYPE_DATA,
01399                 PLAYER_SONAR_DATA_RANGES,
01400                 (void*)&(this->p2os_data.sonar),
01401                 sizeof(player_sonar_data_t),
01402                 &timestampStandardSIP);
01403   delete this->p2os_data.sonar.ranges;
01404 
01405   // put aio data
01406   this->Publish(this->aio_id,
01407                 PLAYER_MSGTYPE_DATA,
01408                 PLAYER_AIO_DATA_STATE,
01409                 (void*)&(this->p2os_data.aio),
01410                 sizeof(player_aio_data_t),
01411                 &timestampStandardSIP);
01412 
01413   // put dio data
01414   this->Publish(this->dio_id,
01415                 PLAYER_MSGTYPE_DATA,
01416                 PLAYER_DIO_DATA_VALUES,
01417                 (void*)&(this->p2os_data.dio),
01418                 sizeof(player_dio_data_t),
01419                 &timestampStandardSIP);
01420 
01421   // put gripper data
01422   this->Publish(this->gripper_id,
01423                 PLAYER_MSGTYPE_DATA,
01424                 PLAYER_GRIPPER_DATA_STATE,
01425                 (void*)&(this->p2os_data.gripper),
01426                 sizeof(player_gripper_data_t),
01427                 &timestampStandardSIP);
01428 
01429   // put lift data
01430   this->Publish(this->lift_id,
01431                 PLAYER_MSGTYPE_DATA,
01432                 PLAYER_ACTARRAY_DATA_STATE,
01433                 (void*)&(this->p2os_data.lift),
01434                 sizeof(player_actarray_data_t),
01435                 &timestampStandardSIP);
01436 
01437   // put bumper data
01438   this->Publish(this->bumper_id,
01439                 PLAYER_MSGTYPE_DATA,
01440                 PLAYER_BUMPER_DATA_STATE,
01441                 (void*)&(this->p2os_data.bumper),
01442                 sizeof(player_bumper_data_t),
01443                 &timestampStandardSIP);
01444 
01445   // put power data
01446   this->Publish(this->power_id,
01447                 PLAYER_MSGTYPE_DATA,
01448                 PLAYER_POWER_DATA_STATE,
01449                 (void*)&(this->p2os_data.power),
01450                 sizeof(player_power_data_t),
01451                 &timestampStandardSIP);
01452 
01453   // put compass data
01454   this->Publish(this->compass_id,
01455                 PLAYER_MSGTYPE_DATA,
01456                 PLAYER_POSITION2D_DATA_STATE,
01457                 (void*)&(this->p2os_data.compass),
01458                 sizeof(player_position2d_data_t),
01459                 &timestampStandardSIP);
01460 }
01461 
01462 void
01463 P2OS::GyroPutData(double timestampGyro)
01464 {
01465   // put gyro data
01466   this->Publish(this->gyro_id,
01467                 PLAYER_MSGTYPE_DATA,
01468                 PLAYER_POSITION2D_DATA_STATE,
01469                 (void*)&(this->p2os_data.gyro),
01470                 sizeof(player_position2d_data_t),
01471                 &timestampGyro);
01472 }
01473 
01474 void
01475 P2OS::BlobfinderPutData(double timestampSERAUX)
01476 {
01477   // put blobfinder data
01478   this->Publish(this->blobfinder_id,
01479                 PLAYER_MSGTYPE_DATA,
01480                 PLAYER_BLOBFINDER_DATA_BLOBS,
01481                 (void*)&(this->p2os_data.blobfinder),
01482                 sizeof(player_blobfinder_data_t),
01483                 &timestampSERAUX);
01484 }
01485 
01486 void
01487 P2OS::ActarrayPutData(double timestampArm)
01488 {
01489   // put actarray data
01490   this->Publish(this->actarray_id,
01491                 PLAYER_MSGTYPE_DATA,
01492                 PLAYER_ACTARRAY_DATA_STATE,
01493                 (void*)&(this->p2os_data.actArray),
01494                 sizeof(player_actarray_data_t),
01495                 &timestampArm);
01496   delete[] this->p2os_data.actArray.actuators;
01497 
01498   // put limb data
01499   this->Publish(this->limb_id,
01500                 PLAYER_MSGTYPE_DATA,
01501                 PLAYER_LIMB_DATA_STATE,
01502                 (void*)&(this->limb_data),
01503                 sizeof(player_limb_data_t),
01504                 &timestampArm);
01505 
01506   // put arm gripper data
01507   this->Publish(this->armgripper_id,
01508                 PLAYER_MSGTYPE_DATA,
01509                 PLAYER_GRIPPER_DATA_STATE,
01510                 (void*)&(this->p2os_data.armGripper),
01511                 sizeof(player_gripper_data_t),
01512                 &timestampArm);
01513 }
01514 
01515 void
01516 P2OS::Main()
01517 {
01518   int last_sonar_subscrcount=0;
01519   int last_position_subscrcount=0;
01520   int last_actarray_subscrcount=0;
01521   double currentTime;
01522   struct timeval timeVal;
01523 
01524   for(;;)
01525   {
01526     pthread_testcancel();
01527 
01528     // we want to turn on the sonars if someone just subscribed, and turn
01529     // them off if the last subscriber just unsubscribed.
01530     this->Lock();
01531     if(!last_sonar_subscrcount && this->sonar_subscriptions)
01532       this->ToggleSonarPower(1);
01533     else if(last_sonar_subscrcount && !(this->sonar_subscriptions))
01534       this->ToggleSonarPower(0);
01535     last_sonar_subscrcount = this->sonar_subscriptions;
01536 
01537     // Same for the actarray - this will also turn it on and off with limb subscriptions
01538     if(!last_actarray_subscrcount && this->actarray_subscriptions)
01539       this->ToggleActArrayPower(1, false);
01540     else if(last_actarray_subscrcount && !(this->actarray_subscriptions))
01541       this->ToggleActArrayPower(0, false);
01542     last_actarray_subscrcount = this->actarray_subscriptions;
01543 
01544     // we want to reset the odometry and enable the motors if the first
01545     // client just subscribed to the position device, and we want to stop
01546     // and disable the motors if the last client unsubscribed.
01547     if(!last_position_subscrcount && this->position_subscriptions)
01548     {
01549       this->ToggleMotorPower(0);
01550       this->ResetRawPositions();
01551     }
01552     else if(last_position_subscrcount && !(this->position_subscriptions))
01553     {
01554       // enable motor power
01555       this->ToggleMotorPower(1);
01556     }
01557     last_position_subscrcount = this->position_subscriptions;
01558     this->Unlock();
01559 
01560     // The Amigo board seems to drop commands once in a while.  This is
01561     // a hack to restart the serial reads if that happens.
01562     if(this->blobfinder_id.interf)
01563     {
01564       struct timeval now_tv;
01565       GlobalTime->GetTime(&now_tv);
01566       if (now_tv.tv_sec > lastblob_tv.tv_sec)
01567       {
01568         P2OSPacket cam_packet;
01569         unsigned char cam_command[4];
01570 
01571         cam_command[0] = GETAUX2;
01572         cam_command[1] = ARGINT;
01573         cam_command[2] = 0;
01574         cam_command[3] = 0;
01575         cam_packet.Build(cam_command, 4);
01576         SendReceive(&cam_packet);
01577 
01578         cam_command[0] = GETAUX2;
01579         cam_command[1] = ARGINT;
01580         cam_command[2] = CMUCAM_MESSAGE_LEN * 2 -1;
01581         cam_command[3] = 0;
01582         cam_packet.Build(cam_command, 4);
01583         SendReceive(&cam_packet);
01584         GlobalTime->GetTime(&lastblob_tv);  // Reset last blob packet time
01585       }
01586     }
01587 
01588     // handle pending messages
01589     if(!this->InQueue->Empty())
01590     {
01591       ProcessMessages();
01592     }
01593 
01594     // Check if need to send a pulse to the robot
01595     if (this->pulse != -1)
01596     {
01597       gettimeofday (&timeVal, NULL);
01598       currentTime = static_cast<double> (timeVal.tv_sec) + (static_cast<double> (timeVal.tv_usec) / 1e6);
01599       if ((currentTime - lastPulseTime) > this->pulse)
01600       {
01601         SendPulse ();
01602         // Update the time of last pulse/command
01603         lastPulseTime = currentTime;
01604       }
01605     }
01606     // Hack fix to get around the fact that if no commands are sent to the robot via SendReceive,
01607     // the driver will never read SIP packets and so never send data back to clients.
01608     // We need a better way of doing regular checks of the serial port - peek in sendreceive, maybe?
01609     // Because if there is no data waiting this will sit around waiting until one comes
01610     SendReceive (NULL, true);
01611   }
01612 }
01613 
01614 /* send the packet, then receive and parse an SIP */
01615 int
01616 P2OS::SendReceive(P2OSPacket* pkt, bool publish_data)
01617 {
01618   P2OSPacket packet;
01619 
01620   // zero the combined data buffer.  it will be filled with the latest data
01621   // by corresponding SIP::Fill*()
01622   memset(&(this->p2os_data),0,sizeof(player_p2os_data_t));
01623   if((this->psos_fd >= 0) && this->sippacket)
01624   {
01625     if(pkt)
01626       pkt->Send(this->psos_fd);
01627 
01628     /* receive a packet */
01629     pthread_testcancel();
01630     if(packet.Receive(this->psos_fd))
01631     {
01632       puts("RunPsosThread(): Receive errored");
01633       pthread_exit(NULL);
01634     }
01635 
01636     if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
01637        (packet.packet[3] == 0x30 || packet.packet[3] == 0x31) ||
01638        (packet.packet[3] == 0x32 || packet.packet[3] == 0x33) ||
01639        (packet.packet[3] == 0x34))
01640     {
01641 
01642       /* It is a server packet, so process it */
01643       this->sippacket->ParseStandard( &packet.packet[3] );
01644       this->sippacket->FillStandard(&(this->p2os_data));
01645 
01646       if(publish_data)
01647         this->StandardSIPPutData(packet.timestamp);
01648     }
01649     else if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
01650             packet.packet[3] == SERAUX)
01651     {
01652        // This is an AUX serial packet
01653     }
01654     else if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
01655             packet.packet[3] == SERAUX2)
01656     {
01657       // This is an AUX2 serial packet
01658 
01659       if(blobfinder_id.interf)
01660       {
01661         /* It is an extended SIP (blobfinder) packet, so process it */
01662         /* Be sure to pass data size too (packet[2])! */
01663         this->sippacket->ParseSERAUX( &packet.packet[2] );
01664         this->sippacket->FillSERAUX(&(this->p2os_data));
01665 
01666         if(publish_data)
01667           this->BlobfinderPutData(packet.timestamp);
01668 
01669         P2OSPacket cam_packet;
01670         unsigned char cam_command[4];
01671 
01672         /* We cant get the entire contents of the buffer,
01673         ** and we cant just have P2OS send us the buffer on a regular basis.
01674         ** My solution is to flush the buffer and then request exactly
01675         ** CMUCAM_MESSAGE_LEN * 2 -1 bytes of data.  This ensures that
01676         ** we will get exactly one full message, and it will be "current"
01677         ** within the last 2 messages.  Downside is that we end up pitching
01678         ** every other CMUCAM message.  Tradeoffs... */
01679         // Flush
01680         cam_command[0] = GETAUX2;
01681         cam_command[1] = ARGINT;
01682         cam_command[2] = 0;
01683         cam_command[3] = 0;
01684         cam_packet.Build(cam_command, 4);
01685         this->SendReceive(&cam_packet,publish_data);
01686 
01687         // Reqest next packet
01688         cam_command[0] = GETAUX2;
01689         cam_command[1] = ARGINT;
01690         // Guarantee exactly 1 full message
01691         cam_command[2] = CMUCAM_MESSAGE_LEN * 2 -1;
01692         cam_command[3] = 0;
01693         cam_packet.Build(cam_command, 4);
01694         this->SendReceive(&cam_packet,publish_data);
01695         GlobalTime->GetTime(&lastblob_tv);  // Reset last blob packet time
01696       }
01697     }
01698     else if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
01699             (packet.packet[3] == 0x50 || packet.packet[3] == 0x80) ||
01700 //            (packet.packet[3] == 0xB0 || packet.packet[3] == 0xC0) ||
01701             (packet.packet[3] == 0xC0) ||
01702             (packet.packet[3] == 0xD0 || packet.packet[3] == 0xE0))
01703     {
01704       /* It is a vision packet from the old Cognachrome system*/
01705 
01706       /* we don't understand these yet, so ignore */
01707     }
01708     else if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
01709             packet.packet[3] == GYROPAC)
01710     {
01711       if(this->gyro_id.interf)
01712       {
01713         /* It's a set of gyro measurements */
01714         this->sippacket->ParseGyro(&packet.packet[2]);
01715         this->sippacket->FillGyro(&(this->p2os_data));
01716 
01717         if(publish_data)
01718           this->GyroPutData(packet.timestamp);
01719 
01720         /* Now, the manual says that we get one gyro packet each cycle,
01721          * right before the standard SIP.  So, we'll call SendReceive()
01722          * again (with no packet to send) to get the standard SIP.  There's
01723          * a definite danger of infinite recursion here if the manual
01724          * is wrong.
01725          */
01726         this->SendReceive(NULL,publish_data);
01727       }
01728     }
01729     else if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
01730             (packet.packet[3] == 0x20))
01731     {
01732       //printf("got a CONFIGpac:%d\n",packet.size);
01733     }
01734     else if (packet.packet[0] == 0xFA && packet.packet[1] == 0xFB && packet.packet[3] == ARMPAC)
01735     {
01736       if (actarray_id.interf)
01737       {
01738         // ARMpac - current arm status
01739         double joints[6];
01740         sippacket->ParseArm (&packet.packet[2]);
01741         for (int ii = 0; ii < 6; ii++)
01742         {
01743           sippacket->armJointPosRads[ii] = TicksToRadians (ii, sippacket->armJointPos[ii]);
01744           joints[ii] = sippacket->armJointPosRads[ii];
01745         }
01746         sippacket->FillArm(&p2os_data);
01747         if(kineCalc)
01748         {
01749           kineCalc->CalculateFK (joints);
01750           limb_data.position.px = kineCalc->GetP ().x + armOffsetX;
01751           limb_data.position.py = kineCalc->GetP ().y + armOffsetY;
01752           limb_data.position.pz = kineCalc->GetP ().z + armOffsetZ;
01753           limb_data.approach.px = kineCalc->GetA ().x;
01754           limb_data.approach.py = kineCalc->GetA ().y;
01755           limb_data.approach.pz = kineCalc->GetA ().z;
01756           limb_data.orientation.px = kineCalc->GetO ().x;
01757           limb_data.orientation.py = kineCalc->GetO ().y;
01758           limb_data.orientation.pz = kineCalc->GetO ().z;
01759           if (limb_data.state != PLAYER_LIMB_STATE_OOR && limb_data.state != PLAYER_LIMB_STATE_COLL)
01760           {
01761             if (sippacket->armJointMoving[0] || sippacket->armJointMoving[1] || sippacket->armJointMoving[2] ||
01762                 sippacket->armJointMoving[3] || sippacket->armJointMoving[4])
01763             {
01764               limb_data.state = PLAYER_LIMB_STATE_MOVING;
01765             }
01766             else
01767               limb_data.state = PLAYER_LIMB_STATE_IDLE;
01768           }
01769         }
01770         if(publish_data)
01771         this->ActarrayPutData(packet.timestamp);
01772       }
01773 
01774       // Go for another SIP - there had better be one or things will probably go boom
01775       SendReceive(NULL,publish_data);
01776     }
01777     else if (packet.packet[0] == 0xFA && packet.packet[1] == 0xFB && packet.packet[3] == ARMINFOPAC)
01778     {
01779       // ARMINFOpac - arm configuration stuff
01780       if (actarray_id.interf)
01781       {
01782         sippacket->ParseArmInfo (&packet.packet[2]);
01783         // Update the KineCalc with the new info for joints - one would assume this doesn't change, though...
01784         if (kineCalc)
01785         {
01786           for (int ii = 0; ii < 5; ii++)
01787             kineCalc->SetJointRange (ii, TicksToRadians (ii, sippacket->armJoints[ii].min), TicksToRadians (ii, sippacket->armJoints[ii].max));
01788           // Go for another SIP - there had better be one or things will probably go boom
01789         }
01790 
01791         SendReceive(NULL,publish_data);
01792       }
01793     }
01794     else
01795     {
01796       packet.PrintHex();
01797     }
01798   }
01799 
01800   return(0);
01801 }
01802 
01803 void
01804 P2OS::ResetRawPositions()
01805 {
01806   P2OSPacket pkt;
01807   unsigned char p2oscommand[4];
01808 
01809   if(this->sippacket)
01810   {
01811     this->sippacket->rawxpos = 0;
01812     this->sippacket->rawypos = 0;
01813     this->sippacket->xpos = 0;
01814     this->sippacket->ypos = 0;
01815     p2oscommand[0] = SETO;
01816     p2oscommand[1] = ARGINT;
01817     pkt.Build(p2oscommand, 2);
01818     this->SendReceive(&pkt,false);
01819   }
01820 }
01821 
01822 
01823 /****************************************************************
01824 ** Reset the CMUcam.  This includes flushing the buffer and
01825 ** setting interface output mode to raw.  It also restarts
01826 ** tracking output (current mode)
01827 ****************************************************************/
01828 void P2OS::CMUcamReset(bool doLock)
01829 {
01830   CMUcamStopTracking(doLock); // Stop the current tracking.
01831 
01832   P2OSPacket cam_packet;
01833   unsigned char cam_command[8];
01834 
01835   printf("Resetting the CMUcam...\n");
01836   cam_command[0] = TTY3;
01837   cam_command[1] = ARGSTR;
01838   sprintf((char*)&cam_command[3], "RS\r");
01839   cam_command[2] = strlen((char *)&cam_command[3]);
01840   cam_packet.Build(cam_command, (int)cam_command[2]+3);
01841   this->SendReceive(&cam_packet,doLock);
01842 
01843   // Set for raw output + no ACK/NACK
01844   printf("Setting raw mode...\n");
01845   cam_command[0] = TTY3;
01846   cam_command[1] = ARGSTR;
01847   sprintf((char*)&cam_command[3], "RM 3\r");
01848   cam_command[2] = strlen((char *)&cam_command[3]);
01849   cam_packet.Build(cam_command, (int)cam_command[2]+3);
01850   this->SendReceive(&cam_packet,doLock);
01851   usleep(100000);
01852 
01853   printf("Flushing serial buffer...\n");
01854   cam_command[0] = GETAUX2;
01855   cam_command[1] = ARGINT;
01856   cam_command[2] = 0;
01857   cam_command[3] = 0;
01858   cam_packet.Build(cam_command, 4);
01859   this->SendReceive(&cam_packet,doLock);
01860 
01861   sleep(1);
01862   // (Re)start tracking
01863   this->CMUcamStartTracking(false);
01864 }
01865 
01866 
01867 /****************************************************************
01868 ** Start CMUcam blob tracking.  This method can be called 3 ways:
01869 **   1) with a set of 6 color arguments (RGB min and max)
01870 **   2) with auto tracking (-1 argument)
01871 **   3) with current values (0 or no arguments)
01872 ****************************************************************/
01873 void P2OS::CMUcamTrack(int rmin, int rmax,
01874                        int gmin, int gmax,
01875                        int bmin, int bmax)
01876 {
01877   this->CMUcamStopTracking(); // Stop the current tracking.
01878 
01879   P2OSPacket cam_packet;
01880   unsigned char cam_command[50];
01881 
01882   if (!rmin && !rmax && !gmin && !gmax && !bmin && !bmax)
01883   {
01884     CMUcamStartTracking();
01885   }
01886   else if (rmin<0 || rmax<0 || gmin<0 || gmax<0 || bmin<0 || bmax<0)
01887   {
01888     printf("Activating CMUcam color tracking (AUTO-mode)...\n");
01889     cam_command[0] = TTY3;
01890     cam_command[1] = ARGSTR;
01891     sprintf((char*)&cam_command[3], "TW\r");
01892     cam_command[2] = strlen((char *)&cam_command[3]);
01893     cam_packet.Build(cam_command, (int)cam_command[2]+3);
01894     this->SendReceive(&cam_packet);
01895   }
01896   else
01897   {
01898     printf("Activating CMUcam color tracking (MANUAL-mode)...\n");
01899     //printf("      RED: %d %d    GREEN: %d %d    BLUE: %d %d\n",
01900     //                   rmin, rmax, gmin, gmax, bmin, bmax);
01901     cam_command[0] = TTY3;
01902     cam_command[1] = ARGSTR;
01903     sprintf((char*)&cam_command[3], "TC %d %d %d %d %d %d\r",
01904              rmin, rmax, gmin, gmax, bmin, bmax);
01905     cam_command[2] = strlen((char *)&cam_command[3]);
01906     cam_packet.Build(cam_command, (int)cam_command[2]+3);
01907     this->SendReceive(&cam_packet);
01908   }
01909 
01910   cam_command[0] = GETAUX2;
01911   cam_command[1] = ARGINT;
01912   cam_command[2] = CMUCAM_MESSAGE_LEN * 2 -1; // Guarantee 1 full message
01913   cam_command[3] = 0;
01914   cam_packet.Build(cam_command, 4);
01915   this->SendReceive(&cam_packet);
01916 }
01917 
01918 /****************************************************************
01919 ** Start Tracking - with last config
01920 ****************************************************************/
01921 void P2OS::CMUcamStartTracking(bool doLock)
01922 {
01923    P2OSPacket cam_packet;
01924    unsigned char cam_command[50];
01925 
01926     // Then start it up with current values.
01927     cam_command[0] = TTY3;
01928     cam_command[1] = ARGSTR;
01929     sprintf((char*)&cam_command[3], "TC\r");
01930     cam_command[2] = strlen((char *)&cam_command[3]);
01931     cam_packet.Build(cam_command, (int)cam_command[2]+3);
01932     this->SendReceive(&cam_packet,false);
01933 }
01934 
01935 
01936 /****************************************************************
01937 ** Stop Tracking - This should be done before any new command
01938 ** are issued to the CMUcam.
01939 ****************************************************************/
01940 void P2OS::CMUcamStopTracking(bool doLock)
01941 {
01942   P2OSPacket cam_packet;
01943   unsigned char cam_command[50];
01944 
01945   // First we must STOP tracking.  Just send a return.
01946   cam_command[0] = TTY3;
01947   cam_command[1] = ARGSTR;
01948   sprintf((char*)&cam_command[3], "\r");
01949   cam_command[2] = strlen((char *)&cam_command[3]);
01950   cam_packet.Build(cam_command, (int)cam_command[2]+3);
01951   this->SendReceive(&cam_packet,doLock);
01952 }
01953 
01954 /* toggle sonars on/off, according to val */
01955 void
01956 P2OS::ToggleSonarPower(unsigned char val)
01957 {
01958   unsigned char command[4];
01959   P2OSPacket packet;
01960 
01961   command[0] = SONAR;
01962   command[1] = ARGINT;
01963   command[2] = val;
01964   command[3] = 0;
01965   packet.Build(command, 4);
01966   SendReceive(&packet,false);
01967 }
01968 
01969 /* toggle motors on/off, according to val */
01970 void
01971 P2OS::ToggleMotorPower(unsigned char val)
01972 {
01973   unsigned char command[4];
01974   P2OSPacket packet;
01975 
01976   command[0] = ENABLE;
01977   command[1] = ARGINT;
01978   command[2] = val;
01979   command[3] = 0;
01980   packet.Build(command, 4);
01981   SendReceive(&packet,false);
01982 }
01983 
01985 //  Actarray stuff
01987 
01988 // Ticks to degrees from the ARIA software
01989 inline double P2OS::TicksToDegrees (int joint, unsigned char ticks)
01990 {
01991   if ((joint < 0) || (joint >= sippacket->armNumJoints))
01992     return 0;
01993 
01994   double result;
01995   int pos = ticks - sippacket->armJoints[joint].centre;
01996   result = 90.0 / static_cast<double> (sippacket->armJoints[joint].ticksPer90);
01997   result = result * pos;
01998   if ((joint >= 0) && (joint <= 2))
01999     result = -result;
02000 
02001   return result;
02002 }
02003 
02004 // Degrees to ticks from the ARIA software
02005 inline unsigned char P2OS::DegreesToTicks (int joint, double degrees)
02006 {
02007   double val;
02008 
02009   if ((joint < 0) || (joint >= sippacket->armNumJoints))
02010     return 0;
02011 
02012   val = static_cast<double> (sippacket->armJoints[joint].ticksPer90) * degrees / 90.0;
02013   val = round (val);
02014   if ((joint >= 0) && (joint <= 2))
02015     val = -val;
02016   val += sippacket->armJoints[joint].centre;
02017 
02018   if (val < sippacket->armJoints[joint].min)
02019     return sippacket->armJoints[joint].min;
02020   else if (val > sippacket->armJoints[joint].max)
02021     return sippacket->armJoints[joint].max;
02022   else
02023     return static_cast<int> (round (val));
02024 }
02025 
02026 inline double P2OS::TicksToRadians (int joint, unsigned char ticks)
02027 {
02028   double result = DTOR (TicksToDegrees (joint, ticks));
02029   return result;
02030 }
02031 
02032 inline unsigned char P2OS::RadiansToTicks (int joint, double rads)
02033 {
02034   unsigned char result = static_cast<unsigned char> (DegreesToTicks (joint, RTOD (rads)));
02035   return result;
02036 }
02037 
02038 inline double P2OS::RadsPerSectoSecsPerTick (int joint, double speed)
02039 {
02040   double degs = RTOD (speed);
02041   double ticksPerDeg = static_cast<double> (sippacket->armJoints[joint].ticksPer90) / 90.0f;
02042   double ticksPerSec = degs * ticksPerDeg;
02043   double secsPerTick = 1000.0f / ticksPerSec;
02044 
02045   if (secsPerTick > 127)
02046     return 127;
02047   else if (secsPerTick < 1)
02048     return 1;
02049   return secsPerTick;
02050 }
02051 
02052 inline double P2OS::SecsPerTicktoRadsPerSec (int joint, double msecs)
02053 {
02054   double ticksPerSec = 1.0 / (static_cast<double> (msecs) / 1000.0);
02055   double ticksPerDeg = static_cast<double> (sippacket->armJoints[joint].ticksPer90) / 90.0f;
02056   double degs = ticksPerSec / ticksPerDeg;
02057   double rads = DTOR (degs);
02058 
02059   return rads;
02060 }
02061 
02062 void P2OS::ToggleActArrayPower (unsigned char value, bool lock)
02063 {
02064   unsigned char command[4];
02065   P2OSPacket packet;
02066 
02067   command[0] = ARM_POWER;
02068   command[1] = ARGINT;
02069   command[2] = value;
02070   command[3] = 0;
02071   packet.Build (command, 4);
02072   SendReceive (&packet, lock);
02073 }
02074 
02075 void P2OS::SetActArrayJointSpeed (int joint, double speed)
02076 {
02077   unsigned char command[4];
02078   P2OSPacket packet;
02079 
02080   command[0] = ARM_SPEED;
02081   command[1] = ARGINT;
02082   command[2] = static_cast<int> (round (speed));
02083   command[3] = joint;
02084   packet.Build (command, 4);
02085   SendReceive (&packet);
02086 }
02087 
02089 //  End actarray stuff
02091 
02092 
02093 int
02094 P2OS::ProcessMessage(QueuePointer & resp_queue,
02095                      player_msghdr * hdr,
02096                      void * data)
02097 {
02098   // Check for capabilities requests first
02099   HANDLE_CAPABILITY_REQUEST (position_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_CAPABILTIES_REQ);
02100   HANDLE_CAPABILITY_REQUEST (actarray_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_CAPABILTIES_REQ);
02101   HANDLE_CAPABILITY_REQUEST (lift_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_CAPABILTIES_REQ);
02102   HANDLE_CAPABILITY_REQUEST (limb_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_CAPABILTIES_REQ);
02103   HANDLE_CAPABILITY_REQUEST (gripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_CAPABILTIES_REQ);
02104   HANDLE_CAPABILITY_REQUEST (armgripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_CAPABILTIES_REQ);
02105   // Position2d caps
02106   HANDLE_CAPABILITY_REQUEST (position_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL);
02107   // Act array caps
02108   HANDLE_CAPABILITY_REQUEST (actarray_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_POS);
02109   HANDLE_CAPABILITY_REQUEST (actarray_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_MULTI_POS);
02110   HANDLE_CAPABILITY_REQUEST (actarray_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_HOME);
02111   HANDLE_CAPABILITY_REQUEST (actarray_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_POWER);
02112   HANDLE_CAPABILITY_REQUEST (actarray_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_GET_GEOM);
02113   HANDLE_CAPABILITY_REQUEST (actarray_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_SPEED);
02114   // Lift caps
02115   HANDLE_CAPABILITY_REQUEST (lift_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_POS);
02116   HANDLE_CAPABILITY_REQUEST (lift_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_HOME);
02117   HANDLE_CAPABILITY_REQUEST (lift_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_GET_GEOM);
02118   // Limb caps
02119   HANDLE_CAPABILITY_REQUEST (limb_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_LIMB_CMD_HOME);
02120   HANDLE_CAPABILITY_REQUEST (limb_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_LIMB_CMD_STOP);
02121   HANDLE_CAPABILITY_REQUEST (limb_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_LIMB_CMD_SETPOSE);
02122   HANDLE_CAPABILITY_REQUEST (limb_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_LIMB_REQ_POWER);
02123   HANDLE_CAPABILITY_REQUEST (limb_id, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_LIMB_REQ_GEOM);
02124   // Gripper caps
02125   HANDLE_CAPABILITY_REQUEST (gripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_OPEN);
02126   HANDLE_CAPABILITY_REQUEST (gripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_CLOSE);
02127   HANDLE_CAPABILITY_REQUEST (gripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_STOP);
02128   // Arm gripper caps
02129   HANDLE_CAPABILITY_REQUEST (armgripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_OPEN);
02130   HANDLE_CAPABILITY_REQUEST (armgripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_CLOSE);
02131   HANDLE_CAPABILITY_REQUEST (armgripper_id, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_STOP);
02132 
02133   // Process other messages
02134   if(hdr->type == PLAYER_MSGTYPE_REQ)
02135     return(this->HandleConfig(resp_queue,hdr,data));
02136   else if(hdr->type == PLAYER_MSGTYPE_CMD)
02137     return(this->HandleCommand(hdr,data));
02138   else
02139     return(-1);
02140 }
02141 
02142 int
02143 P2OS::HandleConfig(QueuePointer & resp_queue,
02144                    player_msghdr * hdr,
02145                    void * data)
02146 {
02147   int joint = 0;
02148   double newSpeed = 0.0f;
02149 
02150   // check for position config requests
02151   if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02152                            PLAYER_POSITION2D_REQ_SET_ODOM,
02153                            this->position_id))
02154   {
02155     if(hdr->size != sizeof(player_position2d_set_odom_req_t))
02156     {
02157       PLAYER_WARN("Arg to odometry set requests wrong size; ignoring");
02158       return(-1);
02159     }
02160     player_position2d_set_odom_req_t* set_odom_req =
02161             (player_position2d_set_odom_req_t*)data;
02162 
02163     this->sippacket->x_offset = ((int)rint(set_odom_req->pose.px*1e3)) -
02164             this->sippacket->xpos;
02165     this->sippacket->y_offset = ((int)rint(set_odom_req->pose.py*1e3)) -
02166             this->sippacket->ypos;
02167     this->sippacket->angle_offset = ((int)rint(RTOD(set_odom_req->pose.pa))) -
02168             this->sippacket->angle;
02169 
02170     this->Publish(this->position_id, resp_queue,
02171                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_SET_ODOM);
02172     return(0);
02173   }
02174   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02175                                 PLAYER_POSITION2D_REQ_MOTOR_POWER,
02176                                 this->position_id))
02177   {
02178     /* motor state change request
02179      *   1 = enable motors
02180      *   0 = disable motors (default)
02181      */
02182     if(hdr->size != sizeof(player_position2d_power_config_t))
02183     {
02184       PLAYER_WARN("Arg to motor state change request wrong size; ignoring");
02185       return(-1);
02186     }
02187     player_position2d_power_config_t* power_config =
02188             (player_position2d_power_config_t*)data;
02189     this->ToggleMotorPower(power_config->state);
02190 
02191     this->Publish(this->position_id, resp_queue,
02192                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_MOTOR_POWER);
02193     return(0);
02194   }
02195   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02196                                 PLAYER_POSITION2D_REQ_RESET_ODOM,
02197                                 this->position_id))
02198   {
02199     /* reset position to 0,0,0: no args */
02200     if(hdr->size != 0)
02201     {
02202       PLAYER_WARN("Arg to reset position request is wrong size; ignoring");
02203       return(-1);
02204     }
02205     ResetRawPositions();
02206 
02207     this->Publish(this->position_id, resp_queue,
02208                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_RESET_ODOM);
02209     return(0);
02210   }
02211   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02212                                 PLAYER_POSITION2D_REQ_GET_GEOM,
02213                                 this->position_id))
02214   {
02215     /* Return the robot geometry. */
02216     if(hdr->size != 0)
02217     {
02218       PLAYER_WARN("Arg get robot geom is wrong size; ignoring");
02219       return(-1);
02220     }
02221     player_position2d_geom_t geom;
02222     // TODO: Figure out this rotation offset somehow; it's not
02223     //       given in the Saphira parameters.  For now, -0.1 is
02224     //       about right for a Pioneer 2DX.
02225     geom.pose.px = -0.1;
02226     geom.pose.py = 0.0;
02227     geom.pose.pyaw = 0.0;
02228     // get dimensions from the parameter table
02229     geom.size.sl = PlayerRobotParams[param_idx].RobotLength / 1e3;
02230     geom.size.sw = PlayerRobotParams[param_idx].RobotWidth / 1e3;
02231 
02232     this->Publish(this->position_id, resp_queue,
02233                   PLAYER_MSGTYPE_RESP_ACK,
02234                   PLAYER_POSITION2D_REQ_GET_GEOM,
02235                   (void*)&geom, sizeof(geom), NULL);
02236     return(0);
02237   }
02238   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02239                                 PLAYER_POSITION2D_REQ_VELOCITY_MODE,
02240                                 this->position_id))
02241   {
02242     /* velocity control mode:
02243      *   0 = direct wheel velocity control (default)
02244      *   1 = separate translational and rotational control
02245      */
02246     if(hdr->size != sizeof(player_position2d_velocity_mode_config_t))
02247     {
02248       PLAYER_WARN("Arg to velocity control mode change request is wrong "
02249                   "size; ignoring");
02250       return(-1);
02251     }
02252     player_position2d_velocity_mode_config_t* velmode_config =
02253             (player_position2d_velocity_mode_config_t*)data;
02254 
02255     if(velmode_config->value)
02256       direct_wheel_vel_control = false;
02257     else
02258       direct_wheel_vel_control = true;
02259 
02260     this->Publish(this->position_id, resp_queue,
02261                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_VELOCITY_MODE);
02262     return(0);
02263   }
02264   // check for sonar config requests
02265   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02266                                 PLAYER_SONAR_REQ_POWER,
02267                                 this->sonar_id))
02268   {
02269     /*
02270      * 1 = enable sonars
02271      * 0 = disable sonar
02272      */
02273     if(hdr->size != sizeof(player_sonar_power_config_t))
02274     {
02275       PLAYER_WARN("Arg to sonar state change request wrong size; ignoring");
02276       return(-1);
02277     }
02278     player_sonar_power_config_t* sonar_config =
02279             (player_sonar_power_config_t*)data;
02280     this->ToggleSonarPower(sonar_config->state);
02281 
02282     this->Publish(this->sonar_id, resp_queue,
02283                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_SONAR_REQ_POWER);
02284     return(0);
02285   }
02286   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02287                                 PLAYER_SONAR_REQ_GET_GEOM,
02288                                 this->sonar_id))
02289   {
02290     /* Return the sonar geometry. */
02291     if(hdr->size != 0)
02292     {
02293       PLAYER_WARN("Arg get sonar geom is wrong size; ignoring");
02294       return(-1);
02295     }
02296     player_sonar_geom_t geom;
02297     geom.poses_count = PlayerRobotParams[param_idx].SonarNum;
02298     geom.poses = new player_pose3d_t[geom.poses_count];
02299     for(int i = 0; i < PlayerRobotParams[param_idx].SonarNum; i++)
02300     {
02301       sonar_pose_t pose = PlayerRobotParams[param_idx].sonar_pose[i];
02302       geom.poses[i].px = pose.x / 1e3;
02303       geom.poses[i].py = pose.y / 1e3;
02304       geom.poses[i].pyaw = DTOR(pose.th);
02305     }
02306 
02307     this->Publish(this->sonar_id, resp_queue,
02308                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_SONAR_REQ_GET_GEOM,
02309                   (void*)&geom);
02310     delete [] geom.poses;
02311     return(0);
02312   }
02313   // check for blobfinder requests
02314   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02315                              PLAYER_BLOBFINDER_REQ_SET_COLOR,
02316                              this->blobfinder_id))
02317   {
02318     // Set the tracking color (RGB max/min values)
02319 
02320     if(hdr->size != sizeof(player_blobfinder_color_config_t))
02321     {
02322       puts("Arg to blobfinder color request wrong size; ignoring");
02323       return(-1);
02324     }
02325     player_blobfinder_color_config_t* color_config =
02326             (player_blobfinder_color_config_t*)data;
02327 
02328     CMUcamTrack(color_config->rmin,
02329                 color_config->rmax,
02330                 color_config->gmin,
02331                 color_config->gmax,
02332                 color_config->bmin,
02333                 color_config->bmax);
02334 
02335     this->Publish(this->blobfinder_id, resp_queue,
02336                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_BLOBFINDER_REQ_SET_COLOR);
02337     return(0);
02338   }
02339   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
02340                                 PLAYER_BLOBFINDER_REQ_SET_IMAGER_PARAMS,
02341                                 this->blobfinder_id))
02342   {
02343     // Set the imager control params
02344     if(hdr->size != sizeof(player_blobfinder_imager_config_t))
02345     {
02346       puts("Arg to blobfinder imager request wrong size; ignoring");
02347       return(-1);
02348     }
02349     player_blobfinder_imager_config_t* imager_config =
02350             (player_blobfinder_imager_config_t*)data;
02351 
02352     P2OSPacket cam_packet;
02353     unsigned char cam_command[50];
02354     int np;
02355 
02356     np=3;
02357 
02358     CMUcamStopTracking(); // Stop the current tracking.
02359 
02360     cam_command[0] = TTY3;
02361     cam_command[1] = ARGSTR;
02362     np += sprintf((char*)&cam_command[np], "CR ");
02363 
02364     if (imager_config->brightness >= 0)
02365       np += sprintf((char*)&cam_command[np], " 6 %d",
02366                     imager_config->brightness);
02367 
02368     if (imager_config->contrast >= 0)
02369       np += sprintf((char*)&cam_command[np], " 5 %d",
02370                     imager_config->contrast);
02371 
02372     if (imager_config->autogain >= 0)
02373       if (imager_config->autogain == 0)
02374         np += sprintf((char*)&cam_command[np], " 19 32");
02375       else
02376         np += sprintf((char*)&cam_command[np], " 19 33");
02377 
02378     if (imager_config->colormode >= 0)
02379       if (imager_config->colormode == 3)
02380         np += sprintf((char*)&cam_command[np], " 18 36");
02381       else if (imager_config->colormode == 2)
02382         np += sprintf((char*)&cam_command[np], " 18 32");
02383       else if (imager_config->colormode == 1)
02384         np += sprintf((char*)&cam_command[np], " 18 44");
02385       else
02386         np += sprintf((char*)&cam_command[np], " 18 40");
02387 
02388     if (np > 6)
02389     {
02390       sprintf((char*)&cam_command[np], "\r");
02391       cam_command[2] = strlen((char *)&cam_command[3]);
02392       cam_packet.Build(cam_command, (int)cam_command[2]+3);
02393       SendReceive(&cam_packet);
02394 
02395       printf("Blobfinder imager parameters updated.\n");
02396       printf("       %s\n", &cam_command[3]);
02397     } else
02398       printf("Blobfinder imager parameters NOT updated.\n");
02399 
02400     CMUcamTrack();  // Restart tracking
02401 
02402     this->Publish(this->blobfinder_id, resp_queue,
02403                   PLAYER_MSGTYPE_RESP_ACK,
02404                   PLAYER_BLOBFINDER_REQ_SET_IMAGER_PARAMS);
02405     return(0);
02406   }
02407   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_ACTARRAY_REQ_POWER,this->actarray_id))
02408   {
02409     ToggleActArrayPower (((player_actarray_power_config_t*) data)->value);
02410     this->Publish(this->actarray_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_ACTARRAY_REQ_POWER);
02411     return 0;
02412   }
02413   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_ACTARRAY_REQ_GET_GEOM,this->actarray_id))
02414   {
02415     // First ask for an ARMINFOpac (because we need to get any updates to speed settings)
02416     P2OSPacket aaPacket;
02417     unsigned char aaCmd = ARM_INFO;
02418     aaPacket.Build (&aaCmd, 1);
02419     SendReceive (&aaPacket);
02420 
02421     player_actarray_geom_t aaGeom;
02422     player_actarray_actuatorgeom_t *actuators;
02423 
02424     aaGeom.actuators_count = sippacket->armNumJoints;
02425     actuators = new player_actarray_actuatorgeom_t[sippacket->armNumJoints];
02426     if (actuators == NULL)
02427     {
02428       PLAYER_ERROR ("Failed to allocate memory for actuator data");
02429       return -1;
02430     }
02431     aaGeom.actuators = actuators;
02432 
02433     for (int ii = 0; ii < sippacket->armNumJoints; ii++)
02434     {
02435       aaGeom.actuators[ii].type = PLAYER_ACTARRAY_TYPE_ROTARY;
02436       aaGeom.actuators[ii].length = aaLengths[ii];
02437       aaGeom.actuators[ii].orientation.proll = aaOrients[ii * 3];
02438       aaGeom.actuators[ii].orientation.ppitch = aaOrients[ii * 3 + 1];
02439       aaGeom.actuators[ii].orientation.pyaw = aaOrients[ii * 3 + 2];
02440       aaGeom.actuators[ii].axis.px = aaAxes[ii * 3];
02441       aaGeom.actuators[ii].axis.py = aaAxes[ii * 3 + 1];
02442       aaGeom.actuators[ii].axis.pz = aaAxes[ii * 3 + 2];
02443       aaGeom.actuators[ii].min = static_cast<float> (TicksToRadians (ii, sippacket->armJoints[ii].min));
02444       aaGeom.actuators[ii].centre = static_cast<float> (TicksToRadians (ii, sippacket->armJoints[ii].centre));
02445       aaGeom.actuators[ii].max = static_cast<float> (TicksToRadians (ii, sippacket->armJoints[ii].max));
02446       aaGeom.actuators[ii].home = static_cast<float> (TicksToRadians (ii, sippacket->armJoints[ii].home));
02447       aaGeom.actuators[ii].config_speed = static_cast<float> (SecsPerTicktoRadsPerSec (ii, sippacket->armJoints[ii].speed));
02448       aaGeom.actuators[ii].hasbrakes = 0;
02449     }
02450 
02451     aaGeom.base_pos.px = aaBasePos.px;
02452     aaGeom.base_pos.py = aaBasePos.py;
02453     aaGeom.base_pos.pz = aaBasePos.pz;
02454     aaGeom.base_orientation.proll = aaBaseOrient.proll;
02455     aaGeom.base_orientation.ppitch = aaBaseOrient.ppitch;
02456     aaGeom.base_orientation.pyaw = aaBaseOrient.pyaw;
02457 
02458     this->Publish(this->actarray_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_ACTARRAY_REQ_GET_GEOM, &aaGeom, sizeof (aaGeom), NULL);
02459     delete[] actuators;
02460     return 0;
02461   }
02462   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_ACTARRAY_REQ_SPEED,this->actarray_id))
02463   {
02464     joint = ((player_actarray_speed_config_t*) data)->joint + 1;
02465     newSpeed = RadsPerSectoSecsPerTick (joint, ((player_actarray_speed_config_t*) data)->speed);
02466     SetActArrayJointSpeed (joint, newSpeed);
02467 
02468     this->Publish(this->actarray_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_ACTARRAY_REQ_SPEED);
02469     return 0;
02470   }
02471   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_LIMB_REQ_POWER,this->limb_id))
02472   {
02473     ToggleActArrayPower (((player_actarray_power_config_t*) data)->value);
02474     this->Publish(this->actarray_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_LIMB_REQ_POWER);
02475     return 0;
02476   }
02477   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_LIMB_REQ_BRAKES,this->limb_id))
02478   {
02479     // We don't have any brakes
02480     return 0;
02481   }
02482   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_LIMB_REQ_GEOM,this->limb_id))
02483   {
02484     player_limb_geom_req_t limbGeom;
02485 
02486     limbGeom.basePos.px = armOffsetX;
02487     limbGeom.basePos.py = armOffsetY;
02488     limbGeom.basePos.pz = armOffsetZ;
02489 
02490     this->Publish(this->limb_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_LIMB_REQ_GEOM, &limbGeom, sizeof (limbGeom), NULL);
02491     return 0;
02492   }
02493   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_LIMB_REQ_SPEED,this->limb_id))
02494   {
02495     // FIXME - need to figure out what sort of speed support we should provide through the IK interface
02496     // Would need some form of motion control
02497     // For now, just set all joint speeds - take the value as being rad/s instead of m/s
02498     float speed = ((player_limb_speed_req_t*) data)->speed;
02499     for (int ii = 1; ii < 6; ii++)
02500     {
02501       newSpeed = RadsPerSectoSecsPerTick (ii, speed);
02502       SetActArrayJointSpeed (ii, newSpeed);
02503     }
02504 
02505     this->Publish(this->limb_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_LIMB_REQ_SPEED);
02506     return 0;
02507   }
02508   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, PLAYER_BUMPER_REQ_GET_GEOM, this->bumper_id))
02509   {
02510     /* Return the bumper geometry. */
02511     if(hdr->size != 0)
02512     {
02513       PLAYER_WARN("Arg get bumper geom is wrong size; ignoring");
02514       return(-1);
02515     }
02516     player_bumper_geom_t geom;
02517     geom.bumper_def_count = PlayerRobotParams[param_idx].NumFrontBumpers + PlayerRobotParams[param_idx].NumRearBumpers;
02518     geom.bumper_def = new player_bumper_define_t[geom.bumper_def_count];
02519     for(unsigned int ii = 0; ii < geom.bumper_def_count; ii++)
02520     {
02521       bumper_def_t def = PlayerRobotParams[param_idx].bumper_geom[ii];
02522       geom.bumper_def[ii].pose.px = def.x;
02523       geom.bumper_def[ii].pose.py = def.y;
02524       geom.bumper_def[ii].pose.pyaw = DTOR(def.th);
02525       geom.bumper_def[ii].length = def.length;
02526       geom.bumper_def[ii].radius = def.radius;
02527     }
02528 
02529     this->Publish(this->bumper_id, resp_queue,
02530                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_BUMPER_REQ_GET_GEOM,
02531                   (void*)&geom);
02532     delete [] geom.bumper_def;
02533     return(0);
02534   }
02535   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_ACTARRAY_REQ_GET_GEOM,this->lift_id))
02536   {
02537     player_actarray_geom_t aaGeom;
02538     player_actarray_actuatorgeom_t actuator;
02539     aaGeom.actuators = &actuator;
02540 
02541     aaGeom.actuators_count = 1;
02542     memset (aaGeom.actuators, 0, sizeof (player_actarray_actuator_t));
02543 
02544     aaGeom.actuators[0].type = PLAYER_ACTARRAY_TYPE_LINEAR;
02545     aaGeom.actuators[0].min = 0.0f;
02546     aaGeom.actuators[0].centre = 0.5f;
02547     aaGeom.actuators[0].max = 1.0f;
02548     aaGeom.actuators[0].home = 1.0f;
02549     aaGeom.actuators[0].config_speed = 0.02f; // 2cm/s, according to the manual
02550     aaGeom.actuators[0].hasbrakes = 0;
02551 
02552     this->Publish(this->lift_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_ACTARRAY_REQ_GET_GEOM, &aaGeom, sizeof (aaGeom), NULL);
02553     return 0;
02554   }
02555   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_GRIPPER_REQ_GET_GEOM,this->gripper_id))
02556   {
02557     player_gripper_geom_t geom;
02558     memset (&geom, 0, sizeof (player_gripper_geom_t));
02559 
02560     geom.pose = gripperPose;
02561     geom.outer_size = gripperOuterSize;
02562     geom.inner_size = gripperInnerSize;
02563     geom.num_beams = 2;
02564     geom.capacity = 0;
02565 
02566     this->Publish(this->gripper_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_GRIPPER_REQ_GET_GEOM, &geom, sizeof (geom), NULL);
02567     return 0;
02568   }
02569   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,PLAYER_GRIPPER_REQ_GET_GEOM,this->armgripper_id))
02570   {
02571     player_gripper_geom_t geom;
02572     memset (&geom, 0, sizeof (player_gripper_geom_t));
02573 
02574     memset (&(geom.pose), 0, sizeof (player_pose3d_t));  // Hard to know since it's on the end of the arm
02575     geom.outer_size = armGripperOuterSize;
02576     geom.inner_size = armGripperInnerSize;
02577     geom.num_beams = 0;
02578     geom.capacity = 0;
02579 
02580     this->Publish(this->armgripper_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_GRIPPER_REQ_GET_GEOM, &geom, sizeof (geom), NULL);
02581     return 0;
02582   }
02583   else
02584   {
02585     PLAYER_WARN("unknown config request to p2os driver");
02586     return(-1);
02587   }
02588 }
02589 
02590 void P2OS::SendPulse (void)
02591 {
02592   unsigned char command;
02593   P2OSPacket packet;
02594 
02595   command = PULSE;
02596   packet.Build(&command, 1);
02597   SendReceive(&packet);
02598 }
02599 
02601 //  Command handling
02603 
02604 void
02605 P2OS::HandlePositionCommand(player_position2d_cmd_vel_t position_cmd)
02606 {
02607   int speedDemand, turnRateDemand;
02608   double leftvel, rightvel;
02609   double rotational_term;
02610   unsigned short absspeedDemand, absturnRateDemand;
02611   unsigned char motorcommand[4];
02612   P2OSPacket motorpacket;
02613 
02614   speedDemand = (int)rint(position_cmd.vel.px * 1e3);
02615   turnRateDemand = (int)rint(RTOD(position_cmd.vel.pa));
02616 
02617   if(this->direct_wheel_vel_control)
02618   {
02619     // convert xspeed and yawspeed into wheelspeeds
02620     rotational_term = (M_PI/180.0) * turnRateDemand /
02621             PlayerRobotParams[param_idx].DiffConvFactor;
02622     leftvel = (speedDemand - rotational_term);
02623     rightvel = (speedDemand + rotational_term);
02624 
02625     // Apply wheel speed bounds
02626     if(fabs(leftvel) > this->motor_max_speed)
02627     {
02628       if(leftvel > 0)
02629       {
02630         rightvel *= this->motor_max_speed/leftvel;
02631         leftvel = this->motor_max_speed;
02632         puts("Left wheel velocity threshholded!");
02633       }
02634       else
02635       {
02636         rightvel *= -this->motor_max_speed/leftvel;
02637         leftvel = -this->motor_max_speed;
02638       }
02639     }
02640     if(fabs(rightvel) > this->motor_max_speed)
02641     {
02642       if(rightvel > 0)
02643       {
02644         leftvel *= this->motor_max_speed/rightvel;
02645         rightvel = this->motor_max_speed;
02646         puts("Right wheel velocity threshholded!");
02647       }
02648       else
02649       {
02650         leftvel *= -this->motor_max_speed/rightvel;
02651         rightvel = -this->motor_max_speed;
02652       }
02653     }
02654 
02655     // Apply control band bounds
02656     if(this->use_vel_band)
02657     {
02658       // This band prevents the wheels from turning in opposite
02659       // directions
02660       if (leftvel * rightvel < 0)
02661       {
02662         if (leftvel + rightvel >= 0)
02663         {
02664           if (leftvel < 0)
02665             leftvel = 0;
02666           if (rightvel < 0)
02667             rightvel = 0;
02668         }
02669         else
02670         {
02671           if (leftvel > 0)
02672             leftvel = 0;
02673           if (rightvel > 0)
02674             rightvel = 0;
02675         }
02676       }
02677     }
02678 
02679     // Apply byte range bounds
02680     if (leftvel / PlayerRobotParams[param_idx].Vel2Divisor > 126)
02681       leftvel = 126 * PlayerRobotParams[param_idx].Vel2Divisor;
02682     if (leftvel / PlayerRobotParams[param_idx].Vel2Divisor < -126)
02683       leftvel = -126 * PlayerRobotParams[param_idx].Vel2Divisor;
02684     if (rightvel / PlayerRobotParams[param_idx].Vel2Divisor > 126)
02685       rightvel = 126 * PlayerRobotParams[param_idx].Vel2Divisor;
02686     if (rightvel / PlayerRobotParams[param_idx].Vel2Divisor < -126)
02687       rightvel = -126 * PlayerRobotParams[param_idx].Vel2Divisor;
02688 
02689     // send the speed command
02690     motorcommand[0] = VEL2;
02691     motorcommand[1] = ARGINT;
02692     motorcommand[2] = (char)(rightvel /
02693                              PlayerRobotParams[param_idx].Vel2Divisor);
02694     motorcommand[3] = (char)(leftvel /
02695                              PlayerRobotParams[param_idx].Vel2Divisor);
02696 
02697     motorpacket.Build(motorcommand, 4);
02698     this->SendReceive(&motorpacket);
02699   }
02700   else
02701   {
02702     // do separate trans and rot vels
02703 
02704     motorcommand[0] = VEL;
02705     if(speedDemand >= 0)
02706       motorcommand[1] = ARGINT;
02707     else
02708       motorcommand[1] = ARGNINT;
02709 
02710     absspeedDemand = (unsigned short)abs(speedDemand);
02711     if(absspeedDemand < this->motor_max_speed)
02712     {
02713       motorcommand[2] = absspeedDemand & 0x00FF;
02714       motorcommand[3] = (absspeedDemand & 0xFF00) >> 8;
02715     }
02716     else
02717     {
02718       puts("Speed demand threshholded!");
02719       motorcommand[2] = this->motor_max_speed & 0x00FF;
02720       motorcommand[3] = (this->motor_max_speed & 0xFF00) >> 8;
02721     }
02722     motorpacket.Build(motorcommand, 4);
02723     this->SendReceive(&motorpacket);
02724 
02725     motorcommand[0] = RVEL;
02726     if(turnRateDemand >= 0)
02727       motorcommand[1] = ARGINT;
02728     else
02729       motorcommand[1] = ARGNINT;
02730 
02731     absturnRateDemand = (unsigned short)abs(turnRateDemand);
02732     if(absturnRateDemand < this->motor_max_turnspeed)
02733     {
02734       motorcommand[2] = absturnRateDemand & 0x00FF;
02735       motorcommand[3] = (absturnRateDemand & 0xFF00) >> 8;
02736     }
02737     else
02738     {
02739       puts("Turn rate demand threshholded!");
02740       motorcommand[2] = this->motor_max_turnspeed & 0x00FF;
02741       motorcommand[3] = (this->motor_max_turnspeed & 0xFF00) >> 8;
02742     }
02743 
02744     motorpacket.Build(motorcommand, 4);
02745     this->SendReceive(&motorpacket);
02746 
02747   }
02748 }
02749 
02750 void
02751 P2OS::HandleAudioCommand(player_audio_sample_item_t audio_cmd)
02752 {
02753   unsigned char soundcommand[4];
02754   P2OSPacket soundpacket;
02755   unsigned short soundindex;
02756 
02757   soundindex = audio_cmd.index;
02758 
02759   if(!this->sent_audio_cmd || (soundindex != this->last_audio_cmd.index))
02760   {
02761     soundcommand[0] = SOUND;
02762     soundcommand[1] = ARGINT;
02763     soundcommand[2] = soundindex & 0x00FF;
02764     soundcommand[3] = (soundindex & 0xFF00) >> 8;
02765     soundpacket.Build(soundcommand,4);
02766     SendReceive(&soundpacket);
02767     fflush(stdout);
02768 
02769     this->last_audio_cmd.index = soundindex;
02770   }
02771 }
02772 
02774 //  Arm actuator array commands
02775 
02776 void P2OS::HandleActArrayPosCmd (player_actarray_position_cmd_t cmd)
02777 {
02778   unsigned char command[4];
02779   P2OSPacket packet;
02780 
02781   if (!(lastActArrayCmd == PLAYER_ACTARRAY_CMD_POS) || ((lastActArrayCmd == PLAYER_ACTARRAY_CMD_POS) &&
02782        (cmd.joint != lastActArrayPosCmd.joint || cmd.position != lastActArrayPosCmd.position)))
02783   {
02784     command[0] = ARM_POS;
02785     command[1] = ARGINT;
02786     command[2] = RadiansToTicks (cmd.joint, cmd.position);
02787     command[3] = static_cast<unsigned char> (cmd.joint) + 1;
02788     packet.Build(command, 4);
02789     SendReceive(&packet);
02790     sippacket->armJointTargetPos[static_cast<unsigned char> (cmd.joint)] = command[2];
02791   }
02792 }
02793 
02794 void P2OS::HandleActArrayHomeCmd (player_actarray_home_cmd_t cmd)
02795 {
02796   unsigned char command[4];
02797   P2OSPacket packet;
02798 
02799   if ((lastActArrayCmd == PLAYER_ACTARRAY_CMD_POS) || (!(lastActArrayCmd == PLAYER_ACTARRAY_CMD_POS) &&
02800        (cmd.joint != lastActArrayHomeCmd.joint)))
02801   {
02802     command[0] = ARM_HOME;
02803     command[1] = ARGINT;
02804     command[2] = (cmd.joint == -1) ? 7 : (static_cast<unsigned char> (cmd.joint) + 1);
02805     command[3] = 0;
02806     packet.Build(command, 4);
02807     SendReceive(&packet);
02808   }
02809 }
02810 
02811 int P2OS::HandleActArrayCommand (player_msghdr * hdr, void * data)
02812 {
02813   if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_POS, this->actarray_id))
02814   {
02815     player_actarray_position_cmd_t cmd;
02816     cmd = *(player_actarray_position_cmd_t*) data;
02817     this->HandleActArrayPosCmd (cmd);
02818     lastActArrayCmd = PLAYER_ACTARRAY_CMD_POS;
02819     return 0;
02820   }
02821   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_HOME, this->actarray_id))
02822   {
02823     player_actarray_home_cmd_t cmd;
02824     cmd = *(player_actarray_home_cmd_t*) data;
02825     this->HandleActArrayHomeCmd (cmd);
02826     lastActArrayCmd = PLAYER_ACTARRAY_CMD_HOME;
02827     return 0;
02828   }
02829   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_MULTI_POS, this->actarray_id))
02830   {
02831     player_actarray_multi_position_cmd_t cmd = *(player_actarray_multi_position_cmd_t*) data;
02832     player_actarray_position_cmd_t singleCmd;
02833     for (unsigned int ii = 0; ii < cmd.positions_count && ii < 6; ii++)
02834     {
02835       singleCmd.joint = ii;
02836       singleCmd.position = cmd.positions[ii];
02837       this->HandleActArrayPosCmd (singleCmd);
02838     }
02839     lastActArrayCmd = PLAYER_ACTARRAY_CMD_MULTI_POS;
02840   }
02841 
02842   return -1;
02843 }
02844 
02846 //  Limb commands
02847 
02848 void P2OS::HandleLimbHomeCmd (void)
02849 {
02850   unsigned char command[4];
02851   P2OSPacket packet;
02852 
02853   command[0] = ARM_HOME;
02854   command[1] = ARGINT;
02855   command[2] = 7;
02856   command[3] = 0;
02857   packet.Build(command, 4);
02858   SendReceive(&packet);
02859 }
02860 
02861 void P2OS::HandleLimbStopCmd (void)
02862 {
02863   unsigned char command[4];
02864   P2OSPacket packet;
02865 
02866   command[0] = ARM_STOP;
02867   command[1] = ARGINT;
02868 
02869   for (int ii = 1; ii < 5; ii++)
02870   {
02871     command[2] = ii;
02872     command[3] = 0;
02873     packet.Build (command, 4);
02874     SendReceive (&packet);
02875   }
02876 }
02877 
02878 void P2OS::HandleLimbSetPoseCmd (player_limb_setpose_cmd_t cmd)
02879 {
02880   unsigned char command[4];
02881   P2OSPacket packet;
02882   EndEffector pose;
02883 
02884 //   printf ("Moving limb to pose (%f, %f, %f), (%f, %f, %f), (%f, %f, %f)\n", cmd.position.px, cmd.position.py, cmd.position.pz, cmd.approach.px, cmd.approach.py, cmd.approach.pz, cmd.orientation.px, cmd.orientation.py, cmd.orientation.pz);
02885 
02886   pose.p.x = cmd.position.px - armOffsetX;
02887   pose.p.y = cmd.position.py - armOffsetY;
02888   pose.p.z = cmd.position.pz - armOffsetZ;
02889   pose.a.x = cmd.approach.px; pose.a.y = cmd.approach.py; pose.a.z = cmd.approach.pz;
02890   pose.o.x = cmd.orientation.px; pose.o.y = cmd.orientation.py; pose.o.z = cmd.orientation.pz;
02891   pose.a = kineCalc->Normalise (pose.a);
02892   pose.o = kineCalc->Normalise (pose.o);
02893   pose.n = kineCalc->CalculateN (pose);
02894 
02895 //   printf ("Pose = %f, %f, %f\t", pose.p.x, pose.p.y, pose.p.z);
02896 //   printf ("Approach = %f, %f, %f\n", pose.a.x, pose.a.y, pose.a.z);
02897 //   printf ("Orientation = %f, %f, %f\t", pose.o.x, pose.o.y, pose.o.z);
02898 //   printf ("Normal = %f, %f, %f\n", pose.n.x, pose.n.y, pose.n.z);
02899 
02900   if (!kineCalc->CalculateIK (pose))
02901   {
02902     limb_data.state = PLAYER_LIMB_STATE_OOR;
02903     return;
02904   }
02905 
02906   command[0] = ARM_POS;
02907   command[1] = ARGINT;
02908 
02909   for (int ii = 0; ii < 5; ii++)
02910   {
02911     command[2] = RadiansToTicks (ii, kineCalc->GetTheta (ii));
02912     command[3] = ii + 1;
02913     packet.Build (command, 4);
02914     SendReceive (&packet);
02915 //     printf ("Sent joint %d to %f (%d)\n", ii, kineCalc->GetTheta (ii), command[2]);
02916   }
02917 
02918   limb_data.state = PLAYER_LIMB_STATE_MOVING;
02919 }
02920 
02921 // NOTE: Not functional
02922 void P2OS::HandleLimbSetPositionCmd (player_limb_setposition_cmd_t cmd)
02923 {
02924   EndEffector pose;
02925   unsigned char command[4];
02926   P2OSPacket packet;
02927 
02928   pose.p.x = cmd.position.px - armOffsetX;
02929   pose.p.y = -(cmd.position.py - armOffsetY);
02930   pose.p.z = cmd.position.pz - armOffsetZ;
02931 
02932   // Use the pose info from the last reported arm position (cause the IK calculator doesn't
02933   // calculate without full pose data)
02934   pose.o = kineCalc->GetO ();
02935   pose.a = kineCalc->GetA ();
02936   pose.n = kineCalc->GetN ();
02937 
02938   if (!kineCalc->CalculateIK (pose))
02939   {
02940     limb_data.state = PLAYER_LIMB_STATE_OOR;
02941     return;
02942   }
02943 
02944   command[0] = ARM_POS;
02945   command[1] = ARGINT;
02946 
02947   for (int ii = 0; ii < 5; ii++)
02948   {
02949     command[2] = RadiansToTicks (ii, kineCalc->GetTheta (ii));
02950     command[3] = ii + 1;
02951     packet.Build (command, 4);
02952     SendReceive (&packet);
02953   }
02954 
02955   limb_data.state = PLAYER_LIMB_STATE_MOVING;
02956 }
02957 
02958 // NOTE: Not functional
02959 void P2OS::HandleLimbVecMoveCmd (player_limb_vecmove_cmd_t cmd)
02960 {
02961   EndEffector pose;
02962   unsigned char command[4];
02963   P2OSPacket packet;
02964 
02965   // To do a vector move, calculate a new position that is offset from the current
02966   // by the length of the desired move in the direction of the desired vector.
02967   // Since we lack constant motion control, but are moving over a small range, this
02968   // should hopefully give an accurate representation of a vector move.
02969   // UPDATE: Turns out it doesn't work. Hopefully I'll have time to rewrite
02970   // this driver in the future so that it can support proper constant motion
02971   // control without being an unmaintainable mess.
02972   // As such, this vector move isn't actually a vector move as it is intended in
02973   // the interface. I'll leave it in because it could be useful as an "offset"
02974   // command, but this should be noted in the docs for the driver.
02975 
02976   pose.p = kineCalc->GetP ();
02977   pose.o = kineCalc->GetO ();
02978   pose.a = kineCalc->GetA ();
02979   pose.n = kineCalc->GetN ();
02980 
02981   KineVector offset;
02982   offset.x = cmd.direction.px;   offset.y = -cmd.direction.py;   offset.z = cmd.direction.pz;
02983   offset = kineCalc->Normalise (offset);
02984   offset.x *= cmd.length;
02985   offset.y *= cmd.length;
02986   offset.z *= cmd.length;
02987 
02988   pose.p.x += offset.x;
02989   pose.p.y += offset.y;
02990   pose.p.z += offset.z;
02991 
02992   if (!kineCalc->CalculateIK (pose))
02993   {
02994     limb_data.state = PLAYER_LIMB_STATE_OOR;
02995     return;
02996   }
02997 
02998   command[0] = ARM_POS;
02999   command[1] = ARGINT;
03000 
03001   for (int ii = 0; ii < 5; ii++)
03002   {
03003     command[2] = RadiansToTicks (ii, kineCalc->GetTheta (ii));
03004     command[3] = ii + 1;
03005     packet.Build (command, 4);
03006     SendReceive (&packet);
03007   }
03008 
03009   limb_data.state = PLAYER_LIMB_STATE_MOVING;
03010 }
03011 
03012 int P2OS::HandleLimbCommand (player_msghdr *hdr, void *data)
03013 {
03014   if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_CMD,PLAYER_LIMB_CMD_HOME,this->limb_id))
03015   {
03016     this->HandleLimbHomeCmd ();
03017     return 0;
03018   }
03019   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_CMD,PLAYER_LIMB_CMD_STOP,this->limb_id))
03020   {
03021     this->HandleLimbStopCmd ();
03022     return 0;
03023   }
03024   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_CMD,PLAYER_LIMB_CMD_SETPOSE,this->limb_id))
03025   {
03026     player_limb_setpose_cmd_t cmd;
03027     cmd = *(player_limb_setpose_cmd_t*) data;
03028     this->HandleLimbSetPoseCmd (cmd);
03029     return 0;
03030   }
03031   return -1;
03032 }
03033 
03035 //  Lift commands
03036 
03037 int P2OS::HandleLiftCommand (player_msghdr *hdr, void *data)
03038 {
03039   unsigned char command[4];
03040   P2OSPacket packet;
03041 
03042   if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_CMD,PLAYER_ACTARRAY_CMD_POS,this->lift_id))
03043   {
03044     player_actarray_position_cmd_t cmd;
03045     cmd = *(player_actarray_position_cmd_t*) data;
03046 
03047     // If not the first joint, return error
03048     if (cmd.joint > 0)
03049       return -1;
03050 
03051     if (lastLiftCmd == PLAYER_ACTARRAY_CMD_POS && lastLiftPosCmd.position == cmd.position)
03052       return 0;
03053 
03054     command[0] = GRIPPER;
03055     command[1] = ARGINT;
03056 
03057     // If the position is 1 or 0, then it's easy: just use LIFTup or LIFTdown
03058     if (cmd.position <= 0.0)
03059     {
03060      command[2] = LIFTdown;
03061      command[3] = 0;
03062       packet.Build (command, 4);
03063       SendReceive (&packet);
03064     }
03065     else if (cmd.position >= 1.0)
03066     {
03067       command[3] = LIFTup;
03068      command[3] = 0;
03069       packet.Build (command, 4);
03070       SendReceive (&packet);
03071     }
03072     else
03073     {
03074       // Lift position is a range from 0 to 1. 0 corresponds to down, 1 corresponds to up.
03075       // Setting positions in between is done using the carry time.
03076       // According to the manual, the lift can move 7cm at a rate of 2cm/s (in ideal conditions).
03077       // So to figure out the lift time for a given position, we consider an AA position of 1 to
03078       // correspond to a lift position of 7cm and 0 to 0cm. Given a speed of 2cm/s, this means
03079       // the lift takes 3.5s to move over its full range. So an AA position is converted to a
03080       // time by 3.5 * cmd.pos. For example, 0.5 is 3.5 * 0.5 = 1.75s travel time.
03081       // We then use the LIFTcarry command to set this travel time. LIFTcarry is specified as
03082       // an integer, with each step equal to 20ms of travel time. So the LIFTcarry value
03083       // becomes travel time / 0.02.
03084       // It is important to remember that the LIFTcarry is (if my reading of the manul is correct)
03085       // an offset command, not absolute position command. So we have to track the last commanded
03086       // position of the lift and work from that to get the correct travel time (and direction).
03087 
03088       double offset = cmd.position - lastLiftPosCmd.position;
03089       double travelTime = offset * 3.5f;
03090       short liftCarryVal = static_cast<short> (travelTime / 0.02f);
03091 
03092       // Send the LIFTcarry command
03093      command[2] = LIFTcarry;
03094      command[3] = 0;
03095       packet.Build (command, 4);
03096       SendReceive (&packet);
03097 
03098       // Followed by the carry time
03099       command[0] = GRIPPERVAL;
03100       command[2] = liftCarryVal & 0x00FF;
03101       command[3] = (liftCarryVal & 0xFF00) >> 8;
03102       packet.Build (command, 4);
03103       SendReceive (&packet);
03104     }
03105 
03106     lastLiftCmd = PLAYER_ACTARRAY_CMD_POS;
03107     lastLiftPosCmd = cmd;
03108     sippacket->lastLiftPos = cmd.position;
03109     return 0;
03110   }
03111   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_CMD,PLAYER_ACTARRAY_CMD_HOME,this->lift_id))
03112   {
03113     if (lastLiftCmd == PLAYER_ACTARRAY_CMD_HOME)
03114       return 0;
03115 
03116     // For home, just send the lift to up position
03117     command[0] = GRIPPER;
03118     command[1] = ARGINT;
03119    command[2] = LIFTup;
03120    command[3] = 0;
03121     packet.Build (command, 4);
03122     SendReceive (&packet);
03123     lastLiftCmd = PLAYER_ACTARRAY_CMD_HOME;
03124     lastLiftPosCmd.position = 1.0f;
03125     return 0;
03126   }
03127   return -1;
03128 }
03129 
03131 //  Gripper commands
03132 
03133 void P2OS::OpenGripper (void)
03134 {
03135   unsigned char cmd[4];
03136   P2OSPacket packet;
03137 
03138  /*
03139   if (sentGripperCmd && lastGripperCmd == PLAYER_GRIPPER_CMD_OPEN)
03140     return;
03141  */
03142 
03143   cmd[0] = GRIPPER;
03144   cmd[1] = ARGINT;
03145  cmd[2] = GRIPopen;  // low bits of unsigned 16bit int
03146  cmd[3] = 0;         // high bits of unsigned 16bit int
03147   packet.Build (cmd, 4);
03148   SendReceive (&packet);
03149 
03150   sentGripperCmd = true;
03151   lastGripperCmd = PLAYER_GRIPPER_CMD_OPEN;
03152 }
03153 
03154 void P2OS::CloseGripper (void)
03155 {
03156   unsigned char cmd[4];
03157   P2OSPacket packet;
03158 
03159  /*
03160   if (sentGripperCmd && lastGripperCmd == PLAYER_GRIPPER_CMD_CLOSE)
03161     return;
03162  */
03163 
03164   cmd[0] = GRIPPER;
03165   cmd[1] = ARGINT;
03166  cmd[2] = GRIPclose; // low bits of unsigned 16 bit int
03167  cmd[3] = 0;         // high bits of unsigned 16bit int
03168   packet.Build (cmd, 4);
03169   SendReceive (&packet);
03170 
03171   sentGripperCmd = true;
03172   lastGripperCmd = PLAYER_GRIPPER_CMD_CLOSE;
03173 }
03174 
03175 void P2OS::StopGripper (void)
03176 {
03177   unsigned char cmd[4];
03178   P2OSPacket packet;
03179 
03180   if (sentGripperCmd && lastGripperCmd == PLAYER_GRIPPER_CMD_STOP)
03181     return;
03182 
03183   cmd[0] = GRIPPER;
03184   cmd[1] = ARGINT;
03185  cmd[2] = GRIPstop;
03186  cmd[3] = 0;
03187   packet.Build (cmd, 4);
03188   SendReceive (&packet);
03189 
03190   sentGripperCmd = true;
03191   lastGripperCmd = PLAYER_GRIPPER_CMD_STOP;
03192 }
03193 
03194 int P2OS::HandleGripperCommand (player_msghdr * hdr, void * data)
03195 {
03196   if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_OPEN, this->gripper_id))
03197   {
03198     OpenGripper ();
03199     return 0;
03200   }
03201   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_CLOSE, this->gripper_id))
03202   {
03203     CloseGripper ();
03204     return 0;
03205   }
03206   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_STOP, this->gripper_id))
03207   {
03208     StopGripper ();
03209     return 0;
03210   }
03211   return -1;
03212 }
03213 
03215 //  Arm gripper commands
03216 
03217 void P2OS::OpenArmGripper (void)
03218 {
03219   unsigned char command[4];
03220   P2OSPacket packet;
03221 
03222   if (sentArmGripperCmd && lastArmGripperCmd == PLAYER_GRIPPER_CMD_OPEN)
03223     return;
03224 
03225   command[0] = ARM_POS;
03226   command[1] = ARGINT;
03227   command[2] = sippacket->armJoints[5].max;
03228   command[3] = 6;
03229   packet.Build(command, 4);
03230   SendReceive(&packet);
03231 
03232   sippacket->armJointTargetPos[5] = command[2];
03233   sentArmGripperCmd = true;
03234   lastArmGripperCmd = PLAYER_GRIPPER_CMD_OPEN;
03235 }
03236 
03237 void P2OS::CloseArmGripper (void)
03238 {
03239   unsigned char command[4];
03240   P2OSPacket packet;
03241 
03242   if (sentArmGripperCmd && lastArmGripperCmd == PLAYER_GRIPPER_CMD_CLOSE)
03243     return;
03244 
03245   command[0] = ARM_POS;
03246   command[1] = ARGINT;
03247   command[2] = sippacket->armJoints[5].min;
03248   command[3] = 6;
03249   packet.Build(command, 4);
03250   SendReceive(&packet);
03251 
03252   sippacket->armJointTargetPos[5] = command[2];
03253   sentArmGripperCmd = true;
03254   lastArmGripperCmd = PLAYER_GRIPPER_CMD_CLOSE;
03255 }
03256 
03257 void P2OS::StopArmGripper (void)
03258 {
03259   unsigned char command[4];
03260   P2OSPacket packet;
03261 
03262   if (sentArmGripperCmd && lastArmGripperCmd == PLAYER_GRIPPER_CMD_STOP)
03263     return;
03264 
03265   command[0] = ARM_STOP;
03266   command[1] = ARGINT;
03267   command[2] = 6;
03268   command[3] = 0;
03269   packet.Build(command, 4);
03270   SendReceive(&packet);
03271 
03272   sentArmGripperCmd = true;
03273   lastArmGripperCmd = PLAYER_GRIPPER_CMD_STOP;
03274 }
03275 
03276 int P2OS::HandleArmGripperCommand (player_msghdr *hdr, void *data)
03277 {
03278   if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_OPEN, this->armgripper_id))
03279   {
03280     OpenArmGripper ();
03281     return 0;
03282   }
03283   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_CLOSE, this->armgripper_id))
03284   {
03285     CloseArmGripper ();
03286     return 0;
03287   }
03288   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_GRIPPER_CMD_STOP, this->armgripper_id))
03289   {
03290     StopArmGripper ();
03291     return 0;
03292   }
03293   return -1;
03294 }
03295 
03297 
03298 int
03299 P2OS::HandleCommand(player_msghdr * hdr, void* data)
03300 {
03301   int retVal = -1;
03302   struct timeval timeVal;
03303 
03304   if(Message::MatchMessage(hdr,
03305                            PLAYER_MSGTYPE_CMD,
03306                            PLAYER_POSITION2D_CMD_VEL,
03307                            this->position_id))
03308   {
03309     // get and send the latest motor command
03310     player_position2d_cmd_vel_t position_cmd;
03311     position_cmd = *(player_position2d_cmd_vel_t*)data;
03312     this->HandlePositionCommand(position_cmd);
03313     retVal = 0;
03314   }
03315   else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_SAMPLE_PLAY, this->audio_id))
03316   {
03317     // get and send the latest audio command, if it's new
03318     player_audio_sample_item_t audio_cmd;
03319     audio_cmd = *(player_audio_sample_item_t*)data;
03320     this->HandleAudioCommand(audio_cmd);
03321     retVal = 0;
03322   }
03323   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, -1, actarray_id))
03324   {
03325     retVal = HandleActArrayCommand (hdr, data);
03326   }
03327   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, -1, limb_id))
03328   {
03329     retVal = HandleLimbCommand (hdr, data);
03330   }
03331   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, -1, lift_id))
03332   {
03333     retVal = HandleLiftCommand (hdr, data);
03334   }
03335   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, -1, gripper_id))
03336   {
03337     retVal = HandleGripperCommand (hdr, data);
03338   }
03339   else if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, -1, gripper_id))
03340   {
03341     retVal = HandleGripperCommand(hdr, data);
03342   }
03343   else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, -1, armgripper_id))
03344   {
03345     retVal = HandleArmGripperCommand (hdr, data);
03346   }
03347 
03348   // Update the time of last pulse/command on successful handling of commands
03349   if (retVal == 0 && pulse != -1)
03350   {
03351     gettimeofday (&timeVal, NULL);
03352     lastPulseTime = static_cast<double> (timeVal.tv_sec) + (static_cast<double> (timeVal.tv_usec) / 1e6);
03353   }
03354   return retVal;
03355 }

Last updated 12 September 2005 21:38:45