sicks3000.cc
Go to the documentation of this file.
00001 /*
00002 *  Copyright (c) 2012, Robotnik Automation, SLL
00003 *
00004 *
00005 *   This program is free software: you can redistribute it and/or modify
00006 *   it under the terms of the GNU General Public License as published by
00007 *   the Free Software Foundation, either version 3 of the License, or
00008 *   (at your option) any later version.
00009 *
00010 *   This program is distributed in the hope that it will be useful,
00011 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 *   GNU General Public License for more details.
00014 *
00015 *   You should have received a copy of the GNU General Public License
00016 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 *
00018 */
00019 /*
00020  Desc: Driver for the SICK S3000 laser
00021  Author: Robotnik Automation SLL (based on sicks3000 by Brian Gerkey, Kasper Stoy, Richard Vaughan, & Andrew Howard for Player/Stage)
00022  Date: 1 Sept 2012
00023 
00024  The sicks3000 driver controls the SICK S 3000 safety laser scanner interpreting its data output.
00025  The driver is very basic and assumes the S3000 has already been configured to continuously output
00026  its measured data on the RS422 data lines.
00027 */
00028 
00029 #include <netinet/in.h>  // htons
00030 #include "s3000_laser/sicks3000.h"
00031 
00032 // 1 second of data at 500kbaud
00033 #define DEFAULT_RX_BUFFER_SIZE 500*1024/8
00034 
00038 SickS3000::SickS3000( std::string port, int baudrate, std::string parity, int datasize )
00039 : serial_( port.c_str(), baudrate, parity.c_str(), datasize )
00040 {
00041   rx_count = 0;
00042   // allocate our recieve buffer
00043   rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
00044   rx_buffer = new uint8_t[rx_buffer_size];
00045   assert(rx_buffer);
00046 
00047   recognisedScanner = false;
00048 }
00049 
00050 SickS3000::~SickS3000() 
00051 {
00052   delete [] rx_buffer;
00053 }
00054 
00060 bool SickS3000::Open()
00061 {
00062     return serial_.OpenPort();
00063 }
00064 
00070 bool SickS3000::Close()
00071 {
00072     return serial_.ClosePort();
00073 }
00074 
00076 // Set up scanner parameters based on number of results per scan
00077 bool SickS3000::SetScannerParams(sensor_msgs::LaserScan& scan, int data_count)
00078 {
00079     if (data_count == 761) // sicks3000
00080     {
00081         float freq_hz = 16.6;
00082                 
00083         scan.angle_min          = deg_to_rad(-95);
00084         scan.angle_max          = deg_to_rad(95);
00085         scan.angle_increment    = deg_to_rad(0.25);
00086         scan.scan_time          = 1.0 / freq_hz;
00087         scan.time_increment     = scan.scan_time / data_count;
00088         scan.range_min          = 0;
00089         scan.range_max          = 49;   // check ?
00090 
00091         return true;
00092     }
00093 
00094     if (data_count == 381) // sicks3000 0.5deg resolution
00095     {
00096         float freq_hz = 20.0;
00097 
00098         scan.angle_min          = deg_to_rad(-95);
00099         scan.angle_max          = deg_to_rad(95);
00100         scan.angle_increment    = deg_to_rad(0.5);
00101         scan.scan_time          = 1.0 / freq_hz;
00102         scan.time_increment     = scan.scan_time / data_count;
00103         scan.range_min          = 0;
00104         scan.range_max          = 49;   // check ?
00105 
00106         return true;
00107     }
00108 
00109     if (data_count == 541) // sicks30b
00110     {
00111         float freq_hz = 12.7;
00112 
00113         scan.angle_min          = deg_to_rad(-135);
00114         scan.angle_max          = deg_to_rad(135);
00115         scan.angle_increment    = deg_to_rad(0.5);
00116         scan.scan_time          = 1.0 / freq_hz;
00117         scan.time_increment     = scan.scan_time / data_count;
00118         scan.range_min          = 0;
00119         scan.range_max          = 40;   // check ? 30m in datasheet
00120 
00121         return true;
00122     }
00123     
00124     return false;
00125 }
00126 
00127 bool SickS3000::ReadLaser( sensor_msgs::LaserScan& scan )
00128 {
00129         int bytes_read=0;                       // Number of received bytes
00130 
00131         // Read controller messages
00132         if (serial_.ReadPort(read_buffer_, READ_BUFFER_SIZE, bytes_read)==false) 
00133         {
00134             ROS_ERROR("SickS3000::ReadLaser: Error reading port");
00135             return false;
00136     }
00137 
00138         if (rx_count + bytes_read > rx_buffer_size) 
00139         {
00140            ROS_WARN("S3000 Buffer Full");
00141            rx_count = 0; // clear buffer
00142            return false;
00143     }
00144 
00145    memcpy(&rx_buffer[rx_count], read_buffer_, bytes_read);
00146    rx_count += bytes_read;
00147 
00148    bool bValidData=false;
00149    ProcessLaserData(scan, bValidData);
00150    
00151    return bValidData;
00152 }
00153 
00156 
00157 int SickS3000::ProcessLaserData(sensor_msgs::LaserScan& scan, bool& bValidData)
00158 {
00159   while(rx_count >= 22)
00160   {
00161     // find our continuous data header
00162     unsigned int ii;
00163     bool found = false;
00164     for (ii = 0; ii < rx_count - 22; ++ii)
00165     {
00166       if (memcmp(&rx_buffer[ii],"\0\0\0\0\0\0",6) == 0)
00167       {
00168         memmove(rx_buffer, &rx_buffer[ii], rx_count-ii);
00169         rx_count -= ii;
00170         found = true;
00171         break;
00172       }
00173     }
00174 
00175     if (!found)
00176     {
00177       memmove(rx_buffer, &rx_buffer[ii], rx_count-ii);
00178       rx_count -= ii;
00179       return 0;
00180     }
00181 
00182     // get relevant bits of the header
00183     // size includes all data from the data block number
00184     // through to the end of the packet including the checksum
00185     unsigned short size = 2*htons(*reinterpret_cast<unsigned short *> (&rx_buffer[6]));
00186     //ROS_INFO(" size %d   rx_count %d ", size, rx_count);
00187     if (size > rx_buffer_size - 26)
00188     {
00189       ROS_WARN("S3000: Requested Size of data is larger than the buffer size");
00190       memmove(rx_buffer, &rx_buffer[1], --rx_count);
00191       return 0;
00192     }
00193 
00194     // check if we have enough data yet
00195     if (size > rx_count - 4)
00196       return 0;
00197 
00198 
00199     unsigned short packet_checksum = *reinterpret_cast<unsigned short *> (&rx_buffer[size+2]);
00200     unsigned short calc_checksum = CreateCRC(&rx_buffer[4], size-2);
00201     if (packet_checksum != calc_checksum)
00202     {
00203       ROS_WARN("S3000: Checksum's dont match, thats bad (data packet size %d)",size);
00204       memmove(rx_buffer, &rx_buffer[1], --rx_count);
00205       continue;
00206     }
00207 
00208     else
00209     {
00210       uint8_t * data = &rx_buffer[20];
00211       if (data[0] != data[1])
00212       {
00213         ROS_WARN("S3000: Bad type header bytes dont match");
00214       }
00215       else
00216       {
00217         if (data[0] == 0xAA)
00218         {
00219           ROS_WARN("S3000: We got a I/O data packet we dont know what to do with it\n");
00220         }
00221         else if (data[0] == 0xBB)
00222         {
00223           int data_count = (size - 22) / 2;
00224           if (data_count < 0)
00225           {
00226             ROS_WARN("S3000: bad data count (%d)", data_count);
00227             memmove(rx_buffer, &rx_buffer[size+4], rx_count - (size+4));
00228             rx_count -= (size + 4);
00229             continue;
00230           }
00231           if (!recognisedScanner)
00232           {
00233             // Set up parameters based on number of results.
00234                         if(SetScannerParams(scan, data_count)) recognisedScanner=true; 
00235                   }
00236 
00237           // Scan data, clear ranges, keep configuration
00238           scan.ranges.clear();
00239           scan.intensities.clear();  // not used
00240           // scan.ranges_count = data_count;
00241           scan.ranges.resize(data_count);  //
00242           for (int ii = 0; ii < data_count; ++ii)
00243           {
00244             unsigned short Distance_CM = (*reinterpret_cast<unsigned short *> (&data[4 + 2*ii]));
00245             Distance_CM &= 0x1fff; // remove status bits
00246             double distance_m = static_cast<double>(Distance_CM)/100.0;
00247                 scan.ranges[ii] = static_cast<float> (distance_m);
00248           }
00249 
00250         // CHECK
00251           // Return this flag to let the node know that the message is ready to publish
00252           bValidData = true;
00253         }
00254         else if (data[0] == 0xCC && data[1] == 0xCC )
00255         {
00256             size_t read_pos=2; // start reading after 'CCCC' header
00257             
00258             uint16_t reflector_count = *reinterpret_cast<uint16_t*>( &data[read_pos] );
00259             read_pos += sizeof(reflector_count);
00260 
00261             ROS_DEBUG_STREAM( "reflectors=" << reflector_count );
00262             bValidData = ( reflector_count > 0 );
00263 
00264             uint32_t reflector_data, num_ranges = ( scan.angle_max - scan.angle_min ) / scan.angle_increment;
00265     
00266             scan.header.stamp = ros::Time::now();
00267             scan.ranges.resize( num_ranges );
00268             std::fill( scan.ranges.begin(), scan.ranges.end(), scan.range_min-1 );
00269             scan.intensities.clear();  // not used
00270             
00271             for ( size_t i=0; i< reflector_count; ++i )
00272             {
00273                 reflector_data = *reinterpret_cast<uint32_t*>( &data[read_pos] );
00274                 read_pos += sizeof(reflector_data);
00275                 
00276                 int raw_angle = reflector_data & 0xFFFF; // read 16 bits
00277                 int raw_dist = ( reflector_data >> 16 ) & 0x1FFF; // read 13 bits
00278                 ROS_DEBUG("reflector %lu: angle=%.2fdeg distance=%.2fm", i, raw_angle*0.01, raw_dist*0.01 );
00279 
00280                 float scan_angle = scan.angle_max - deg_to_rad(raw_angle*0.01);
00281                 int range_idx = ( scan.angle_max - scan_angle ) / scan.angle_increment;
00282 
00283                 if ( range_idx >= 0 && range_idx < scan.ranges.size() ) scan.ranges[range_idx] = raw_dist*0.01;
00284                 else ROS_WARN("invalid reflector angle=%.2frad, idx=%d/%lu", scan_angle, range_idx, scan.ranges.size() );
00285             }
00286         }
00287         else
00288         {
00289           ROS_WARN("We got an unknown packet\n");
00290         }
00291 
00292       }
00293     }
00294 
00295     memmove(rx_buffer, &rx_buffer[size+4], rx_count - (size+4));
00296     rx_count -= (size + 4);
00297     continue;
00298   }
00299   return 1;
00300 }
00301 
00302 
00303 static const unsigned short crc_table[256] = 
00304 {
00305   0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
00306   0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
00307   0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
00308   0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
00309   0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
00310   0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
00311   0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
00312   0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
00313   0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
00314   0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
00315   0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
00316   0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
00317   0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
00318   0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
00319   0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
00320   0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
00321   0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
00322   0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
00323   0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
00324   0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
00325   0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
00326   0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
00327   0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
00328   0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
00329   0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
00330   0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
00331   0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
00332   0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
00333   0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
00334   0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
00335   0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
00336   0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
00337 };
00338 
00339 unsigned short SickS3000::CreateCRC(const uint8_t *Data, ssize_t length)
00340 {
00341   unsigned short CRC_16 = 0xFFFF;
00342   unsigned short i;
00343   for (i = 0; i < length; i++)
00344   {
00345     CRC_16 = (CRC_16 << 8) ^ (crc_table[(CRC_16 >> 8) ^ (Data[i])]);
00346   }
00347   return CRC_16;
00348 }


s3000_laser
Author(s): Roman Navarro Garcia
autogenerated on Sat Jun 8 2019 20:55:59