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 * // Optional: Set the initial tilt angle of Kinect: upon initialization, the motor is sent a command to 00184 * // rotate to this angle (in degrees). Note: You must be aware of the tilt when interpreting the sensor readings. 00185 * initial_tilt_angle = 0 00186 * 00187 * \endcode 00188 * 00189 * More references to read: 00190 * - http://openkinect.org/wiki/Imaging_Information 00191 * - http://nicolas.burrus.name/index.php/Research/KinectCalibration 00192 * \ingroup mrpt_hwdrivers_grp 00193 */ 00194 class HWDRIVERS_IMPEXP CKinect : public mrpt::hwdrivers::CGenericSensor 00195 { 00196 DEFINE_GENERIC_SENSOR(CKinect) 00197 00198 public: 00199 typedef float TDepth2RangeArray[KINECT_RANGES_TABLE_LEN]; //!< A typedef for an array that converts raw depth to ranges in meters. 00200 00201 /** RGB or IR video channel identifiers \sa setVideoChannel */ 00202 enum TVideoChannel { 00203 VIDEO_CHANNEL_RGB=0, 00204 VIDEO_CHANNEL_IR 00205 }; 00206 00207 CKinect(); //!< Default ctor 00208 ~CKinect(); //!< Default ctor 00209 00210 /** Initializes the 3D camera - should be invoked after calling loadConfig() or setting the different parameters with the set*() methods. 00211 * \exception This method must throw an exception with a descriptive message if some critical error is found. 00212 */ 00213 virtual void initialize(); 00214 00215 /** To be called at a high rate (>XX Hz), this method populates the internal buffer of received observations. 00216 * This method is mainly intended for usage within rawlog-grabber or similar programs. 00217 * For an alternative, see getNextObservation() 00218 * \exception This method must throw an exception with a descriptive message if some critical error is found. 00219 * \sa getNextObservation 00220 */ 00221 virtual void doProcess(); 00222 00223 /** The main data retrieving function, to be called after calling loadConfig() and initialize(). 00224 * \param out_obs The output retrieved observation (only if there_is_obs=true). 00225 * \param there_is_obs If set to false, there was no new observation. 00226 * \param hardware_error True on hardware/comms error. 00227 * 00228 * \sa doProcess 00229 */ 00230 void getNextObservation( 00231 mrpt::slam::CObservation3DRangeScan &out_obs, 00232 bool &there_is_obs, 00233 bool &hardware_error ); 00234 00235 /** \overload 00236 * \note This method also grabs data from the accelerometers, returning them in out_obs_imu 00237 */ 00238 void getNextObservation( 00239 mrpt::slam::CObservation3DRangeScan &out_obs, 00240 mrpt::slam::CObservationIMU &out_obs_imu, 00241 bool &there_is_obs, 00242 bool &hardware_error ); 00243 00244 /** Set the path where to save off-rawlog image files (this class DOES take into account this path). 00245 * An empty string (the default value at construction) means to save images embedded in the rawlog, instead of on separate files. 00246 * \exception std::exception If the directory doesn't exists and cannot be created. 00247 */ 00248 virtual void setPathForExternalImages( const std::string &directory ); 00249 00250 00251 /** @name Sensor parameters (alternative to \a loadConfig ) and manual control 00252 @{ */ 00253 00254 /** Try to open the camera (set all the parameters before calling this) - users may also call initialize(), which in turn calls this method. 00255 * Raises an exception upon error. 00256 * \exception std::exception A textual description of the error. 00257 */ 00258 void open(); 00259 00260 bool isOpen() const; //!< Whether there is a working connection to the sensor 00261 00262 /** Close the conection to the sensor (not need to call it manually unless desired for some reason, 00263 * since it's called at destructor) */ 00264 void close(); 00265 00266 /** 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. 00267 Default is RGB channel. */ 00268 void setVideoChannel(const TVideoChannel vch); 00269 /** Return the current video channel (RGB or IR) \sa setVideoChannel */ 00270 inline TVideoChannel getVideoChannel() const { return m_video_channel; } 00271 00272 /** Set the sensor index to open (if there're several sensors attached to the computer); default=0 -> the first one. */ 00273 inline void setDeviceIndexToOpen(int index) { m_user_device_number=index; } 00274 inline int getDeviceIndexToOpen() const { return m_user_device_number; } 00275 00276 /** Change tilt angle \note Sensor must be open first. */ 00277 void setTiltAngleDegrees(double angle); 00278 double getTiltAngleDegrees(); 00279 00280 /** Default: disabled */ 00281 inline void enablePreviewRGB(bool enable=true) { m_preview_window = enable; } 00282 inline void disablePreviewRGB() { m_preview_window = false; } 00283 inline bool isPreviewRGBEnabled() const { return m_preview_window; } 00284 00285 /** If preview is enabled, show only one image out of N (default: 1=show all) */ 00286 inline void setPreviewDecimation(size_t decimation_factor ) { m_preview_window_decimation = decimation_factor; } 00287 inline size_t getPreviewDecimation() const { return m_preview_window_decimation; } 00288 00289 /** Get the maximum range (meters) that can be read in the observation field "rangeImage" */ 00290 inline double getMaxRange() const { return m_maxRange; } 00291 00292 /** Get the row count in the camera images, loaded automatically upon camera open(). */ 00293 inline size_t getRowCount() const { return m_cameraParamsRGB.nrows; } 00294 /** Get the col count in the camera images, loaded automatically upon camera open(). */ 00295 inline size_t getColCount() const { return m_cameraParamsRGB.ncols; } 00296 00297 /** Get a const reference to the depth camera calibration parameters */ 00298 inline const mrpt::utils::TCamera & getCameraParamsIntensity() const { return m_cameraParamsRGB; } 00299 inline void setCameraParamsIntensity(const mrpt::utils::TCamera &p) { m_cameraParamsRGB=p; } 00300 00301 /** Get a const reference to the depth camera calibration parameters */ 00302 inline const mrpt::utils::TCamera & getCameraParamsDepth() const { return m_cameraParamsDepth; } 00303 inline void setCameraParamsDepth(const mrpt::utils::TCamera &p) { m_cameraParamsDepth=p; } 00304 00305 /** Set the pose of the intensity camera wrt the depth camera \sa See mrpt::slam::CObservation3DRangeScan for a 3D diagram of this pose */ 00306 inline void setRelativePoseIntensityWrtDepth(const mrpt::poses::CPose3D &p) { m_relativePoseIntensityWRTDepth=p; } 00307 inline const mrpt::poses::CPose3D &getRelativePoseIntensityWrtDepth() const { return m_relativePoseIntensityWRTDepth; } 00308 00309 /** 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. 00310 * 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. 00311 */ 00312 inline TDepth2RangeArray & getRawDepth2RangeConversion() { return m_range2meters; } 00313 inline const TDepth2RangeArray & getRawDepth2RangeConversion() const { return m_range2meters; } 00314 00315 /** Enable/disable the grabbing of the RGB channel */ 00316 inline void enableGrabRGB(bool enable=true) { m_grab_image=enable; } 00317 inline bool isGrabRGBEnabled() const { return m_grab_image; } 00318 00319 /** Enable/disable the grabbing of the depth channel */ 00320 inline void enableGrabDepth(bool enable=true) { m_grab_depth=enable; } 00321 inline bool isGrabDepthEnabled() const { return m_grab_depth; } 00322 00323 /** Enable/disable the grabbing of the inertial data */ 00324 inline void enableGrabAccelerometers(bool enable=true) { m_grab_IMU=enable; } 00325 inline bool isGrabAccelerometersEnabled() const { return m_grab_IMU; } 00326 00327 /** Enable/disable the grabbing of the 3D point clouds */ 00328 inline void enableGrab3DPoints(bool enable=true) { m_grab_3D_points=enable; } 00329 inline bool isGrab3DPointsEnabled() const { return m_grab_3D_points; } 00330 00331 /** @} */ 00332 00333 00334 #if MRPT_HAS_KINECT_FREENECT 00335 // Auxiliary getters/setters (we can't declare the libfreenect callback as friend since we 00336 // want to avoid including the API headers here). 00337 inline mrpt::slam::CObservation3DRangeScan & internal_latest_obs() { return m_latest_obs; } 00338 inline volatile uint32_t & internal_tim_latest_depth() { return m_tim_latest_depth; } 00339 inline volatile uint32_t & internal_tim_latest_rgb() { return m_tim_latest_rgb; } 00340 inline mrpt::synch::CCriticalSection & internal_latest_obs_cs() { return m_latest_obs_cs; } 00341 #endif 00342 00343 protected: 00344 /** 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) 00345 * \exception This method must throw an exception with a descriptive message if some critical parameter is missing or has an invalid value. 00346 */ 00347 virtual void loadConfig_sensorSpecific( 00348 const mrpt::utils::CConfigFileBase &configSource, 00349 const std::string §ion ); 00350 00351 mrpt::poses::CPose3D m_sensorPoseOnRobot; 00352 00353 bool m_preview_window; //!< Show preview window while grabbing 00354 size_t m_preview_window_decimation; //!< If preview is enabled, only show 1 out of N images. 00355 size_t m_preview_decim_counter_range, m_preview_decim_counter_rgb; 00356 mrpt::gui::CDisplayWindowPtr m_win_range, m_win_int; 00357 00358 #if MRPT_HAS_KINECT_FREENECT 00359 void *m_f_ctx; //!< The "freenect_context", or NULL if closed 00360 void *m_f_dev; //!< The "freenect_device", or NULL if closed 00361 00362 // Data fields for use with the callback function: 00363 mrpt::slam::CObservation3DRangeScan m_latest_obs; 00364 volatile uint32_t m_tim_latest_depth, m_tim_latest_rgb; // 0 = not updated 00365 mrpt::synch::CCriticalSection m_latest_obs_cs; 00366 #endif 00367 00368 #if MRPT_HAS_KINECT_CL_NUI 00369 void *m_clnui_cam; //!< The "CLNUICamera" or NULL if closed 00370 void *m_clnui_motor; //!< The "CLNUIMotor" or NULL if closed 00371 #endif 00372 00373 mrpt::utils::TCamera m_cameraParamsRGB; //!< Params for the RGB camera 00374 mrpt::utils::TCamera m_cameraParamsDepth; //!< Params for the Depth camera 00375 mrpt::poses::CPose3D m_relativePoseIntensityWRTDepth; //!< See mrpt::slam::CObservation3DRangeScan for a diagram of this pose 00376 00377 int m_initial_tilt_angle; //!< Set Kinect tilt to an initial deegre (it should be take in account in the sensor pose by the user) 00378 00379 double m_maxRange; //!< Sensor max range (meters) 00380 00381 int m_user_device_number; //!< Number of device to open (0:first,...) 00382 00383 bool m_grab_image, m_grab_depth, m_grab_3D_points, m_grab_IMU ; //!< Default: all true 00384 00385 TVideoChannel m_video_channel; //!< The video channel to open: RGB or IR 00386 00387 private: 00388 std::vector<uint8_t> m_buf_depth, m_buf_rgb; //!< Temporary buffers for image grabbing. 00389 TDepth2RangeArray m_range2meters; //!< The table raw depth -> range in meters 00390 00391 void calculate_range2meters(); //!< Compute m_range2meters at construction 00392 00393 public: 00394 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 00395 00396 }; // End of class 00397 } // End of NS 00398 00399 // Specializations MUST occur at the same namespace: 00400 namespace utils 00401 { 00402 template <> 00403 struct TEnumTypeFiller<hwdrivers::CKinect::TVideoChannel> 00404 { 00405 typedef hwdrivers::CKinect::TVideoChannel enum_t; 00406 static void fill(bimap<enum_t,std::string> &m_map) 00407 { 00408 m_map.insert(hwdrivers::CKinect::VIDEO_CHANNEL_RGB, "VIDEO_CHANNEL_RGB"); 00409 m_map.insert(hwdrivers::CKinect::VIDEO_CHANNEL_IR, "VIDEO_CHANNEL_IR"); 00410 } 00411 }; 00412 } // End of namespace 00413 00414 } // End of NS 00415 00416 00417 #endif
| Page generated by Doxygen 1.7.4 for MRPT 0.9.5 SVN:2717 at Sun Oct 16 16:08:03 PDT 2011 | Hosted on: |