snark
stream.h
1 // This file is part of snark, a generic and flexible library
2 // for robotics research.
3 //
4 // Copyright (C) 2011 The University of Sydney
5 //
6 // snark is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 3 of the License, or (at your option) any later version.
10 //
11 // snark is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 // for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with snark. If not, see <http://www.gnu.org/licenses/>.
18 
19 #ifndef SNARK_SENSORS_VELODYNE_STREAM_H_
20 #define SNARK_SENSORS_VELODYNE_STREAM_H_
21 
22 #include <stdlib.h>
23 #include <boost/noncopyable.hpp>
24 #include <boost/optional.hpp>
25 #include <boost/scoped_ptr.hpp>
26 #include <boost/date_time/posix_time/posix_time.hpp>
27 #include <comma/math/compare.h>
28 #include <snark/sensors/velodyne/db.h>
29 #include <snark/sensors/velodyne/laser_return.h>
30 #include <snark/sensors/velodyne/packet.h>
31 #include <snark/sensors/velodyne/impl/stream_traits.h>
32 #include <snark/sensors/velodyne/impl/get_laser_return.h>
33 
34 namespace snark { namespace velodyne {
35 
37 template < typename S >
38 class stream : public boost::noncopyable
39 {
40  public:
42  stream( S* stream, unsigned int rpm, bool outputInvalid = false, bool outputRaw = false );
43 
45  stream( S* stream, bool outputInvalid = false, bool outputRaw = false );
46 
48  laser_return* read();
49 
52  void skipscan();
53 
55  unsigned int scan() const;
56 
58  void close();
59 
60  private:
61  boost::optional< double > m_angularSpeed;
62  bool m_outputInvalid;
63  bool m_outputRaw;
64  boost::scoped_ptr< S > m_stream;
65  boost::posix_time::ptime m_timestamp;
66  const packet* m_packet;
67  enum { m_size = 12 * 32 };
68  struct index // quick and dirty
69  {
70  unsigned int idx;
71  unsigned int block;
72  unsigned int laser;
73  index() : idx( 0 ), block( 0 ), laser( 0 ) {}
74  const index& operator++()
75  {
76  ++idx;
77  if( block & 0x1 )
78  {
79  ++laser;
80  if( laser < 32 ) { --block; } else { laser = 0; ++block; }
81  }
82  else
83  {
84  ++block;
85  }
86  return *this;
87  }
88  bool operator==( const index& rhs ) const { return idx == rhs.idx; }
89  };
90  index m_index;
91  unsigned int m_scan;
92  unsigned int m_count;
93  bool m_closed;
94  laser_return m_laserReturn;
95  double angularSpeed();
96 };
97 
98 template < typename S >
99 inline stream< S >::stream( S* stream, unsigned int rpm, bool outputInvalid, bool outputRaw )
100  : m_angularSpeed( ( 360 / 60 ) * rpm )
101  , m_outputInvalid( outputInvalid )
102  , m_outputRaw( outputRaw )
103  , m_stream( stream )
104  , m_scan( 0 )
105  , m_count( 0 )
106  , m_closed( false )
107 {
108  m_index.idx = m_size;
109 }
110 
111 template < typename S >
112 inline stream< S >::stream( S* stream, bool outputInvalid, bool outputRaw )
113  : m_outputInvalid( outputInvalid )
114  , m_outputRaw( outputRaw )
115  , m_stream( stream )
116  , m_scan( 0 )
117  , m_count( 0 )
118  , m_closed( false )
119 {
120  m_index.idx = m_size;
121 }
122 
123 template < typename S >
124 inline double stream< S >::angularSpeed()
125 {
126  if( m_angularSpeed ) { return *m_angularSpeed; }
127  double da = double( m_packet->blocks[0].rotation() - m_packet->blocks[11].rotation() ) / 100;
128  double dt = double( ( impl::time_offset( 0, 0 ) - impl::time_offset( 11, 0 ) ).total_microseconds() ) / 1e6;
129  return da / dt;
130 }
131 
132 template < typename S >
134 {
135  while( !m_closed )
136  {
137  if( m_index.idx >= m_size )
138  {
139  m_index = index();
140  m_packet = reinterpret_cast< const packet* >( impl::stream_traits< S >::read( *m_stream, sizeof( packet ) ) );
141  if( m_packet == NULL ) { return NULL; }
142  m_timestamp = impl::stream_traits< S >::timestamp( *m_stream );
143  // velodyne status spin counter does not work: if( m_packet->status.as< status::version >().valid() ) { m_scan = m_packet->status.as< status::version >().counter(); }
144  ++m_count;
145  }
146  // todo: scan number will be slightly different, depending on m_outputRaw value
147  m_laserReturn = impl::getlaser_return( *m_packet, m_index.block, m_index.laser, m_timestamp, angularSpeed(), m_outputRaw );
148  ++m_index;
149  bool valid = !comma::math::equal( m_laserReturn.range, 0 );
150  if( m_count > 100 && valid && m_laserReturn.azimuth < 5 ) { ++m_scan; m_count = 0; } // quick and dirty
151  if( valid || m_outputInvalid ) { return &m_laserReturn; }
152  }
153  return NULL;
154 }
155 
156 template < typename S >
157 inline unsigned int stream< S >::scan() const { return m_scan; }
158 
159 template < typename S >
160 inline void stream< S >::close() { m_closed = true; impl::stream_traits< S >::close( *m_stream ); }
161 
162 template < typename S >
163 inline void stream< S >::skipscan() // todo: reuse the code of read() better; test as well...
164 {
165  while( !m_closed )
166  {
167  m_index = index();
168  m_packet = reinterpret_cast< const packet* >( impl::stream_traits< S >::read( *m_stream, sizeof( packet ) ) );
169  if( m_packet == NULL ) { return; }
170  m_timestamp = impl::stream_traits< S >::timestamp( *m_stream );
171  // velodyne status spin counter does not work: if( m_packet->status.as< status::version >().valid() ) { m_scan = m_packet->status.as< status::version >().counter(); }
172  ++m_count;
173  if( m_count < 100 ) { continue; }
174  while( m_index.idx < m_size )
175  {
176  m_laserReturn = impl::getlaser_return( *m_packet, m_index.block, m_index.laser, m_timestamp, angularSpeed(), m_outputRaw );
177  ++m_index;
178  if( comma::math::equal( m_laserReturn.range, 0 ) ) { continue; }
179  if( m_laserReturn.azimuth > 5 ) { break; }
180  m_count = 0;
181  ++m_scan;
182  m_index = index();
183  return;
184  }
185  }
186 }
187 
188 } } // namespace snark { namespace velodyne {
189 
190 #endif /*SNARK_SENSORS_VELODYNE_STREAM_H_*/