$search
00001 /* 00002 * AscTec Autopilot Serial Interface 00003 * Copyright (C) 2010, CCNY Robotics Lab 00004 * William Morris <morris@ee.ccny.cuny.edu> 00005 * Ivan Dryanovski <ivan.dryanovski@gmail.com> 00006 * Steven Bellens <steven.bellens@mech.kuleuven.be> 00007 * Patrick Bouffard <bouffard@eecs.berkeley.edu> 00008 * 00009 * http://robotics.ccny.cuny.edu 00010 * 00011 * This program is free software: you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License as published by 00013 * the Free Software Foundation, either version 3 of the License, or 00014 * (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00023 */ 00024 00025 #include <stdio.h> 00026 #include <sys/termios.h> 00027 #include <sys/ioctl.h> 00028 #include <cstring> 00029 #include <cstdlib> 00030 #include <time.h> 00031 #include <errno.h> 00032 #include <bitset> 00033 00034 #include <ros/ros.h> 00035 00036 #include "asctec_autopilot/crc16.h" 00037 #include "asctec_autopilot/autopilot.h" 00038 #include "asctec_autopilot/telemetry.h" 00039 #include "asctec_autopilot/serialinterface.h" 00040 00041 // C++ is a horrible version of C 00042 extern "C" { 00043 #include <unistd.h> 00044 #include <fcntl.h> 00045 } 00046 00047 namespace asctec 00048 { 00049 SerialInterface::SerialInterface (std::string port, uint32_t speed):serialport_name_ (port), serialport_speed_ (speed) 00050 { 00051 struct termios tio; 00052 status = false; 00053 serialport_baud_ = bitrate (serialport_speed_); 00054 ROS_INFO ("Initializing serial port..."); 00055 00056 dev_ = open(serialport_name_.c_str (),O_RDWR | O_NOCTTY | O_NDELAY); 00057 ROS_DEBUG ("dev: %d", dev_); 00058 ROS_ASSERT_MSG (dev_ != -1, "Failed to open serial port: %s %s", serialport_name_.c_str (), strerror (errno)); 00059 00060 ROS_ASSERT_MSG (tcgetattr (dev_, &tio) == 0, "Unknown Error: %s", strerror (errno)); 00061 00062 cfsetispeed (&tio, serialport_baud_); 00063 cfsetospeed (&tio, serialport_baud_); 00064 00065 tio.c_iflag = 0; 00066 tio.c_iflag &= ~(BRKINT | ICRNL | IMAXBEL); 00067 tio.c_iflag |= IGNBRK; 00068 00069 tio.c_oflag = 0; 00070 tio.c_oflag &= ~(OPOST | ONLCR); 00071 00072 tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8; 00073 tio.c_cflag &= ~(PARENB | CRTSCTS | CSTOPB); 00074 00075 tio.c_lflag = 0; 00076 tio.c_lflag |= NOFLSH; 00077 tio.c_lflag &= ~(ISIG | IEXTEN | ICANON | ECHO | ECHOE); 00078 00079 ROS_ASSERT_MSG (tcsetattr (dev_, TCSADRAIN, &tio) == 0, "Unknown Error: %s", strerror (errno)); 00080 00081 tio.c_cc[VMIN] = 0; 00082 tio.c_cc[VTIME] = 0; 00083 00084 tcflush (dev_, TCIOFLUSH); 00085 00086 ROS_ASSERT_MSG (dev_ != NULL, "Could not open serial port %s", serialport_name_.c_str ()); 00087 ROS_INFO ("Successfully connected to %s, Baudrate %d\n", serialport_name_.c_str (), serialport_speed_); 00088 } 00089 00090 SerialInterface::~SerialInterface () 00091 { 00092 ROS_DEBUG ("Destroying Serial Interface"); 00093 flush (); 00094 close (dev_); 00095 } 00096 00097 void SerialInterface::flush () 00098 { 00099 tcflush (dev_, TCIOFLUSH); 00100 } 00101 00102 void SerialInterface::drain () 00103 { 00104 ROS_ASSERT_MSG (tcdrain (dev_) == 0, "Drain Error: %s", strerror (errno)); 00105 } 00106 00107 int SerialInterface::wait (int bytes_requested) 00108 { 00109 int bytes_available=0; 00110 unsigned int i=0; 00111 00112 while (bytes_available < bytes_requested) 00113 { 00114 ioctl(dev_,FIONREAD,&bytes_available); 00115 usleep(1); 00116 if (i>650 && bytes_available < bytes_requested) 00117 { 00118 ROS_ERROR("Timeout: %d bytes available %d bytes requested",bytes_available,bytes_requested); 00119 return bytes_available; 00120 } 00121 i++; 00122 } 00123 return bytes_available; 00124 } 00125 00126 speed_t SerialInterface::bitrate (int Bitrate) 00127 { 00128 switch (Bitrate) 00129 { 00130 case 9600: 00131 return B9600; 00132 case 19200: 00133 return B19200; 00134 case 38400: 00135 return B38400; 00136 case 57600: 00137 return B57600; 00138 case 115200: 00139 return B115200; 00140 case 230400: 00141 return B230400; 00142 default: // invalid bitrate 00143 return B0; 00144 } 00145 } 00146 00147 bool SerialInterface::getPacket (char *spacket, unsigned char &packet_type, unsigned short &packet_crc, 00148 unsigned short &packet_size) 00149 { 00150 char stoken[4]; 00151 char ssize[2]; 00152 char stype[1]; 00153 char scrc[2]; 00154 int bytes; 00155 00156 int i; 00157 00158 ROS_DEBUG (" SerialInterface::getPacket()"); 00159 // get beginning (">*>") 00160 stoken[0] = '\0'; 00161 stoken[1] = '\0'; 00162 stoken[2] = '\0'; 00163 stoken[3] = '\0'; 00164 00165 wait(3); 00166 i = read (dev_,stoken, 3); 00167 if (i == 0 || strncmp (stoken, ">*>", 3) != 0) 00168 { 00169 ROS_DEBUG (" dev: %zd", (size_t) dev_); 00170 ROS_ERROR (" Error Reading Packet Header: %s", strerror (errno)); 00171 ROS_ERROR (" Read (%d): %s", i, stoken); 00172 //ROS_BREAK(); 00173 //while (read (dev_,stoken, 1) != 0) {} 00174 flush (); 00175 return false; 00176 } 00177 serialport_bytes_rx_ += 3; 00178 ROS_DEBUG (" Packet Header OK"); 00179 00180 // get packet size 00181 wait(2); 00182 i = read (dev_,ssize, 2); 00183 if (i == 0) 00184 { 00185 ROS_ERROR ("Error Reading Packet Size: %s", strerror (errno)); 00186 flush (); 00187 return false; 00188 } 00189 serialport_bytes_rx_ += 2; 00190 memcpy (&packet_size, ssize, sizeof (packet_size)); 00191 //ROS_DEBUG ("Packet size: %d", packet_size); 00192 00193 // get packet type 00194 wait(1); 00195 i = read (dev_, stype, 1); 00196 if (i == 0) 00197 return false; 00198 serialport_bytes_rx_ += 1; 00199 memcpy (&packet_type, stype, sizeof (packet_type)); 00200 //ROS_DEBUG ("Packet type: %d", packet_type); 00201 00202 // get packet 00203 wait(packet_size); 00204 i = read (dev_, spacket, packet_size); 00205 if (i == 0) 00206 return false; 00207 serialport_bytes_rx_ += packet_size; 00208 //ROS_DEBUG ("Packet string: ok"); 00209 00210 // get packet crc 00211 wait(2); 00212 i = read (dev_, scrc, 2); 00213 if (i == 0) 00214 return false; 00215 serialport_bytes_rx_ += sizeof (scrc); 00216 memcpy (&packet_crc, scrc, sizeof (packet_crc)); 00217 //ROS_DEBUG ("Packet crc: %d", packet_crc); 00218 00219 // get closing ("<#<") 00220 wait(3); 00221 i = read (dev_, stoken, 3); 00222 if (i == 0 || strncmp (stoken, "<#<", 3) != 0) 00223 { 00224 ROS_ERROR ("Error Reading Packet Footer: %s", strerror (errno)); 00225 ROS_DEBUG ("Read (%d): %s", i, stoken); 00226 while (read (dev_, stoken, 1) != 0) 00227 { 00228 stoken[1] = '\0'; 00229 ROS_DEBUG ("%s", stoken); 00230 } 00231 flush (); 00232 drain (); 00233 ROS_DEBUG ("Packet Footer Corrupt!!"); 00234 return false; 00235 } 00236 serialport_bytes_rx_ += 3; 00237 //ROS_DEBUG ("Packet Footer OK"); 00238 00239 return true; 00240 } 00241 00242 void SerialInterface::output (char *output, int len) 00243 { 00244 int i; 00245 ROS_DEBUG ("SerialInterface::output()"); 00246 serialport_bytes_tx_ += len; 00247 //ROS_DEBUG ("Writing %d element(s): %s", len, output); 00248 //ROS_DEBUG ("dev: %zd", (size_t) dev_); 00249 //flush (); 00250 i = write (dev_, output, len); 00251 if (i != len) 00252 { 00253 ROS_ERROR ("Error wrote %d out of %d element(s): %s", i, len, strerror (errno)); 00254 ROS_BREAK (); 00255 } 00256 ROS_DEBUG ("Write completed"); 00257 } 00258 00259 void SerialInterface::output (unsigned char *output, int len) 00260 { 00261 int i; 00262 ROS_DEBUG ("SerialInterface::output()"); 00263 serialport_bytes_tx_ += len; 00264 //ROS_INFO ("Writing %d element(s): %s", len, output); 00265 //ROS_DEBUG ("dev: %zd", (size_t) dev_); 00266 //ROS_DEBUG ("FOO"); 00267 i = write (dev_, output, len); 00268 if (i != len) 00269 { 00270 ROS_ERROR ("Error wrote %d out of %d element(s): %s", i, len, strerror (errno)); 00271 ROS_BREAK (); 00272 } 00273 } 00274 void SerialInterface::sendControl (Telemetry * telemetry) 00275 { 00276 int i; 00277 char data[5]; 00278 00279 if(!telemetry->controlEnabled_) return; 00280 //ROS_DEBUG ("sendControl started"); 00281 flush(); 00282 unsigned char cmd[] = ">*>di"; 00283 //telemetry->dumpCTRL_INPUT(); 00284 if (telemetry->controlInterval_ != 0 && ((telemetry->controlCount_ - telemetry->controlOffset_) % telemetry->controlInterval_ == 0)) { 00285 if(telemetry->CTRL_INPUT_.chksum != telemetry->CTRL_INPUT_.pitch + telemetry->CTRL_INPUT_.roll + telemetry->CTRL_INPUT_.yaw + telemetry->CTRL_INPUT_.thrust + telemetry->CTRL_INPUT_.ctrl + (short) 0xAAAA){ 00286 //ROS_INFO("invalid CtrlInput checksum: %d != %d", telemetry->CTRL_INPUT_.chksum, telemetry->CTRL_INPUT_.pitch + telemetry->CTRL_INPUT_.roll + telemetry->CTRL_INPUT_.yaw + telemetry->CTRL_INPUT_.thrust + telemetry->CTRL_INPUT_.ctrl + (short) 0xAAAA); 00287 return; 00288 } 00289 output(cmd,5); 00290 output((unsigned char*) &telemetry->CTRL_INPUT_, 12); 00291 //ROS_INFO("writing control to pelican: size of CTRL_INPUT_ %zd", sizeof(telemetry->CTRL_INPUT_)); 00292 wait(5); 00293 //ROS_INFO("Data Available"); 00294 i = read (dev_,data,5); 00295 if (i != 5) { 00296 ROS_ERROR("Control Response : Insufficient Data"); 00297 flush(); 00298 return; 00299 } 00300 if (strncmp(data,">a",2) != 0) { 00301 ROS_ERROR("Corrupt Response Header %c%c (%0x%0x)",data[0],data[1],data[0],data[1]); 00302 flush(); 00303 return; 00304 } 00305 if (strncmp(data+3,"a<",2) != 0) { 00306 ROS_ERROR("Corrupt Response Footer %c%c (%0x%0x)",data[3],data[4],data[3],data[4]); 00307 flush(); 00308 return; 00309 } 00310 ROS_DEBUG("Control Response Code %0x",data[2]); 00311 } 00312 //ROS_INFO ("sendControl completed" ); 00313 } 00314 00315 void SerialInterface::sendEstop(Telemetry * telemetry) 00316 { 00317 static bool sent_estop_reported = false; 00318 if (!telemetry->controlEnabled_) 00319 return; 00320 //ROS_DEBUG ("sendControl started"); 00321 flush(); 00322 unsigned char cmd[] = ">*>me"; 00323 output(cmd, 5); 00324 if (!sent_estop_reported) 00325 { 00326 ROS_WARN("Sent E-Stop command!"); 00327 sent_estop_reported = true; 00328 } 00329 } 00330 00331 bool SerialInterface::getPackets (Telemetry * telemetry) 00332 { 00333 flush (); 00334 ROS_DEBUG ("SerialInterface::getPackets"); 00335 char cmd[16]; 00336 char spacket[1024]; 00337 unsigned char packet_type; 00338 unsigned short packet_crc; 00339 unsigned short packet_size; 00340 unsigned int i; 00341 bool result = false; 00342 ros::Time packetTime; 00343 00344 ROS_DEBUG (" Requesting %04x %zd packets", (short) telemetry->requestPackets_.to_ulong (), 00345 telemetry->requestPackets_.count ()); 00346 sprintf (cmd, ">*>p%c", (short) telemetry->requestPackets_.to_ulong ()); 00347 output (cmd, 6); 00348 00349 for (i = 0; i < telemetry->requestPackets_.count (); i++) 00350 { 00351 packetTime = ros::Time::now(); // Presumes that the AutoPilot is grabbing the data for each packet 00352 // immediately prior to each packet being sent, as opposed to gathering 00353 // all the data at once and then sending it all. Either way is a guess 00354 // unless we get some info from AscTec one way or the other.. 00355 bool read_result = getPacket (spacket, packet_type, packet_crc, packet_size); 00356 00357 if (read_result) 00358 { 00359 ROS_DEBUG (" Read successful: type = %d, crc = %d", packet_type, packet_crc); 00360 00361 if (packet_type == Telemetry::PD_LLSTATUS) 00362 { 00363 ROS_DEBUG (" Packet type is LL_STATUS"); 00364 memcpy (&telemetry->LL_STATUS_, spacket, packet_size); 00365 telemetry->timestamps_[RequestTypes::LL_STATUS] = packetTime; 00366 if (crc_valid (packet_crc, &telemetry->LL_STATUS_, sizeof (packet_size))) 00367 { 00368 result = true; 00369 } 00370 //telemetry->dumpLL_STATUS(); 00371 } 00372 else if (packet_type == Telemetry::PD_IMURAWDATA) 00373 { 00374 ROS_DEBUG (" Packet type is IMU_RAWDATA"); 00375 memcpy (&telemetry->IMU_RAWDATA_, spacket, packet_size); 00376 telemetry->timestamps_[RequestTypes::IMU_RAWDATA] = packetTime; 00377 if (crc_valid (packet_crc, &telemetry->IMU_RAWDATA_, packet_size)) 00378 { 00379 result = true; 00380 } 00381 //telemetry->dumpIMU_RAWDATA(); 00382 } 00383 else if (packet_type == Telemetry::PD_IMUCALCDATA) 00384 { 00385 ROS_DEBUG (" Packet type is IMU_CALCDATA"); 00386 memcpy (&telemetry->IMU_CALCDATA_, spacket, packet_size); 00387 telemetry->timestamps_[RequestTypes::IMU_CALCDATA] = packetTime; 00388 if (crc_valid (packet_crc, &telemetry->IMU_CALCDATA_, packet_size)) 00389 { 00390 result = true; 00391 } 00392 //telemetry->dumpIMU_CALCDATA(); 00393 } 00394 else if (packet_type == Telemetry::PD_RCDATA) 00395 { 00396 ROS_DEBUG (" Packet type is RC_DATA"); 00397 memcpy (&telemetry->RC_DATA_, spacket, packet_size); 00398 telemetry->timestamps_[RequestTypes::RC_DATA] = packetTime; 00399 if (crc_valid (packet_crc, &telemetry->RC_DATA_, packet_size)) 00400 { 00401 result = true; 00402 } 00403 //telemetry->dumpRC_DATA(); 00404 } 00405 else if (packet_type == Telemetry::PD_CTRLOUT) 00406 { 00407 ROS_DEBUG (" Packet type is CONTROLLER_OUTPUT"); 00408 memcpy (&telemetry->CONTROLLER_OUTPUT_, spacket, packet_size); 00409 telemetry->timestamps_[RequestTypes::CONTROLLER_OUTPUT] = packetTime; 00410 if (crc_valid (packet_crc, &telemetry->CONTROLLER_OUTPUT_, packet_size)) 00411 { 00412 result = true; 00413 } 00414 //telemetry->dumpCONTROLLER_OUTPUT(); 00415 } 00416 else if (packet_type == Telemetry::PD_GPSDATA) 00417 { 00418 ROS_DEBUG (" Packet type is GPS_DATA"); 00419 memcpy (&telemetry->GPS_DATA_, spacket, packet_size); 00420 telemetry->timestamps_[RequestTypes::GPS_DATA] = packetTime; 00421 if (crc_valid (packet_crc, &telemetry->GPS_DATA_, packet_size)) 00422 { 00423 result = true; 00424 } 00425 //telemetry->dumpGPS_DATA(); 00426 } 00427 else if (packet_type == Telemetry::PD_GPSDATAADVANCED) 00428 { 00429 ROS_DEBUG (" Packet type is GPS_DATA_ADVANCED"); 00430 memcpy (&telemetry->GPS_DATA_ADVANCED_, spacket, packet_size); 00431 telemetry->timestamps_[RequestTypes::GPS_DATA_ADVANCED] = packetTime; 00432 if (crc_valid (packet_crc, &telemetry->GPS_DATA_ADVANCED_, packet_size)) 00433 { 00434 result = true; 00435 } 00436 //telemetry->dumpGPS_DATA_ADVANCED(); 00437 } 00438 else 00439 { 00440 ROS_ERROR (" Packet type (%#2x) is UNKNOWN", packet_type); 00441 } 00442 } 00443 else 00444 { 00445 // failed read 00446 ROS_ERROR (" Read failed"); 00447 break; 00448 } 00449 } 00450 ioctl(dev_,FIONREAD,&i); 00451 if (i != 0) 00452 { 00453 ROS_ERROR (" Unexpected Data: Flushing receive buffer"); 00454 flush(); 00455 } 00456 return result; 00457 } 00458 } 00459