p2os.cc
Go to the documentation of this file.
00001 /*
00002  *  P2OS for ROS
00003  *  Copyright (C) 2009
00004  *     Hunter Allen, David Feil-Seifer, Brian Gerkey, Kasper Stoy,
00005  *     Richard Vaughan, & Andrew Howard
00006  *
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program; if not, write to the Free Software
00020  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include <termios.h>
00024 #include <fcntl.h>
00025 #include <string.h>
00026  
00027 #include <ros/ros.h>
00028 #include <p2os_driver/p2os.h>
00029 
00030 P2OSNode::P2OSNode(ros::NodeHandle nh) :
00031         n(nh), gripper_dirty_(false),
00032         batt_pub_(n.advertise<p2os_msgs::BatteryState>("battery_state",1000),
00033                           diagnostic_,
00034                           diagnostic_updater::FrequencyStatusParam(&desired_freq, &desired_freq, 0.1),
00035                           diagnostic_updater::TimeStampStatusParam()),
00036         ptz_(this)
00037 {
00043         // Use sonar
00044         ros::NodeHandle n_private("~");
00045         n_private.param(std::string("odom_frame_id"), odom_frame_id,std::string("odom"));
00046         n_private.param(std::string("base_link_frame_id"), base_link_frame_id,std::string("base_link"));
00047         n_private.param("use_sonar", use_sonar_, false);
00048     
00049         // read in config options
00050         // bumpstall
00051         n_private.param("bumpstall", bumpstall, -1);
00052         // pulse
00053         n_private.param("pulse", pulse, -1.0);
00054         // rot_kp
00055         n_private.param("rot_kp", rot_kp, -1);
00056         // rot_kv
00057         n_private.param("rot_kv", rot_kv, -1);
00058         // rot_ki
00059         n_private.param("rot_ki", rot_ki, -1);
00060         // trans_kp
00061         n_private.param("trans_kp", trans_kp, -1);
00062         // trans_kv
00063         n_private.param("trans_kv", trans_kv, -1);
00064         // trans_ki
00065         n_private.param("trans_ki", trans_ki, -1);
00066         // !!! port !!!
00067         std::string def = DEFAULT_P2OS_PORT;
00068         n_private.param("port", psos_serial_port, def);
00069         ROS_INFO("using serial port: [%s]", psos_serial_port.c_str());
00070         n_private.param("use_tcp", psos_use_tcp, false);
00071         std::string host = DEFAULT_P2OS_TCP_REMOTE_HOST;
00072         n_private.param("tcp_remote_host", psos_tcp_host, host);
00073         n_private.param("tcp_remote_port", psos_tcp_port, DEFAULT_P2OS_TCP_REMOTE_PORT);
00074         // radio
00075         n_private.param("radio", radio_modemp, 0);
00076         // joystick
00077         n_private.param("joystick", joystick, 0);
00078         // direct_wheel_vel_control
00079         n_private.param("direct_wheel_vel_control", direct_wheel_vel_control, 0);
00080         // max xpeed
00081         double spd;
00082         n_private.param("max_xspeed", spd, MOTOR_DEF_MAX_SPEED);
00083         motor_max_speed = (int)rint(1e3*spd);
00084         // max_yawspeed
00085         n_private.param("max_yawspeed", spd, MOTOR_DEF_MAX_TURNSPEED);
00086         motor_max_turnspeed = (short)rint(RTOD(spd));
00087         // max_xaccel
00088         n_private.param("max_xaccel", spd, 0.0);
00089         motor_max_trans_accel = (short)rint(1e3*spd);
00090         // max_xdecel
00091         n_private.param("max_xdecel", spd, 0.0);
00092         motor_max_trans_decel = (short)rint(1e3*spd);
00093         // max_yawaccel
00094         n_private.param("max_yawaccel", spd, 0.0);
00095         motor_max_rot_accel = (short)rint(RTOD(spd));
00096         // max_yawdecel
00097         n_private.param("max_yawdecel", spd, 0.0);
00098         motor_max_rot_decel = (short)rint(RTOD(spd));
00099     
00100         desired_freq = 10;
00101     
00102         // advertise services
00103         pose_pub_ = n.advertise<nav_msgs::Odometry>("pose", 1000);
00104         //advertise topics
00105         mstate_pub_ = n.advertise<p2os_msgs::MotorState>("motor_state",1000);
00106         grip_state_pub_ = n.advertise<p2os_msgs::GripperState>("gripper_state",1000);
00107         ptz_state_pub_ = n.advertise<p2os_msgs::PTZState>("ptz_state",1000);
00108         sonar_pub_ = n.advertise<p2os_msgs::SonarArray>("sonar", 1000);
00109         aio_pub_ = n.advertise<p2os_msgs::AIO>("aio", 1000);
00110         dio_pub_ = n.advertise<p2os_msgs::DIO>("dio", 1000);
00111     
00112         // subscribe to services
00113         cmdvel_sub_ = n.subscribe("cmd_vel", 1, &P2OSNode::cmdvel_cb, this);
00114         cmdmstate_sub_ = n.subscribe("cmd_motor_state", 1, &P2OSNode::cmdmotor_state,
00115                                                                  this);
00116         gripper_sub_ = n.subscribe("gripper_control", 1, &P2OSNode::gripperCallback,
00117                                                            this);
00118         ptz_cmd_sub_ = n.subscribe("ptz_control", 1, &P2OSPtz::callback, &ptz_);
00119     
00120         veltime = ros::Time::now();
00121     
00122         // add diagnostic functions
00123         diagnostic_.add("Motor Stall", this, &P2OSNode::check_stall);
00124         diagnostic_.add("Battery Voltage", this, &P2OSNode::check_voltage);
00125     
00126         // initialize robot parameters (player legacy)
00127         initialize_robot_params();
00128 }
00129 
00130 P2OSNode::~P2OSNode() {}
00131 
00132 void P2OSNode::cmdmotor_state(const p2os_msgs::MotorStateConstPtr & msg)
00133 {
00134         motor_dirty = true;
00135         cmdmotor_state_ = *msg;
00136 }
00137 
00138 void P2OSNode::check_and_set_motor_state()
00139 {
00140         if(!motor_dirty) return;
00141         motor_dirty = false;
00142     
00143         unsigned char val = (unsigned char) cmdmotor_state_.state;
00144         unsigned char command[4];
00145         P2OSPacket packet;
00146         command[0] = ENABLE;
00147         command[1] = ARGINT;
00148         command[2] = val;
00149         command[3] = 0;
00150         packet.Build(command,4);
00151     
00152         // Store the current motor state so that we can set it back
00153         p2os_data.motors.state = cmdmotor_state_.state;
00154         SendReceive(&packet,false);
00155 }
00156 
00157 void P2OSNode::check_and_set_gripper_state()
00158 {
00159         if(!gripper_dirty_) return;
00160         gripper_dirty_ = false;
00161     
00162         // Send the gripper command
00163         unsigned char grip_val = (unsigned char) gripper_state_.grip.state;
00164         unsigned char grip_command[4];
00165 
00166         P2OSPacket grip_packet;
00167         grip_command[0] = GRIPPER;
00168         grip_command[1] = ARGINT;
00169         grip_command[2] = grip_val;
00170         grip_command[3] = 0;
00171         grip_packet.Build(grip_command,4);
00172         SendReceive(&grip_packet, false);
00173     
00174         // Send the lift command
00175         unsigned char lift_val = (unsigned char) gripper_state_.lift.state;
00176         unsigned char lift_command[4];
00177 
00178         P2OSPacket lift_packet;
00179         lift_command[0] = GRIPPER;
00180         lift_command[1] = ARGINT;
00181         lift_command[2] = lift_val;
00182         lift_command[3] = 0;
00183         lift_packet.Build(lift_command,4);
00184 
00185         SendReceive(&lift_packet,false);
00186 }
00187 
00188 void P2OSNode::cmdvel_cb(const geometry_msgs::TwistConstPtr &msg)
00189 {
00190         if(fabs(msg->linear.x - cmdvel_.linear.x) > 0.01 || fabs(msg->angular.z - cmdvel_.angular.z) > 0.01) {
00191                 veltime = ros::Time::now();
00192                 ROS_DEBUG("new speed: [%0.2f,%0.2f](%0.3f)", msg->linear.x*1e3, msg->angular.z, veltime.toSec());
00193                 vel_dirty = true;
00194                 cmdvel_ = *msg;
00195         } else {
00196                 ros::Duration veldur = ros::Time::now() - veltime;
00197                 if(veldur.toSec() > 2.0 && ((fabs(cmdvel_.linear.x) > 0.01) || (fabs(cmdvel_.angular.z) > 0.01))) {
00198                         ROS_DEBUG("maintaining old speed: %0.3f|%0.3f", veltime.toSec(), ros::Time::now().toSec());
00199                         vel_dirty = true;
00200                         veltime = ros::Time::now();
00201                 }
00202         }
00203     
00204 }
00205 
00206 void P2OSNode::check_and_set_vel()
00207 {
00208         if(!vel_dirty) return;
00209     
00210         ROS_DEBUG("setting vel: [%0.2f,%0.2f]",cmdvel_.linear.x,cmdvel_.angular.z);
00211         vel_dirty = false;
00212     
00213         unsigned short absSpeedDemand, absturnRateDemand;
00214         unsigned char motorcommand[4];
00215         P2OSPacket motorpacket;
00216     
00217         int vx = (int) (cmdvel_.linear.x*1e3);
00218         int va = (int) rint(RTOD(cmdvel_.angular.z));
00219     
00220         // non-direct wheel control
00221         motorcommand[0] = VEL;
00222         motorcommand[1] = (vx >= 0) ? ARGINT : ARGNINT;
00223     
00224         absSpeedDemand = (unsigned short) abs(vx);
00225     
00226         if(absSpeedDemand <= this->motor_max_speed) {
00227                 motorcommand[2] = absSpeedDemand & 0x00FF;
00228                 motorcommand[3] = (absSpeedDemand & 0xFF00) >> 8;
00229         } else {
00230                 ROS_WARN("speed demand thresholded! (true: %u, max: %u)", absSpeedDemand, motor_max_speed);
00231                 motorcommand[2] = motor_max_speed & 0x00FF;
00232                 motorcommand[3] = (motor_max_speed & 0xFF00) >> 8;
00233         }
00234     
00235         motorpacket.Build(motorcommand, 4);
00236         SendReceive(&motorpacket);
00237         
00238         motorcommand[0] = RVEL;
00239         motorcommand[1] = (va >= 0) ? ARGINT : ARGNINT;
00240     
00241         absturnRateDemand = (unsigned short) (va >= 0) ? va : (-1 * va);
00242 
00243         if(absturnRateDemand <= motor_max_turnspeed) {
00244                 motorcommand[2] = absturnRateDemand & 0x00FF;
00245                 motorcommand[3] = (absturnRateDemand & 0xFF00) >> 8;
00246         } else {
00247                 ROS_WARN("Turn rate demand threshholded!");
00248                 motorcommand[2] = this->motor_max_turnspeed & 0x00FF;
00249                 motorcommand[3] = (this->motor_max_turnspeed & 0xFF00) >> 8;
00250         }
00251   
00252         motorpacket.Build(motorcommand,4);
00253         SendReceive(&motorpacket);
00254 }
00255 
00256 void P2OSNode::gripperCallback(const p2os_msgs::GripperStateConstPtr &msg)
00257 {
00258         gripper_dirty_ = true;
00259         gripper_state_ = *msg;
00260 }
00261 
00262 int P2OSNode::Setup()
00263 {
00264         int i;
00265         int bauds[] = {B9600, B38400, B19200, B115200, B57600};
00266         int numbauds = sizeof(bauds);
00267         int currbaud = 0;
00268         sippacket = NULL;
00269         lastPulseTime = 0.0;
00270     
00271         struct termios term;
00272         unsigned char command;
00273         P2OSPacket packet, receivedpacket;
00274         int flags=0;
00275         bool sent_close = false;
00276 
00277         enum
00278         {
00279                 NO_SYNC,
00280                 AFTER_FIRST_SYNC,
00281                 AFTER_SECOND_SYNC,
00282                 READY
00283         } psos_state;
00284     
00285         psos_state = NO_SYNC;
00286     
00287         char name[20], type[20], subtype[20];
00288         int cnt;
00289     
00290     
00291         // use serial port
00292     
00293         ROS_INFO("P2OS connection opening serial port %s...",psos_serial_port.c_str());
00294     
00295         if((this->psos_fd = open(this->psos_serial_port.c_str(),
00296                                                          O_RDWR | O_SYNC | O_NONBLOCK, S_IRUSR | S_IWUSR)) < 0)
00297     {
00298                 ROS_ERROR("P2OS::Setup():open():");
00299                 return(1);
00300     }
00301     
00302         if(tcgetattr(this->psos_fd, &term) < 0)
00303     {
00304                 ROS_ERROR("P2OS::Setup():tcgetattr():");
00305                 close(this->psos_fd);
00306                 this->psos_fd = -1;
00307                 return(1);
00308     }
00309     
00310         cfmakeraw(&term);
00311         cfsetispeed(&term, bauds[currbaud]);
00312         cfsetospeed(&term, bauds[currbaud]);
00313     
00314         if(tcsetattr(this->psos_fd, TCSAFLUSH, &term) < 0)
00315     {
00316                 ROS_ERROR("P2OS::Setup():tcsetattr():");
00317                 close(this->psos_fd);
00318                 this->psos_fd = -1;
00319                 return(1);
00320     }
00321     
00322         if(tcflush(this->psos_fd, TCIOFLUSH) < 0)
00323     {
00324                 ROS_ERROR("P2OS::Setup():tcflush():");
00325                 close(this->psos_fd);
00326                 this->psos_fd = -1;
00327                 return(1);
00328     }
00329     
00330         if((flags = fcntl(this->psos_fd, F_GETFL)) < 0)
00331     {
00332                 ROS_ERROR("P2OS::Setup():fcntl()");
00333                 close(this->psos_fd);
00334                 this->psos_fd = -1;
00335                 return(1);
00336     }
00337         // Sync:
00338     
00339         int num_sync_attempts = 3;
00340         while(psos_state != READY)
00341     {
00342                 switch(psos_state)
00343         {
00344         case NO_SYNC:
00345                         command = SYNC0;
00346                         packet.Build(&command, 1);
00347                         packet.Send(this->psos_fd);
00348                         usleep(P2OS_CYCLETIME_USEC);
00349                         break;
00350         case AFTER_FIRST_SYNC:
00351                         ROS_INFO("turning off NONBLOCK mode...");
00352                         if(fcntl(this->psos_fd, F_SETFL, flags ^ O_NONBLOCK) < 0)
00353             {
00354                                 ROS_ERROR("P2OS::Setup():fcntl()");
00355                                 close(this->psos_fd);
00356                                 this->psos_fd = -1;
00357                                 return(1);
00358             }
00359                         command = SYNC1;
00360                         packet.Build(&command, 1);
00361                         packet.Send(this->psos_fd);
00362                         break;
00363         case AFTER_SECOND_SYNC:
00364                         command = SYNC2;
00365                         packet.Build(&command, 1);
00366                         packet.Send(this->psos_fd);
00367                         break;
00368         default:
00369                         ROS_WARN("P2OS::Setup():shouldn't be here...");
00370                         break;
00371         }
00372                 usleep(P2OS_CYCLETIME_USEC);
00373         
00374                 if(receivedpacket.Receive(this->psos_fd))
00375         {
00376                         if((psos_state == NO_SYNC) && (num_sync_attempts >= 0))
00377             {
00378                                 num_sync_attempts--;
00379                                 usleep(P2OS_CYCLETIME_USEC);
00380                                 continue;
00381             }
00382                         else
00383             {
00384                                 // couldn't connect; try different speed.
00385                                 if(++currbaud < numbauds)
00386                 {
00387                                         cfsetispeed(&term, bauds[currbaud]);
00388                                         cfsetospeed(&term, bauds[currbaud]);
00389                                         if(tcsetattr(this->psos_fd, TCSAFLUSH, &term) < 0)
00390                     {
00391                                                 ROS_ERROR("P2OS::Setup():tcsetattr():");
00392                                                 close(this->psos_fd);
00393                                                 this->psos_fd = -1;
00394                                                 return(1);
00395                     }
00396                     
00397                                         if(tcflush(this->psos_fd, TCIOFLUSH) < 0)
00398                     {
00399                                                 ROS_ERROR("P2OS::Setup():tcflush():");
00400                                                 close(this->psos_fd);
00401                                                 this->psos_fd = -1;
00402                                                 return(1);
00403                     }
00404                                         num_sync_attempts = 3;
00405                                         continue;
00406                 }
00407                                 else
00408                 {
00409                                         // tried all speeds; bail
00410                                         break;
00411                 }
00412             }
00413         }
00414                 switch(receivedpacket.packet[3])
00415         {
00416         case SYNC0:
00417                         ROS_INFO("SYNC0");
00418                         psos_state = AFTER_FIRST_SYNC;
00419                         break;
00420         case SYNC1:
00421                         ROS_INFO("SYNC1");
00422                         psos_state = AFTER_SECOND_SYNC;
00423                         break;
00424         case SYNC2:
00425                         ROS_INFO("SYNC2");
00426                         psos_state = READY;
00427                         break;
00428         default:
00429                         // maybe P2OS is still running from last time.  let's try to CLOSE
00430                         // and reconnect
00431                         if(!sent_close)
00432             {
00433                                 ROS_DEBUG("sending CLOSE");
00434                                 command = CLOSE;
00435                                 packet.Build(&command, 1);
00436                                 packet.Send(this->psos_fd);
00437                                 sent_close = true;
00438                                 usleep(2*P2OS_CYCLETIME_USEC);
00439                                 tcflush(this->psos_fd,TCIFLUSH);
00440                                 psos_state = NO_SYNC;
00441             }
00442                         break;
00443         }
00444                 usleep(P2OS_CYCLETIME_USEC);
00445     }
00446         if(psos_state != READY)
00447     {
00448                 if(this->psos_use_tcp)
00449                         ROS_INFO("Couldn't synchronize with P2OS.\n"
00450                                          "  Most likely because the robot is not connected %s %s",
00451                                          this->psos_use_tcp ? "to the ethernet-serial bridge device " : "to the serial port",
00452                                          this->psos_use_tcp ? this->psos_tcp_host.c_str() : this->psos_serial_port.c_str());
00453                 close(this->psos_fd);
00454                 this->psos_fd = -1;
00455                 return(1);
00456     }
00457         cnt = 4;
00458         cnt += snprintf(name, sizeof(name), "%s", &receivedpacket.packet[cnt]);
00459         cnt++;
00460         cnt += snprintf(type, sizeof(type), "%s", &receivedpacket.packet[cnt]);
00461         cnt++;
00462         cnt += snprintf(subtype, sizeof(subtype), "%s", &receivedpacket.packet[cnt]);
00463         cnt++;
00464     
00465         std::string hwID = std::string(name) + ": " + std::string(type) + "/" + std::string(subtype);
00466         diagnostic_.setHardwareID(hwID);
00467     
00468         command = OPEN;
00469         packet.Build(&command, 1);
00470         packet.Send(this->psos_fd);
00471         usleep(P2OS_CYCLETIME_USEC);
00472         command = PULSE;
00473         packet.Build(&command, 1);
00474         packet.Send(this->psos_fd);
00475         usleep(P2OS_CYCLETIME_USEC);
00476     
00477         ROS_INFO("Done.\n   Connected to %s, a %s %s", name, type, subtype);
00478     
00479         // now, based on robot type, find the right set of parameters
00480         for(i=0;i<PLAYER_NUM_ROBOT_TYPES;i++)
00481     {
00482                 if(!strcasecmp(PlayerRobotParams[i].Class.c_str(),type) &&
00483                    !strcasecmp(PlayerRobotParams[i].Subclass.c_str(),subtype))
00484         {
00485                         param_idx = i;
00486                         break;
00487         }
00488     }
00489         if(i == PLAYER_NUM_ROBOT_TYPES)
00490     {
00491                 ROS_WARN("P2OS: Warning: couldn't find parameters for this robot; "
00492                                  "using defaults");
00493                 param_idx = 0;
00494     }
00495     
00496         //sleep(1);
00497     
00498         // first, receive a packet so we know we're connected.
00499         if(!sippacket)
00500     {
00501                 sippacket = new SIP(param_idx);
00502                 sippacket->odom_frame_id = odom_frame_id;
00503                 sippacket->base_link_frame_id = base_link_frame_id;
00504     }
00505         /*
00506           sippacket->x_offset = 0;
00507           sippacket->y_offset = 0;
00508           sippacket->angle_offset = 0;
00509   
00510           SendReceive((P2OSPacket*)NULL,false);
00511         */
00512         // turn off the sonars at first
00513         this->ToggleSonarPower(0);
00514         // if requested, set max accel/decel limits
00515         P2OSPacket accel_packet;
00516         unsigned char accel_command[4];
00517         if(this->motor_max_trans_accel > 0)
00518     {
00519                 accel_command[0] = SETA;
00520                 accel_command[1] = ARGINT;
00521                 accel_command[2] = this->motor_max_trans_accel & 0x00FF;
00522                 accel_command[3] = (this->motor_max_trans_accel & 0xFF00) >> 8;
00523                 accel_packet.Build(accel_command, 4);
00524                 this->SendReceive(&accel_packet,false);
00525     }
00526     
00527         if(this->motor_max_trans_decel < 0)
00528     {
00529                 accel_command[0] = SETA;
00530                 accel_command[1] = ARGNINT;
00531                 accel_command[2] =  -1 *(this->motor_max_trans_decel) & 0x00FF;
00532                 accel_command[3] =  (-1 *(this->motor_max_trans_decel) & 0xFF00) >> 8;
00533                 accel_packet.Build(accel_command, 4);
00534                 this->SendReceive(&accel_packet,false);
00535     }
00536         if(this->motor_max_rot_accel > 0)
00537     {
00538                 accel_command[0] = SETRA;
00539                 accel_command[1] = ARGINT;
00540                 accel_command[2] = this->motor_max_rot_accel & 0x00FF;
00541                 accel_command[3] = (this->motor_max_rot_accel & 0xFF00) >> 8;
00542                 accel_packet.Build(accel_command, 4);
00543                 this->SendReceive(&accel_packet,false);
00544     }
00545         if(this->motor_max_rot_decel < 0)
00546     {
00547                 accel_command[0] = SETRA;
00548                 accel_command[1] = ARGNINT;
00549                 accel_command[2] = -1*(this->motor_max_rot_decel) & 0x00FF;
00550                 accel_command[3] = (-1*(this->motor_max_rot_decel) & 0xFF00) >> 8;
00551                 accel_packet.Build(accel_command, 4);
00552                 this->SendReceive(&accel_packet,false);
00553     }
00554     
00555     
00556         // if requested, change PID settings
00557         P2OSPacket pid_packet;
00558         unsigned char pid_command[4];
00559         if(this->rot_kp >= 0)
00560     {
00561                 pid_command[0] = ROTKP;
00562                 pid_command[1] = ARGINT;
00563                 pid_command[2] = this->rot_kp & 0x00FF;
00564                 pid_command[3] = (this->rot_kp & 0xFF00) >> 8;
00565                 pid_packet.Build(pid_command, 4);
00566                 this->SendReceive(&pid_packet);
00567     }
00568         if(this->rot_kv >= 0)
00569     {
00570                 pid_command[0] = ROTKV;
00571                 pid_command[1] = ARGINT;
00572                 pid_command[2] = this->rot_kv & 0x00FF;
00573                 pid_command[3] = (this->rot_kv & 0xFF00) >> 8;
00574                 pid_packet.Build(pid_command, 4);
00575                 this->SendReceive(&pid_packet);
00576     }
00577         if(this->rot_ki >= 0)
00578     {
00579                 pid_command[0] = ROTKI;
00580                 pid_command[1] = ARGINT;
00581                 pid_command[2] = this->rot_ki & 0x00FF;
00582                 pid_command[3] = (this->rot_ki & 0xFF00) >> 8;
00583                 pid_packet.Build(pid_command, 4);
00584                 this->SendReceive(&pid_packet);
00585     }
00586         if(this->trans_kp >= 0)
00587     {
00588                 pid_command[0] = TRANSKP;
00589                 pid_command[1] = ARGINT;
00590                 pid_command[2] = this->trans_kp & 0x00FF;
00591                 pid_command[3] = (this->trans_kp & 0xFF00) >> 8;
00592                 pid_packet.Build(pid_command, 4);
00593                 this->SendReceive(&pid_packet);
00594     }
00595         if(this->trans_kv >= 0)
00596     {
00597                 pid_command[0] = TRANSKV;
00598                 pid_command[1] = ARGINT;
00599                 pid_command[2] = this->trans_kv & 0x00FF;
00600                 pid_command[3] = (this->trans_kv & 0xFF00) >> 8;
00601                 pid_packet.Build(pid_command, 4);
00602                 this->SendReceive(&pid_packet);
00603     }
00604         if(this->trans_ki >= 0)
00605     {
00606                 pid_command[0] = TRANSKI;
00607                 pid_command[1] = ARGINT;
00608                 pid_command[2] = this->trans_ki & 0x00FF;
00609                 pid_command[3] = (this->trans_ki & 0xFF00) >> 8;
00610                 pid_packet.Build(pid_command, 4);
00611                 this->SendReceive(&pid_packet);
00612     }
00613     
00614     
00615         // if requested, change bumper-stall behavior
00616         // 0 = don't stall
00617         // 1 = stall on front bumper contact
00618         // 2 = stall on rear bumper contact
00619         // 3 = stall on either bumper contact
00620         if(this->bumpstall >= 0)
00621     {
00622                 if(this->bumpstall > 3)
00623                         ROS_INFO("ignoring bumpstall value %d; should be 0, 1, 2, or 3",
00624                                          this->bumpstall);
00625                 else
00626         {
00627                         ROS_INFO("setting bumpstall to %d", this->bumpstall);
00628                         P2OSPacket bumpstall_packet;;
00629                         unsigned char bumpstall_command[4];
00630                         bumpstall_command[0] = BUMP_STALL;
00631                         bumpstall_command[1] = ARGINT;
00632                         bumpstall_command[2] = (unsigned char)this->bumpstall;
00633                         bumpstall_command[3] = 0;
00634                         bumpstall_packet.Build(bumpstall_command, 4);
00635                         this->SendReceive(&bumpstall_packet,false);
00636         }
00637     }
00638     
00639         // Turn on the sonar
00640         if(use_sonar_) {
00641                 this->ToggleSonarPower(1);
00642                 ROS_DEBUG("Sonar array powered on.");
00643         }
00644         ptz_.setup();
00645     
00646         return(0);
00647 }
00648 
00649 int P2OSNode::Shutdown()
00650 {
00651         unsigned char command[20],buffer[20];
00652         P2OSPacket packet;
00653     
00654         if (ptz_.isOn())
00655     {
00656                 ptz_.shutdown();
00657     }
00658     
00659         memset(buffer,0,20);
00660     
00661         if(this->psos_fd == -1)
00662                 return -1;
00663     
00664         command[0] = STOP;
00665         packet.Build(command, 1);
00666         packet.Send(this->psos_fd);
00667         usleep(P2OS_CYCLETIME_USEC);
00668     
00669         command[0] = CLOSE;
00670         packet.Build(command, 1);
00671         packet.Send(this->psos_fd);
00672         usleep(P2OS_CYCLETIME_USEC);
00673     
00674         close(this->psos_fd);
00675         this->psos_fd = -1;
00676         ROS_INFO("P2OS has been shutdown");
00677         delete this->sippacket;
00678         this->sippacket = NULL;
00679     
00680         return 0;
00681 }
00682 
00683 
00684 void
00685 P2OSNode::StandardSIPPutData(ros::Time ts)
00686 {
00687     
00688         p2os_data.position.header.stamp = ts;
00689         pose_pub_.publish(p2os_data.position);
00690         p2os_data.odom_trans.header.stamp = ts;
00691         odom_broadcaster.sendTransform(p2os_data.odom_trans);
00692     
00693         p2os_data.batt.header.stamp = ts;
00694         batt_pub_.publish(p2os_data.batt);
00695         mstate_pub_.publish(p2os_data.motors);
00696     
00697         // put sonar data
00698         p2os_data.sonar.header.stamp = ts;
00699         sonar_pub_.publish(p2os_data.sonar);
00700     
00701         // put aio data
00702         aio_pub_.publish(p2os_data.aio);
00703         // put dio data
00704         dio_pub_.publish(p2os_data.dio);
00705     
00706         // put gripper and lift data
00707         grip_state_pub_.publish(p2os_data.gripper);
00708         ptz_state_pub_.publish(ptz_.getCurrentState());
00709     
00710         // put bumper data
00711         // put compass data
00712     
00713 }
00714 
00715 /* send the packet, then receive and parse an SIP */
00716 int P2OSNode::SendReceive(P2OSPacket* pkt, bool publish_data)
00717 {
00718         P2OSPacket packet;
00719     
00720         if((this->psos_fd >= 0) && this->sippacket)
00721     {
00722                 if(pkt)
00723                         pkt->Send(this->psos_fd);
00724         
00725                 /* receive a packet */
00726                 pthread_testcancel();
00727                 if(packet.Receive(this->psos_fd))
00728         {
00729                         ROS_ERROR("RunPsosThread(): Receive errored");
00730                         pthread_exit(NULL);
00731         }
00732         
00733                 if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
00734                    (packet.packet[3] == 0x30 || packet.packet[3] == 0x31 ||
00735                         packet.packet[3] == 0x32 || packet.packet[3] == 0x33 ||
00736                         packet.packet[3] == 0x34))
00737         {
00738             
00739                         /* It is a server packet, so process it */
00740                         this->sippacket->ParseStandard(&packet.packet[3]);
00741                         this->sippacket->FillStandard(&(this->p2os_data));
00742             
00743                         if(publish_data)
00744                                 this->StandardSIPPutData(packet.timestamp);
00745         }
00746                 else if(packet.packet[0] == 0xFA && packet.packet[1] == 0xFB &&
00747                                 packet.packet[3] == SERAUX)
00748         {
00749                         // This is an AUX serial packet
00750                         if(ptz_.isOn())
00751             {
00752                                 int len = packet.packet[2] - 3;
00753                                 if (ptz_.cb_.gotPacket())
00754                 {
00755                                         ROS_ERROR("PTZ got a message, but alread has the complete packet.");
00756                 }
00757                                 else
00758                 {
00759                                         for (int i=4; i < 4+len; ++i)
00760                     {
00761                                                 ptz_.cb_.putOnBuf(packet.packet[i]);
00762                     }
00763                 }
00764             }
00765         }
00766                 else
00767         {
00768                         ROS_ERROR("Received other packet!");
00769                         packet.PrintHex();
00770         }
00771     }
00772     
00773         return(0);
00774 }
00775 
00776 void P2OSNode::updateDiagnostics()
00777 {
00778         diagnostic_.update();
00779 }
00780 
00781 void P2OSNode::check_voltage(diagnostic_updater::DiagnosticStatusWrapper &stat)
00782 {
00783         double voltage = sippacket->battery / 10.0;
00784         if(voltage < 11.0) stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "battery voltage critically low");
00785         else if (voltage < 11.75) stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "battery voltage getting low");
00786         else stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "battery voltage OK");
00787     
00788         stat.add("voltage", voltage);
00789 }
00790 
00791 void P2OSNode::check_stall(diagnostic_updater::DiagnosticStatusWrapper &stat)
00792 {
00793         if(sippacket->lwstall||sippacket->rwstall) stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR,
00794                                                                                                                         "wheel stalled");
00795         else stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "no wheel stall");
00796     
00797         stat.add("left wheel stall", sippacket->lwstall);
00798         stat.add("right wheel stall", sippacket->rwstall);
00799 }
00800 
00801 void P2OSNode::ResetRawPositions()
00802 {
00803         P2OSPacket pkt;
00804         unsigned char p2oscommand[4];
00805     
00806         if(this->sippacket) {
00807                 this->sippacket->rawxpos = 0;
00808                 this->sippacket->rawypos = 0;
00809                 this->sippacket->xpos = 0;
00810                 this->sippacket->ypos = 0;
00811                 p2oscommand[0] = SETO;
00812                 p2oscommand[1] = ARGINT;
00813                 pkt.Build(p2oscommand, 2);
00814                 this->SendReceive(&pkt,false);
00815                 ROS_INFO("resetting raw positions");
00816         }
00817 }
00818 
00819 /* toggle sonars on/off, according to val */
00820 void P2OSNode::ToggleSonarPower(unsigned char val)
00821 {
00822         unsigned char command[4];
00823         P2OSPacket packet;
00824     
00825         command[0] = SONAR;
00826         command[1] = ARGINT;
00827         command[2] = val;
00828         command[3] = 0;
00829         packet.Build(command, 4);
00830         SendReceive(&packet,false);
00831 }
00832 
00838 void P2OSNode::ToggleMotorPower(unsigned char val)
00839 {
00840         unsigned char command[4];
00841         P2OSPacket packet;
00842         ROS_INFO("motor state: %d\n", p2os_data.motors.state);
00843         p2os_data.motors.state = (int) val;
00844         command[0] = ENABLE;
00845         command[1] = ARGINT;
00846         command[2] = val;
00847         command[3] = 0;
00848         packet.Build(command, 4);
00849         SendReceive(&packet,false);
00850 }
00851 
00853 //  Actarray stuff
00855 
00856 // Ticks to degrees from the ARIA software
00858 inline double P2OSNode::TicksToDegrees (int joint, unsigned char ticks)
00859 {
00860         if ((joint < 0) || (joint >= sippacket->armNumJoints))
00861                 return 0;
00862     
00863         double result;
00864         int pos = ticks - sippacket->armJoints[joint].centre;
00865         result = 90.0 / static_cast<double> (sippacket->armJoints[joint].ticksPer90);
00866         result = result * pos;
00867         if ((joint >= 0) && (joint <= 2))
00868                 result = -result;
00869     
00870         return result;
00871 }
00872 
00873 // Degrees to ticks from the ARIA software
00875 inline unsigned char P2OSNode::DegreesToTicks (int joint, double degrees)
00876 {
00877         double val;
00878     
00879         if ((joint < 0) || (joint >= sippacket->armNumJoints))
00880                 return 0;
00881     
00882         val = static_cast<double> (sippacket->armJoints[joint].ticksPer90) * degrees / 90.0;
00883         val = round (val);
00884         if ((joint >= 0) && (joint <= 2))
00885                 val = -val;
00886         val += sippacket->armJoints[joint].centre;
00887     
00888         if (val < sippacket->armJoints[joint].min) return sippacket->armJoints[joint].min;
00889         else if (val > sippacket->armJoints[joint].max) return sippacket->armJoints[joint].max;
00890         else return static_cast<int> (round (val));
00891 }
00892 
00894 inline double P2OSNode::TicksToRadians (int joint, unsigned char ticks)
00895 {
00896         double result = DTOR (TicksToDegrees (joint, ticks));
00897         return result;
00898 }
00899 
00901 inline unsigned char P2OSNode::RadiansToTicks (int joint, double rads)
00902 {
00903         unsigned char result = static_cast<unsigned char> (DegreesToTicks (joint, RTOD (rads)));
00904         return result;
00905 }
00906 
00908 inline double P2OSNode::RadsPerSectoSecsPerTick (int joint, double speed)
00909 {
00910         double degs = RTOD (speed);
00911         double ticksPerDeg = static_cast<double> (sippacket->armJoints[joint].ticksPer90) / 90.0;
00912         double ticksPerSec = degs * ticksPerDeg;
00913         double secsPerTick = 1000.0f / ticksPerSec;
00914     
00915         if (secsPerTick > 127)
00916                 return 127;
00917         else if (secsPerTick < 1)
00918                 return 1;
00919         return secsPerTick;
00920 }
00921 
00923 inline double P2OSNode::SecsPerTicktoRadsPerSec (int joint, double msecs)
00924 {
00925         double ticksPerSec = 1.0 / (static_cast<double> (msecs) / 1000.0);
00926         double ticksPerDeg = static_cast<double> (sippacket->armJoints[joint].ticksPer90) / 90.0;
00927         double degs = ticksPerSec / ticksPerDeg;
00928         double rads = DTOR (degs);
00929     
00930         return rads;
00931 }
00932 
00933 void P2OSNode::SendPulse (void)
00934 {
00935         unsigned char command;
00936         P2OSPacket packet;
00937     
00938         command = PULSE;
00939         packet.Build(&command, 1);
00940         SendReceive(&packet);
00941 }


p2os_driver
Author(s): Hunter L. Allen , David Feil-Seifer , Aris Synodinos , Brian Gerkey, Kasper Stoy, Richard Vaughan, Andrew Howard, Tucker Hermans, ActivMedia Robotics LLC, MobileRobots Inc.
autogenerated on Sat Aug 5 2017 02:20:17