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


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 Wed Mar 27 2019 02:34:57