00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
00051
00052 n_private.param("bumpstall", bumpstall, -1);
00053
00054 n_private.param("pulse", pulse, -1.0);
00055
00056 n_private.param("rot_kp", rot_kp, -1);
00057
00058 n_private.param("rot_kv", rot_kv, -1);
00059
00060 n_private.param("rot_ki", rot_ki, -1);
00061
00062 n_private.param("trans_kp", trans_kp, -1);
00063
00064 n_private.param("trans_kv", trans_kv, -1);
00065
00066 n_private.param("trans_ki", trans_ki, -1);
00067
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
00076 n_private.param("radio", radio_modemp, 0);
00077
00078 n_private.param("joystick", joystick, 0);
00079
00080 n_private.param("direct_wheel_vel_control", direct_wheel_vel_control, 0);
00081
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
00086 n_private.param("max_yawspeed", spd, MOTOR_DEF_MAX_TURNSPEED);
00087 motor_max_turnspeed = static_cast<int16_t>(rint(RTOD(spd)));
00088
00089 n_private.param("max_xaccel", spd, 0.0);
00090 motor_max_trans_accel = static_cast<int16_t>(rint(1e3 * spd));
00091
00092 n_private.param("max_xdecel", spd, 0.0);
00093 motor_max_trans_decel = static_cast<int16_t>(rint(1e3 * spd));
00094
00095 n_private.param("max_yawaccel", spd, 0.0);
00096 motor_max_rot_accel = static_cast<int16_t>(rint(RTOD(spd)));
00097
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
00104 pose_pub_ = n.advertise<nav_msgs::Odometry>("pose", 1000);
00105
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
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
00124 diagnostic_.add("Motor Stall", this, &P2OSNode::check_stall);
00125 diagnostic_.add("Battery Voltage", this, &P2OSNode::check_voltage);
00126
00127
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
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
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
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
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
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
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
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
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
00422
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
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
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
00493
00494
00495
00496
00497
00498
00499 this->ToggleSonarPower(0);
00500
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
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
00592
00593
00594
00595
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
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
00671 p2os_data.sonar.header.stamp = ts;
00672 sonar_pub_.publish(p2os_data.sonar);
00673
00674
00675 aio_pub_.publish(p2os_data.aio);
00676
00677 dio_pub_.publish(p2os_data.dio);
00678
00679
00680 grip_state_pub_.publish(p2os_data.gripper);
00681 ptz_state_pub_.publish(ptz_.getCurrentState());
00682
00683
00684
00685 }
00686
00687
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
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
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
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
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
00822
00823
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
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 }