00001 /* +---------------------------------------------------------------------------+ 00002 | The Mobile Robot Programming Toolkit (MRPT) C++ library | 00003 | | 00004 | http://www.mrpt.org/ | 00005 | | 00006 | Copyright (C) 2005-2011 University of Malaga | 00007 | | 00008 | This software was written by the Machine Perception and Intelligent | 00009 | Robotics Lab, University of Malaga (Spain). | 00010 | Contact: Jose-Luis Blanco <jlblanco@ctima.uma.es> | 00011 | | 00012 | This file is part of the MRPT project. | 00013 | | 00014 | MRPT is free software: you can redistribute it and/or modify | 00015 | it under the terms of the GNU General Public License as published by | 00016 | the Free Software Foundation, either version 3 of the License, or | 00017 | (at your option) any later version. | 00018 | | 00019 | MRPT is distributed in the hope that it will be useful, | 00020 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 00021 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 00022 | GNU General Public License for more details. | 00023 | | 00024 | You should have received a copy of the GNU General Public License | 00025 | along with MRPT. If not, see <http://www.gnu.org/licenses/>. | 00026 | | 00027 +---------------------------------------------------------------------------+ */ 00028 #ifndef mrpt_CKinect_H 00029 #define mrpt_CKinect_H 00030 00031 #include <mrpt/hwdrivers/CGenericSensor.h> 00032 #include <mrpt/slam/CObservation3DRangeScan.h> 00033 #include <mrpt/slam/CObservationIMU.h> 00034 #include <mrpt/utils/TEnumType.h> 00035 #include <mrpt/gui/CDisplayWindow.h> 00036 00037 #include <mrpt/hwdrivers/link_pragmas.h> 00038 00039 // MRPT implements a common interface to Kinect disregarding the 00040 // actual underlying library. These macros defined in "mrpt/config.h" 00041 // let us know which library is actually used: 00042 // - MRPT_HAS_KINECT_CL_NUI = 0 or 1 00043 // - MRPT_HAS_KINECT_FREENECT = 0 or 1 00044 00045 // Depth of Kinect ranges: 00046 #if MRPT_HAS_KINECT_FREENECT 00047 # define MRPT_KINECT_DEPTH_10BIT 00048 # define KINECT_RANGES_TABLE_LEN 1024 00049 # define KINECT_RANGES_TABLE_MASK 0x03FF 00050 #else // MRPT_HAS_KINECT_CL_NUI or none: 00051 # define MRPT_KINECT_DEPTH_11BIT 00052 # define KINECT_RANGES_TABLE_LEN 2048 00053 # define KINECT_RANGES_TABLE_MASK 0x07FF 00054 #endif 00055 00056 00057 namespace mrpt 00058 { 00059 namespace hwdrivers 00060 { 00061 /** A class for grabing "range images", intensity images (either RGB or IR) and other information from an Xbox Kinect sensor. 00062 * 00063 * <h2>Configuration and usage:</h2> <hr> 00064 * Data is returned as observations of type mrpt::slam::CObservation3DRangeScan (and mrpt::slam::CObservationIMU for accelerometers data). 00065 * See those classes for documentation on their fields. 00066 * 00067 * As with any other CGenericSensor class, the normal sequence of methods to be called is: 00068 * - CGenericSensor::loadConfig() - Or calls to the individual setXXX() to configure the sensor parameters. 00069 * - CKinect::initialize() - to start the communication with the sensor. 00070 * - call CKinect::getNextObservation() for getting the data. 00071 * 00072 * <h2>Calibration parameters</h2><hr> 00073 * For an accurate transformation of depth images to 3D points, you'll have to calibrate your Kinect, and supply 00074 * the following <b>threee pieces of information</b> (default calibration data will be used otherwise, but they'll be not optimal for all sensors!): 00075 * - Camera parameters for the RGB camera. See CKinect::setCameraParamsIntensity() 00076 * - Camera parameters for the depth camera. See CKinect::setCameraParamsDepth() 00077 * - The 3D relative pose of the two cameras. See CKinect::setRelativePoseIntensityWrtDepth() 00078 * 00079 * <h2>Coordinates convention</h2><hr> 00080 * The origin of coordinates is the focal point of the depth camera, with the axes oriented as in the 00081 * diagram shown in mrpt::slam::CObservation3DRangeScan. Notice in that picture that the RGB camera is 00082 * assumed to have axes as usual in computer vision, which differ from those for the depth camera. 00083 * 00084 * The X,Y,Z axes used to report the data from accelerometers coincide with those of the depth camera 00085 * (e.g. the camera standing on a table would have an ACC_Z=-9.8m/s2). 00086 * 00087 * <h2>Some general comments</h2><hr> 00088 * - Depth is grabbed in 10bit depth, and a range N it's converted to meters as: range(m) = 0.1236 * tan(N/2842.5 + 1.1863) 00089 * - This sensor can be also used from within rawlog-grabber to grab datasets within a robot with more sensors. 00090 * - There is no built-in threading support, so if you use this class manually (not with-in rawlog-grabber), 00091 * the ideal would be to create a thread and continuously request data from that thread (see mrpt::system::createThread ). 00092 * - The intensity channel default to the RGB images, but it can be changed with setVideoChannel() to read the IR camera images (useful for calibrating). 00093 * - There is a built-in support for an optional preview of the data on a window, so you don't need to even worry on creating a window to show them. 00094 * - This class relies on an embedded version of libfreenect (you do NOT need to install it in your system). Thanks guys for the great job! 00095 * 00096 * <h2>Converting to 3D point cloud </h2><hr> 00097 * You can convert the 3D observation into a 3D point cloud with this piece of code: 00098 * 00099 * \code 00100 * mrpt::slam::CObservation3DRangeScan obs3D; 00101 * mrpt::slam::CColouredPointsMap pntsMap; 00102 * pntsMap.colorScheme.scheme = CColouredPointsMap::cmFromIntensityImage; 00103 * pntsMap.loadFromRangeScan(obs3D); 00104 * \endcode 00105 * 00106 * Then the point cloud mrpt::slam::CColouredPointsMap can be converted into an OpenGL object for 00107 * rendering with mrpt::slam::CMetricMap::getAs3DObject() or alternatively with: 00108 * 00109 * \code 00110 * mrpt::opengl::CPointCloudColouredPtr gl_points = mrpt::opengl::CPointCloudColoured::Create(); 00111 * gl_points->loadFromPointsMap(&pntsMap); 00112 * \endcode 00113 * 00114 * 00115 * <h2>Raw depth to range conversion</h2><hr> 00116 * At construction, this class builds an internal array for converting raw 10 or 11bit depths into ranges in meters. 00117 * Users can read that array or modify it (if you have a better calibration, for example) by calling CKinect::getRawDepth2RangeConversion(). 00118 * If you replace it, remember to set the first and last entries (index 0 and KINECT_RANGES_TABLE_LEN-1) to zero, to indicate that those are invalid ranges. 00119 * 00120 * <table width="100%" > 00121 * <tr> 00122 * <td align="center" > 00123 * <img src="kinect_depth2range_10bit.png" > <br> 00124 * R(d) = k3 * tan(d/k2 + k1); <br> 00125 * k1 = 1.1863, k2 = 2842.5, k3 = 0.1236 <br> 00126 * </td> 00127 * <td align="center" > 00128 * </td> 00129 * </tr> 00130 * </table> 00131 * 00132 * 00133 * <h2>Platform-specific comments</h2><hr> 00134 * For more details, refer to <a href="http://openkinect.org/wiki/Main_Page" >libfreenect</a> documentation: 00135 * - Linux: You'll need root privileges to access Kinect. Or, install <code> MRPT/scripts/51-kinect.rules </code> in <code>/etc/udev/rules.d/</code> to allow access to all users. 00136 * - Windows: 00137 * - Since MRPT 0.9.4 you'll only need to install <a href="http://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/" >libusb-win32</a>: download and extract the latest libusb-win32-bin-x.x.x.x.zip 00138 * - To install the drivers, read this: http://openkinect.org/wiki/Getting_Started#Windows 00139 * - MacOS: (write me!) 00140 * 00141 * 00142 * <h2>Format of parameters for loading from a .ini file</h2><hr> 00143 * 00144 * \code 00145 * PARAMETERS IN THE ".INI"-LIKE CONFIGURATION STRINGS: 00146 * ------------------------------------------------------- 00147 * [supplied_section_name] 00148 * sensorLabel = KINECT // A text description 00149 * preview_window = false // Show a window with a preview of the grabbed data in real-time 00150 * 00151 * device_number = 0 // Device index to open (0:first Kinect, 1:second Kinect,...) 00152 * 00153 * grab_image = true // Grab the RGB image channel? (Default=true) 00154 * grab_depth = true // Grab the depth channel? (Default=true) 00155 * grab_3D_points = true // Grab the 3D point cloud? (Default=true) If disabled, points can be generated later on. 00156 * grab_IMU = true // Grab the accelerometers? (Default=true) 00157 * 00158 * video_channel = VIDEO_CHANNEL_RGB // Optional. Can be: VIDEO_CHANNEL_RGB (default) or VIDEO_CHANNEL_IR 00159 * 00160 * // Calibration matrix of the RGB camera: 00161 * rgb_cx = 328.9427 // (cx,cy): Optical center, pixels 00162 * rgb_cy = 267.4807 00163 * rgb_fx = 529.2151 // (fx,fy): Focal distance, pixels 00164 * rgb_fy = 525.5639 00165 * 00166 * // Calibration matrix of the Depth camera: 00167 * d_cx = 339.3078 // (cx,cy): Optical center, pixels 00168 * d_cy = 242.7391 00169 * d_fx = 594.2143 // (fx,fy): Focal distance, pixels 00170 * d_fy = 591.0405 00171 * 00172 * // The relative pose of the RGB camera wrt the depth camera. 00173 * // (See mrpt::slam::CObservation3DRangeScan for a 3D diagram of this pose) 00174 * relativePoseIntensityWRTDepth = [0 -0.02 0 -90 0 -90] // [x(m) y(m) z(m) yaw(deg) pitch(deg) roll(deg)] 00175 * 00176 * pose_x=0 // Camera position in the robot (meters) 00177 * pose_y=0 00178 * pose_z=0 00179 * pose_yaw=0 // Angles in degrees 00180 * pose_pitch=0 00181 * pose_roll=0 00182 * 00183 * \endcode 00184 * 00185 * More references to read: 00186 * - http://openkinect.org/wiki/Imaging_Information 00187 * - http://nicolas.burrus.name/index.php/Research/KinectCalibration 00188 * \ingroup mrpt_hwdrivers_grp 00189 */ 00190 class HWDRIVERS_IMPEXP CKinect : public mrpt::hwdrivers::CGenericSensor 00191 { 00192 DEFINE_GENERIC_SENSOR(CKinect) 00193 00194 public: 00195 typedef float TDepth2RangeArray[KINECT_RANGES_TABLE_LEN]; //!< A typedef for an array that converts raw depth to ranges in meters. 00196 00197 /** RGB or IR video channel identifiers \sa setVideoChannel */ 00198 enum TVideoChannel { 00199 VIDEO_CHANNEL_RGB=0, 00200 VIDEO_CHANNEL_IR 00201 }; 00202 00203 CKinect(); //!< Default ctor 00204 ~CKinect(); //!< Default ctor 00205 00206 /** Initializes the 3D camera - should be invoked after calling loadConfig() or setting the different parameters with the set*() methods. 00207 * \exception This method must throw an exception with a descriptive message if some critical error is found. 00208 */ 00209 virtual void initialize(); 00210 00211 /** To be called at a high rate (>XX Hz), this method populates the internal buffer of received observations. 00212 * This method is mainly intended for usage within rawlog-grabber or similar programs. 00213 * For an alternative, see getNextObservation() 00214 * \exception This method must throw an exception with a descriptive message if some critical error is found. 00215 * \sa getNextObservation 00216 */ 00217 virtual void doProcess(); 00218 00219 /** The main data retrieving function, to be called after calling loadConfig() and initialize(). 00220 * \param out_obs The output retrieved observation (only if there_is_obs=true). 00221 * \param there_is_obs If set to false, there was no new observation. 00222 * \param hardware_error True on hardware/comms error. 00223 * 00224 * \sa doProcess 00225 */ 00226 void getNextObservation( 00227 mrpt::slam::CObservation3DRangeScan &out_obs, 00228 bool &there_is_obs, 00229 bool &hardware_error ); 00230 00231 /** \overload 00232 * \note This method also grabs data from the accelerometers, returning them in out_obs_imu 00233 */ 00234 void getNextObservation( 00235 mrpt::slam::CObservation3DRangeScan &out_obs, 00236 mrpt::slam::CObservationIMU &out_obs_imu, 00237 bool &there_is_obs, 00238 bool &hardware_error ); 00239 00240 /** Set the path where to save off-rawlog image files (this class DOES take into account this path). 00241 * An empty string (the default value at construction) means to save images embedded in the rawlog, instead of on separate files. 00242 * \exception std::exception If the directory doesn't exists and cannot be created. 00243 */ 00244 virtual void setPathForExternalImages( const std::string &directory ); 00245 00246 00247 /** @name Sensor parameters (alternative to \a loadConfig ) and manual control 00248 @{ */ 00249 00250 /** Try to open the camera (set all the parameters before calling this) - users may also call initialize(), which in turn calls this method. 00251 * Raises an exception upon error. 00252 * \exception std::exception A textual description of the error. 00253 */ 00254 void open(); 00255 00256 bool isOpen() const; //!< Whether there is a working connection to the sensor 00257 00258 /** Close the conection to the sensor (not need to call it manually unless desired for some reason, 00259 * since it's called at destructor) */ 00260 void close(); 00261 00262 /** Changes the video channel to open (RGB or IR) - you can call this method before start grabbing or in the middle of streaming and the video source will change on the fly. 00263 Default is RGB channel. */ 00264 void setVideoChannel(const TVideoChannel vch); 00265 /** Return the current video channel (RGB or IR) \sa setVideoChannel */ 00266 inline TVideoChannel getVideoChannel() const { return m_video_channel; } 00267 00268 /** Set the sensor index to open (if there're several sensors attached to the computer); default=0 -> the first one. */ 00269 inline void setDeviceIndexToOpen(int index) { m_user_device_number=index; } 00270 inline int getDeviceIndexToOpen() const { return m_user_device_number; } 00271 00272 /** Change tilt angle \note Sensor must be open first. */ 00273 void setTiltAngleDegrees(double angle); 00274 double getTiltAngleDegrees(); 00275 00276 /** Default: disabled */ 00277 inline void enablePreviewRGB(bool enable=true) { m_preview_window = enable; } 00278 inline void disablePreviewRGB() { m_preview_window = false; } 00279 inline bool isPreviewRGBEnabled() const { return m_preview_window; } 00280 00281 /** If preview is enabled, show only one image out of N (default: 1=show all) */ 00282 inline void setPreviewDecimation(size_t decimation_factor ) { m_preview_window_decimation = decimation_factor; } 00283 inline size_t getPreviewDecimation() const { return m_preview_window_decimation; } 00284 00285 /** Get the maximum range (meters) that can be read in the observation field "rangeImage" */ 00286 inline double getMaxRange() const { return m_maxRange; } 00287 00288 /** Get the row count in the camera images, loaded automatically upon camera open(). */ 00289 inline size_t getRowCount() const { return m_cameraParamsRGB.nrows; } 00290 /** Get the col count in the camera images, loaded automatically upon camera open(). */ 00291 inline size_t getColCount() const { return m_cameraParamsRGB.ncols; } 00292 00293 /** Get a const reference to the depth camera calibration parameters */ 00294 inline const mrpt::utils::TCamera & getCameraParamsIntensity() const { return m_cameraParamsRGB; } 00295 inline void setCameraParamsIntensity(const mrpt::utils::TCamera &p) { m_cameraParamsRGB=p; } 00296 00297 /** Get a const reference to the depth camera calibration parameters */ 00298 inline const mrpt::utils::TCamera & getCameraParamsDepth() const { return m_cameraParamsDepth; } 00299 inline void setCameraParamsDepth(const mrpt::utils::TCamera &p) { m_cameraParamsDepth=p; } 00300 00301 /** Set the pose of the intensity camera wrt the depth camera \sa See mrpt::slam::CObservation3DRangeScan for a 3D diagram of this pose */ 00302 inline void setRelativePoseIntensityWrtDepth(const mrpt::poses::CPose3D &p) { m_relativePoseIntensityWRTDepth=p; } 00303 inline const mrpt::poses::CPose3D &getRelativePoseIntensityWrtDepth() const { return m_relativePoseIntensityWRTDepth; } 00304 00305 /** Get a reference to the array that convert raw depth values (10 or 11 bit) into ranges in meters, so it can be read or replaced by the user. 00306 * If you replace it, remember to set the first and last entries (index 0 and KINECT_RANGES_TABLE_LEN-1) to zero, to indicate that those are invalid ranges. 00307 */ 00308 inline TDepth2RangeArray & getRawDepth2RangeConversion() { return m_range2meters; } 00309 inline const TDepth2RangeArray & getRawDepth2RangeConversion() const { return m_range2meters; } 00310 00311 /** Enable/disable the grabbing of the RGB channel */ 00312 inline void enableGrabRGB(bool enable=true) { m_grab_image=enable; } 00313 inline bool isGrabRGBEnabled() const { return m_grab_image; } 00314 00315 /** Enable/disable the grabbing of the depth channel */ 00316 inline void enableGrabDepth(bool enable=true) { m_grab_depth=enable; } 00317 inline bool isGrabDepthEnabled() const { return m_grab_depth; } 00318 00319 /** Enable/disable the grabbing of the inertial data */ 00320 inline void enableGrabAccelerometers(bool enable=true) { m_grab_IMU=enable; } 00321 inline bool isGrabAccelerometersEnabled() const { return m_grab_IMU; } 00322 00323 /** Enable/disable the grabbing of the 3D point clouds */ 00324 inline void enableGrab3DPoints(bool enable=true) { m_grab_3D_points=enable; } 00325 inline bool isGrab3DPointsEnabled() const { return m_grab_3D_points; } 00326 00327 /** @} */ 00328 00329 00330 #if MRPT_HAS_KINECT_FREENECT 00331 // Auxiliary getters/setters (we can't declare the libfreenect callback as friend since we 00332 // want to avoid including the API headers here). 00333 inline mrpt::slam::CObservation3DRangeScan & internal_latest_obs() { return m_latest_obs; } 00334 inline volatile uint32_t & internal_tim_latest_depth() { return m_tim_latest_depth; } 00335 inline volatile uint32_t & internal_tim_latest_rgb() { return m_tim_latest_rgb; } 00336 inline mrpt::synch::CCriticalSection & internal_latest_obs_cs() { return m_latest_obs_cs; } 00337 #endif 00338 00339 protected: 00340 /** Loads specific configuration for the device from a given source of configuration parameters, for example, an ".ini" file, loading from the section "[iniSection]" (see utils::CConfigFileBase and derived classes) 00341 * \exception This method must throw an exception with a descriptive message if some critical parameter is missing or has an invalid value. 00342 */ 00343 virtual void loadConfig_sensorSpecific( 00344 const mrpt::utils::CConfigFileBase &configSource, 00345 const std::string §ion ); 00346 00347 mrpt::poses::CPose3D m_sensorPoseOnRobot; 00348 00349 bool m_preview_window; //!< Show preview window while grabbing 00350 size_t m_preview_window_decimation; //!< If preview is enabled, only show 1 out of N images. 00351 size_t m_preview_decim_counter_range, m_preview_decim_counter_rgb; 00352 mrpt::gui::CDisplayWindowPtr m_win_range, m_win_int; 00353 00354 #if MRPT_HAS_KINECT_FREENECT 00355 void *m_f_ctx; //!< The "freenect_context", or NULL if closed 00356 void *m_f_dev; //!< The "freenect_device", or NULL if closed 00357 00358 // Data fields for use with the callback function: 00359 mrpt::slam::CObservation3DRangeScan m_latest_obs; 00360 volatile uint32_t m_tim_latest_depth, m_tim_latest_rgb; // 0 = not updated 00361 mrpt::synch::CCriticalSection m_latest_obs_cs; 00362 #endif 00363 00364 #if MRPT_HAS_KINECT_CL_NUI 00365 void *m_clnui_cam; //!< The "CLNUICamera" or NULL if closed 00366 void *m_clnui_motor; //!< The "CLNUIMotor" or NULL if closed 00367 #endif 00368 00369 mrpt::utils::TCamera m_cameraParamsRGB; //!< Params for the RGB camera 00370 mrpt::utils::TCamera m_cameraParamsDepth; //!< Params for the Depth camera 00371 mrpt::poses::CPose3D m_relativePoseIntensityWRTDepth; //!< See mrpt::slam::CObservation3DRangeScan for a diagram of this pose 00372 00373 double m_maxRange; //!< Sensor max range (meters) 00374 00375 int m_user_device_number; //!< Number of device to open (0:first,...) 00376 00377 bool m_grab_image, m_grab_depth, m_grab_3D_points, m_grab_IMU ; //!< Default: all true 00378 00379 TVideoChannel m_video_channel; //!< The video channel to open: RGB or IR 00380 00381 private: 00382 std::vector<uint8_t> m_buf_depth, m_buf_rgb; //!< Temporary buffers for image grabbing. 00383 TDepth2RangeArray m_range2meters; //!< The table raw depth -> range in meters 00384 00385 void calculate_range2meters(); //!< Compute m_range2meters at construction 00386 00387 public: 00388 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 00389 00390 }; // End of class 00391 } // End of NS 00392 00393 // Specializations MUST occur at the same namespace: 00394 namespace utils 00395 { 00396 template <> 00397 struct TEnumTypeFiller<hwdrivers::CKinect::TVideoChannel> 00398 { 00399 typedef hwdrivers::CKinect::TVideoChannel enum_t; 00400 static void fill(bimap<enum_t,std::string> &m_map) 00401 { 00402 m_map.insert(hwdrivers::CKinect::VIDEO_CHANNEL_RGB, "VIDEO_CHANNEL_RGB"); 00403 m_map.insert(hwdrivers::CKinect::VIDEO_CHANNEL_IR, "VIDEO_CHANNEL_IR"); 00404 } 00405 }; 00406 } // End of namespace 00407 00408 } // End of NS 00409 00410 00411 #endif
| Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011 |