SRBA: Sparser Relative Bundle Adjustment
srba/models/sensors.h
00001 /* +---------------------------------------------------------------------------+
00002    |                     Mobile Robot Programming Toolkit (MRPT)               |
00003    |                          http://www.mrpt.org/                             |
00004    |                                                                           |
00005    | Copyright (c) 2005-2015, Individual contributors, see AUTHORS file        |
00006    | See: http://www.mrpt.org/Authors - All rights reserved.                   |
00007    | Released under BSD License. See details in http://www.mrpt.org/License    |
00008    +---------------------------------------------------------------------------+ */
00009 
00010 #pragma once
00011 
00012 #include <mrpt/poses/CPose3DQuat.h>
00013 
00014 namespace srba {
00023     template <>
00024     struct sensor_model<landmarks::Euclidean3D,observations::MonocularCamera>
00025     {
00026         // --------------------------------------------------------------------------------
00027         // Typedefs for the sake of generality in the signature of methods below:
00028         //   *DONT FORGET* to change these when writing new sensor models.
00029         // --------------------------------------------------------------------------------
00030         typedef observations::MonocularCamera  OBS_T;  
00031         typedef landmarks::Euclidean3D         LANDMARK_T;
00032         // --------------------------------------------------------------------------------
00033 
00034         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00035         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00036         
00037         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>  TJacobian_dh_dx;     
00038         typedef landmark_traits<LANDMARK_T>::array_landmark_t    array_landmark_t;             
00039         typedef OBS_T::TObservationParams               TObservationParams;
00040 
00041 
00049         template <class POSE_T>
00050         static void observe_error(
00051             observation_traits<OBS_T>::array_obs_t              & out_obs_err, 
00052             const observation_traits<OBS_T>::array_obs_t        & z_obs, 
00053             const POSE_T                                        & base_pose_wrt_observer,
00054             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00055             const OBS_T::TObservationParams                     & params)
00056         {
00057             double x,y,z; // wrt cam (local coords)
00058             base_pose_wrt_observer.composePoint(lm_pos[0],lm_pos[1],lm_pos[2], x,y,z);
00059             ASSERT_(z!=0)
00060 
00061             // Pinhole model:
00062             observation_traits<OBS_T>::array_obs_t  pred_obs;  // prediction
00063             pred_obs[0] = params.camera_calib.cx() + params.camera_calib.fx() * x/z;
00064             pred_obs[1] = params.camera_calib.cy() + params.camera_calib.fy() * y/z;
00065             out_obs_err = z_obs - pred_obs;
00066         }
00067 
00085         static bool eval_jacob_dh_dx(
00086             TJacobian_dh_dx          & dh_dx,
00087             const array_landmark_t   & xji_l, 
00088             const TObservationParams & sensor_params)
00089         {
00090             // xji_l[0:2]=[X Y Z]
00091             // If the point is behind us, mark this Jacobian as invalid. This is probably a temporary situation until we get closer to the optimum.
00092             if (xji_l[2]<=0)
00093                 return false;
00094 
00095             const double pz_inv = 1.0/xji_l[2];
00096             const double pz_inv2 = pz_inv*pz_inv;
00097 
00098             const double cam_fx = sensor_params.camera_calib.fx();
00099             const double cam_fy = sensor_params.camera_calib.fy();
00100 
00101             dh_dx.coeffRef(0,0)=  cam_fx * pz_inv;
00102             dh_dx.coeffRef(0,1)=  0;
00103             dh_dx.coeffRef(0,2)=  -cam_fx * xji_l[0] * pz_inv2;
00104 
00105             dh_dx.coeffRef(1,0)=  0;
00106             dh_dx.coeffRef(1,1)=  cam_fy * pz_inv;
00107             dh_dx.coeffRef(1,2)=  -cam_fy * xji_l[1] * pz_inv2;
00108 
00109             return true;
00110         }
00111 
00121         static void inverse_sensor_model(
00122             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00123             const observation_traits<OBS_T>::obs_data_t   & obs, 
00124             const OBS_T::TObservationParams               & params)
00125         {
00126             //     > +Z 
00127             //    / 
00128             //   / 
00129             //  +----> +X
00130             //  |
00131             //  |
00132             //  V +Y
00133             //
00134             const double fx = params.camera_calib.fx();
00135             const double fy = params.camera_calib.fy();
00136             const double cx = params.camera_calib.cx();
00137             const double cy = params.camera_calib.cy();
00138             out_lm_pos[0] = (obs.px.x-cx)/fx;
00139             out_lm_pos[1] = (obs.px.y-cy)/fy;
00140             out_lm_pos[2] = 1; // Depth in Z (undefined for monocular cameras, just use any !=0 value)
00141         }
00142 
00143     };  // end of struct sensor_model<landmarks::Euclidean3D,observations::MonocularCamera>
00144 
00145     // -------------------------------------------------------------------------------------------------------------
00146 
00148     template <>
00149     struct sensor_model<landmarks::Euclidean3D,observations::StereoCamera>
00150     {
00151         // --------------------------------------------------------------------------------
00152         // Typedefs for the sake of generality in the signature of methods below:
00153         //   *DONT FORGET* to change these when writing new sensor models.
00154         // --------------------------------------------------------------------------------
00155         typedef observations::StereoCamera     OBS_T;  
00156         typedef landmarks::Euclidean3D         LANDMARK_T;
00157         // --------------------------------------------------------------------------------
00158 
00159         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00160         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00161         
00162         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>  TJacobian_dh_dx;     
00163         typedef landmark_traits<LANDMARK_T>::array_landmark_t    array_landmark_t;             
00164         typedef OBS_T::TObservationParams               TObservationParams;
00165 
00166 
00174         template <class POSE_T>
00175         static void observe_error(
00176             observation_traits<OBS_T>::array_obs_t              & out_obs_err, 
00177             const observation_traits<OBS_T>::array_obs_t        & z_obs, 
00178             const POSE_T                                        & base_pose_wrt_observer,
00179             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00180             const OBS_T::TObservationParams                     & params)
00181         {
00182             double lx,ly,lz; // wrt cam (local coords)
00183             base_pose_wrt_observer.composePoint(lm_pos[0],lm_pos[1],lm_pos[2], lx,ly,lz);
00184             ASSERT_(lz!=0)
00185 
00186             observation_traits<OBS_T>::array_obs_t  pred_obs;  // prediction
00187             // Pinhole model: Left camera.
00188             const mrpt::utils::TCamera &lc = params.camera_calib.leftCamera;
00189             pred_obs[0] = lc.cx() + lc.fx() * lx/lz;
00190             pred_obs[1] = lc.cy() + lc.fy() * ly/lz;
00191 
00192             // Project point relative to right-camera:
00193             const mrpt::poses::CPose3DQuat R2L = -params.camera_calib.rightCameraPose; // R2L = (-) Left-to-right_camera_pose
00194             
00195             // base_wrt_right_cam = ( (-)L2R ) (+) L2Base
00196             //mrpt::poses::CPose3DQuat base_wrt_right_cam(mrpt::poses::UNINITIALIZED_POSE);
00197             //base_wrt_right_cam.composeFrom(R2L,mrpt::poses::CPose3DQuat(base_pose_wrt_observer));
00198             
00199             double rx,ry,rz; // wrt cam (local coords)
00200             //base_wrt_right_cam.composePoint(lx,ly,lz, rx,ry,rz);
00201 
00202             // xji_l_right = R2L (+) Xji_l
00203             R2L.composePoint(lx,ly,lz, rx,ry,rz);
00204             ASSERT_(rz!=0)
00205 
00206             // Pinhole model: Right camera.
00207             const mrpt::utils::TCamera &rc = params.camera_calib.rightCamera;
00208             pred_obs[2] = rc.cx() + rc.fx() * rx/rz;
00209             pred_obs[3] = rc.cy() + rc.fy() * ry/rz;
00210             out_obs_err = z_obs - pred_obs;
00211         }
00212 
00230         static bool eval_jacob_dh_dx(
00231             TJacobian_dh_dx          & dh_dx,
00232             const array_landmark_t   & xji_l, 
00233             const TObservationParams & sensor_params)
00234         {
00235             // xji_l[0:2]=[X Y Z]
00236             // If the point is behind us, mark this Jacobian as invalid. This is probably a temporary situation until we get closer to the optimum.
00237             if (xji_l[2]<=0)
00238                 return false;
00239             
00240             // Left camera:
00241             {
00242                 const double pz_inv = 1.0/xji_l[2];
00243                 const double pz_inv2 = pz_inv*pz_inv;
00244 
00245                 const double cam_fx = sensor_params.camera_calib.leftCamera.fx();
00246                 const double cam_fy = sensor_params.camera_calib.leftCamera.fy();
00247 
00248                 dh_dx.coeffRef(0,0)=  cam_fx * pz_inv;
00249                 dh_dx.coeffRef(0,1)=  0;
00250                 dh_dx.coeffRef(0,2)=  -cam_fx * xji_l[0] * pz_inv2;
00251 
00252                 dh_dx.coeffRef(1,0)=  0;
00253                 dh_dx.coeffRef(1,1)=  cam_fy * pz_inv;
00254                 dh_dx.coeffRef(1,2)=  -cam_fy * xji_l[1] * pz_inv2;
00255             }
00256 
00257             // Right camera:
00258             array_landmark_t   xji_l_right; // xji_l_right = R2L (+) Xji_l
00259             const mrpt::poses::CPose3DQuat R2L = -sensor_params.camera_calib.rightCameraPose; // R2L = (-) Left-to-right_camera_pose
00260             R2L.composePoint(
00261                 xji_l[0],xji_l[1],xji_l[2],
00262                 xji_l_right[0],xji_l_right[1],xji_l_right[2]);
00263             {
00264                 const double pz_inv = 1.0/xji_l_right[2];
00265                 const double pz_inv2 = pz_inv*pz_inv;
00266 
00267                 const double cam_fx = sensor_params.camera_calib.rightCamera.fx();
00268                 const double cam_fy = sensor_params.camera_calib.rightCamera.fy();
00269 
00270                 dh_dx.coeffRef(2,0)=  cam_fx * pz_inv;
00271                 dh_dx.coeffRef(2,1)=  0;
00272                 dh_dx.coeffRef(2,2)=  -cam_fx * xji_l_right[0] * pz_inv2;
00273 
00274                 dh_dx.coeffRef(3,0)=  0;
00275                 dh_dx.coeffRef(3,1)=  cam_fy * pz_inv;
00276                 dh_dx.coeffRef(3,2)=  -cam_fy * xji_l_right[1] * pz_inv2;
00277             }
00278 
00279             return true;
00280         }
00281 
00291         static void inverse_sensor_model(
00292             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00293             const observation_traits<OBS_T>::obs_data_t   & obs, 
00294             const OBS_T::TObservationParams               & params)
00295         {
00296             //     > +Z 
00297             //    / 
00298             //   / 
00299             //  +----> +X
00300             //  |
00301             //  |
00302             //  V +Y
00303             //
00304             const double fxl = params.camera_calib.leftCamera.fx();
00305             const double fyl = params.camera_calib.leftCamera.fy();
00306             const double cxl = params.camera_calib.leftCamera.cx();
00307             const double cyl = params.camera_calib.leftCamera.cy();
00308             const double disparity = std::max(0.001f, obs.left_px.x - obs.right_px.x);
00309             const double baseline  = params.camera_calib.rightCameraPose.x();
00310             ASSERT_(baseline!=0)
00311             const double Z = fxl*baseline/disparity;
00312             out_lm_pos[0] = (obs.left_px.x - cxl)*Z/fxl;
00313             out_lm_pos[1] = (obs.left_px.y - cyl)*Z/fyl;
00314             out_lm_pos[2] = Z;
00315         }
00316 
00317     };  // end of struct sensor_model<landmarks::Euclidean3D,observations::StereoCamera>
00318 
00319     // -------------------------------------------------------------------------------------------------------------
00320 
00322     template <>
00323     struct sensor_model<landmarks::Euclidean3D,observations::Cartesian_3D>
00324     {
00325         // --------------------------------------------------------------------------------
00326         // Typedefs for the sake of generality in the signature of methods below:
00327         //   *DONT FORGET* to change these when writing new sensor models.
00328         // --------------------------------------------------------------------------------
00329         typedef observations::Cartesian_3D     OBS_T;  
00330         typedef landmarks::Euclidean3D         LANDMARK_T;
00331         // --------------------------------------------------------------------------------
00332 
00333         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00334         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00335         
00336         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>        TJacobian_dh_dx;     
00337         typedef landmark_traits<LANDMARK_T>::array_landmark_t array_landmark_t;             
00338         typedef OBS_T::TObservationParams                     TObservationParams;
00339 
00340 
00348         template <class POSE_T>
00349         static void observe_error(
00350             observation_traits<OBS_T>::array_obs_t              & out_obs_err, 
00351             const observation_traits<OBS_T>::array_obs_t        & z_obs, 
00352             const POSE_T                                        & base_pose_wrt_observer,
00353             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00354             const OBS_T::TObservationParams                     & params)
00355         {
00356             MRPT_UNUSED_PARAM(params);
00357             double x,y,z; // wrt cam (local coords)
00358             base_pose_wrt_observer.composePoint(lm_pos[0],lm_pos[1],lm_pos[2], x,y,z);
00359 
00360             observation_traits<OBS_T>::array_obs_t  pred_obs;  // prediction
00361             // Observations are simply the "local coords":
00362             pred_obs[0] = x; pred_obs[1] = y; pred_obs[2] = z;
00363             out_obs_err = z_obs - pred_obs;
00364         }
00365 
00383         static bool eval_jacob_dh_dx(
00384             TJacobian_dh_dx          & dh_dx,
00385             const array_landmark_t   & xji_l, 
00386             const TObservationParams & sensor_params)
00387         {
00388             MRPT_UNUSED_PARAM(xji_l); MRPT_UNUSED_PARAM(sensor_params);
00389             // xji_l[0:2]=[X Y Z]
00390             // This is probably the simplest Jacobian ever:
00391             dh_dx.setIdentity();
00392             return true;
00393         }
00394 
00404         static void inverse_sensor_model(
00405             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00406             const observation_traits<OBS_T>::obs_data_t   & obs, 
00407             const OBS_T::TObservationParams               & params)
00408         {
00409             MRPT_UNUSED_PARAM(params);
00410             out_lm_pos[0] = obs.pt.x;
00411             out_lm_pos[1] = obs.pt.y;
00412             out_lm_pos[2] = obs.pt.z;
00413         }
00414 
00415     };  // end of struct sensor_model<landmarks::Euclidean3D,observations::Cartesian_3D>
00416 
00417     // -------------------------------------------------------------------------------------------------------------
00418 
00420     template <>
00421     struct sensor_model<landmarks::Euclidean2D,observations::Cartesian_2D>
00422     {
00423         // --------------------------------------------------------------------------------
00424         // Typedefs for the sake of generality in the signature of methods below:
00425         //   *DONT FORGET* to change these when writing new sensor models.
00426         // --------------------------------------------------------------------------------
00427         typedef observations::Cartesian_2D     OBS_T;  
00428         typedef landmarks::Euclidean2D         LANDMARK_T;
00429         // --------------------------------------------------------------------------------
00430 
00431         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00432         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00433         
00434         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>  TJacobian_dh_dx;     
00435         typedef landmark_traits<LANDMARK_T>::array_landmark_t    array_landmark_t;             
00436         typedef OBS_T::TObservationParams               TObservationParams;
00437 
00438 
00446         template <class POSE_T>
00447         static void observe_error(
00448             observation_traits<OBS_T>::array_obs_t              & out_obs_err, 
00449             const observation_traits<OBS_T>::array_obs_t        & z_obs, 
00450             const POSE_T                                        & base_pose_wrt_observer,
00451             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00452             const OBS_T::TObservationParams                     & params)
00453         {
00454             double x,y; // wrt cam (local coords)
00455             base_pose_wrt_observer.composePoint(lm_pos[0],lm_pos[1], x,y);
00456 
00457             observation_traits<OBS_T>::array_obs_t  pred_obs;  // prediction
00458             // Observations are simply the "local coords":
00459             pred_obs[0] = x; pred_obs[1] = y;
00460             out_obs_err = z_obs - pred_obs;
00461         }
00462 
00480         static bool eval_jacob_dh_dx(
00481             TJacobian_dh_dx          & dh_dx,
00482             const array_landmark_t   & xji_l, 
00483             const TObservationParams & sensor_params)
00484         {
00485             MRPT_UNUSED_PARAM(xji_l); MRPT_UNUSED_PARAM(sensor_params);
00486             // xji_l[0:1]=[X Y]
00487             // This is probably the simplest Jacobian ever:
00488             dh_dx.setIdentity();
00489             return true;
00490         }
00491 
00501         static void inverse_sensor_model(
00502             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00503             const observation_traits<OBS_T>::obs_data_t   & obs, 
00504             const OBS_T::TObservationParams               & params)
00505         {
00506             MRPT_UNUSED_PARAM(params);
00507             out_lm_pos[0] = obs.pt.x;
00508             out_lm_pos[1] = obs.pt.y;
00509         }
00510 
00511     };  // end of struct sensor_model<landmarks::Euclidean2D,observations::Cartesian_2D>
00512 
00513     // -------------------------------------------------------------------------------------------------------------
00514 
00516     template <>
00517     struct sensor_model<landmarks::Euclidean3D,observations::RangeBearing_3D>
00518     {
00519         // --------------------------------------------------------------------------------
00520         // Typedefs for the sake of generality in the signature of methods below:
00521         //   *DONT FORGET* to change these when writing new sensor models.
00522         // --------------------------------------------------------------------------------
00523         typedef observations::RangeBearing_3D  OBS_T;  
00524         typedef landmarks::Euclidean3D         LANDMARK_T;
00525         // --------------------------------------------------------------------------------
00526 
00527         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00528         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00529         
00530         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>  TJacobian_dh_dx;     
00531         typedef landmark_traits<LANDMARK_T>::array_landmark_t    array_landmark_t;             
00532         typedef OBS_T::TObservationParams               TObservationParams;
00533 
00534 
00542         template <class POSE_T>
00543         static void observe_error(
00544             observation_traits<OBS_T>::array_obs_t              & out_obs_err, 
00545             const observation_traits<OBS_T>::array_obs_t        & z_obs, 
00546             const POSE_T                                        & base_pose_wrt_observer,
00547             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00548             const OBS_T::TObservationParams                     & params)
00549         {
00550             mrpt::math::TPoint3D  l; // wrt sensor (local coords)
00551             base_pose_wrt_observer.composePoint(lm_pos[0],lm_pos[1],lm_pos[2], l.x,l.y,l.z);
00552             
00553             static const mrpt::poses::CPose3D origin;
00554             double range,yaw,pitch;
00555             origin.sphericalCoordinates(
00556                 l,  // In: point
00557                 range,yaw,pitch // Out: spherical coords                            
00558                 );
00559 
00560             observation_traits<OBS_T>::array_obs_t  pred_obs;  // prediction
00561             pred_obs[0] = range;
00562             pred_obs[1] = yaw;
00563             pred_obs[2] = pitch;
00564             out_obs_err = z_obs - pred_obs;
00565         }
00566 
00584         static bool eval_jacob_dh_dx(
00585             TJacobian_dh_dx          & dh_dx,
00586             const array_landmark_t   & xji_l, 
00587             const TObservationParams & sensor_params)
00588         {
00589             MRPT_UNUSED_PARAM(sensor_params);
00590             // xji_l[0:2]=[X Y Z]
00591             mrpt::math::CMatrixDouble33 dh_dx_(mrpt::math::UNINITIALIZED_MATRIX);
00592 
00593             static const mrpt::poses::CPose3DQuat origin;
00594             double range,yaw,pitch;
00595             origin.sphericalCoordinates(
00596                 mrpt::math::TPoint3D(xji_l[0],xji_l[1],xji_l[2]),  // In: point
00597                 range,yaw,pitch, // Out: spherical coords
00598                 &dh_dx_,   // dh_dx
00599                 NULL       // dh_dp (not needed)
00600                 );
00601 
00602             dh_dx = dh_dx_;
00603             return true;
00604         }
00605 
00615         static void inverse_sensor_model(
00616             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00617             const observation_traits<OBS_T>::obs_data_t   & obs, 
00618             const OBS_T::TObservationParams               & params)
00619         {
00620             MRPT_UNUSED_PARAM(params);
00621             const double chn_y = cos(obs.yaw),   shn_y = sin(obs.yaw);
00622             const double chn_p = cos(obs.pitch), shn_p = sin(obs.pitch);
00623             // The new point, relative to the sensor:
00624             out_lm_pos[0] =  obs.range * chn_y * chn_p;
00625             out_lm_pos[1] =  obs.range * shn_y * chn_p;
00626             out_lm_pos[2] = -obs.range * shn_p;
00627         }
00628 
00629     };  // end of struct sensor_model<landmarks::Euclidean3D,observations::RangeBearing_3D>
00630 
00631     // -------------------------------------------------------------------------------------------------------------
00632 
00634     template <>
00635     struct sensor_model<landmarks::Euclidean2D,observations::RangeBearing_2D>
00636     {
00637         // --------------------------------------------------------------------------------
00638         // Typedefs for the sake of generality in the signature of methods below:
00639         //   *DONT FORGET* to change these when writing new sensor models.
00640         // --------------------------------------------------------------------------------
00641         typedef observations::RangeBearing_2D  OBS_T;  
00642         typedef landmarks::Euclidean2D         LANDMARK_T;
00643         // --------------------------------------------------------------------------------
00644 
00645         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00646         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00647         
00648         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>  TJacobian_dh_dx;     
00649         typedef landmark_traits<LANDMARK_T>::array_landmark_t    array_landmark_t;             
00650         typedef OBS_T::TObservationParams               TObservationParams;
00651 
00652 
00660         template <class POSE_T>
00661         static void observe_error(
00662             observation_traits<OBS_T>::array_obs_t              & out_obs_err,
00663             const observation_traits<OBS_T>::array_obs_t        & z_obs,
00664             const POSE_T                                        & base_pose_wrt_observer,
00665             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00666             const OBS_T::TObservationParams                     & params)
00667         {
00668             MRPT_UNUSED_PARAM(params);
00669             mrpt::math::TPoint2D  l; // wrt sensor (local coords)
00670             base_pose_wrt_observer.composePoint(lm_pos[0],lm_pos[1], l.x,l.y);
00671             
00672             const double range = hypot(l.x,l.y);
00673             const double yaw   = atan2(l.y,l.x);
00674 
00675             observation_traits<OBS_T>::array_obs_t  pred_obs;  // prediction
00676             pred_obs[0] = range;
00677             pred_obs[1] = yaw;
00678             out_obs_err = z_obs - pred_obs;
00679         }
00680 
00698         static bool eval_jacob_dh_dx(
00699             TJacobian_dh_dx          & dh_dx,
00700             const array_landmark_t   & xji_l,
00701             const TObservationParams & sensor_params)
00702         {
00703             MRPT_UNUSED_PARAM(sensor_params);
00704             // xji_l[0:1]=[X Y]
00705             const double r = hypot(xji_l[0], xji_l[1]);
00706             if (r==0) return false;
00707 
00708             const double r_inv = 1.0/r;
00709             const double r_inv2 = r_inv*r_inv;
00710             dh_dx(0,0) = xji_l[0] * r_inv;
00711             dh_dx(0,1) = xji_l[1] * r_inv;
00712             dh_dx(1,0) = -xji_l[1] * r_inv2;
00713             dh_dx(1,1) =  xji_l[0] * r_inv2;
00714             return true;
00715         }
00716 
00726         static void inverse_sensor_model(
00727             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00728             const observation_traits<OBS_T>::obs_data_t   & obs, 
00729             const OBS_T::TObservationParams               & params)
00730         {
00731             MRPT_UNUSED_PARAM(params);
00732             const double chn_y = cos(obs.yaw), shn_y = sin(obs.yaw);
00733             // The new point, relative to the sensor:
00734             out_lm_pos[0] = obs.range * chn_y;
00735             out_lm_pos[1] = obs.range * shn_y;
00736         }
00737 
00738     }; // end of sensor_model<landmarks::Euclidean2D,observations::RangeBearing_2D>
00739 
00740     // -------------------------------------------------------------------------------------------------------------
00741 
00743     template <>
00744     struct sensor_model<landmarks::RelativePoses2D,observations::RelativePoses_2D>
00745     {
00746         // --------------------------------------------------------------------------------
00747         // Typedefs for the sake of generality in the signature of methods below:
00748         //   *DONT FORGET* to change these when writing new sensor models.
00749         // --------------------------------------------------------------------------------
00750         typedef observations::RelativePoses_2D  OBS_T;  
00751         typedef landmarks::RelativePoses2D      LANDMARK_T;
00752         // --------------------------------------------------------------------------------
00753 
00754         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00755         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00756         
00757         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>  TJacobian_dh_dx;     
00758         typedef landmark_traits<LANDMARK_T>::array_landmark_t    array_landmark_t;             
00759         typedef OBS_T::TObservationParams               TObservationParams;
00760 
00761 
00769         template <class POSE_T>
00770         static void observe_error(
00771             observation_traits<OBS_T>::array_obs_t              & out_obs_err, 
00772             const observation_traits<OBS_T>::array_obs_t        & z_obs, 
00773             const POSE_T                                        & base_pose_wrt_observer,
00774             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00775             const OBS_T::TObservationParams                     & params)
00776         {
00777             MRPT_UNUSED_PARAM(lm_pos); MRPT_UNUSED_PARAM(params);
00778             // Relative pose observation: 
00779             //  OUT_OBS_ERR = - pseudo-log( PREDICTED_REL_POSE \ominus Z_OBS )
00780             const POSE_T h = POSE_T(z_obs[0],z_obs[1],z_obs[2]) - base_pose_wrt_observer;
00781 
00782             out_obs_err[0] = h.x();
00783             out_obs_err[1] = h.y();
00784             out_obs_err[2] = h.phi();
00785         }
00786 
00804         static bool eval_jacob_dh_dx(
00805             TJacobian_dh_dx          & dh_dx,
00806             const array_landmark_t   & xji_l, 
00807             const TObservationParams & sensor_params)
00808         {
00809             MRPT_UNUSED_PARAM(xji_l); MRPT_UNUSED_PARAM(sensor_params);
00810             // h(z_obs \ominus p) = pseudo-log(z_obs \ominus  p)
00811             // with p: relative pose in SE(2)
00812             dh_dx.setIdentity();
00813             return true;
00814         }
00815 
00825         static void inverse_sensor_model(
00826             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00827             const observation_traits<OBS_T>::obs_data_t   & obs, 
00828             const OBS_T::TObservationParams               & params)
00829         {
00830             MRPT_UNUSED_PARAM(params);
00831             out_lm_pos[0] = obs.x;
00832             out_lm_pos[1] = obs.y;
00833             out_lm_pos[2] = obs.yaw;
00834         }
00835 
00836     }; // end of sensor_model<landmarks::RelativePoses2D,observations::RelativePoses_2D>
00837 
00838     // -------------------------------------------------------------------------------------------------------------
00839 
00841     template <>
00842     struct sensor_model<landmarks::RelativePoses3D,observations::RelativePoses_3D>
00843     {
00844         // --------------------------------------------------------------------------------
00845         // Typedefs for the sake of generality in the signature of methods below:
00846         //   *DONT FORGET* to change these when writing new sensor models.
00847         // --------------------------------------------------------------------------------
00848         typedef observations::RelativePoses_3D  OBS_T;  
00849         typedef landmarks::RelativePoses3D      LANDMARK_T;
00850         // --------------------------------------------------------------------------------
00851 
00852         static const size_t OBS_DIMS = OBS_T::OBS_DIMS;
00853         static const size_t LM_DIMS  = LANDMARK_T::LM_DIMS;
00854         
00855         typedef Eigen::Matrix<double,OBS_DIMS,LM_DIMS>  TJacobian_dh_dx;     
00856         typedef landmark_traits<LANDMARK_T>::array_landmark_t    array_landmark_t;             
00857         typedef OBS_T::TObservationParams               TObservationParams;
00858 
00859 
00867         template <class POSE_T>
00868         static void observe_error(
00869             observation_traits<OBS_T>::array_obs_t              & out_obs_err, 
00870             const observation_traits<OBS_T>::array_obs_t        & z_obs, 
00871             const POSE_T                                        & base_pose_wrt_observer,
00872             const landmark_traits<LANDMARK_T>::array_landmark_t & lm_pos,
00873             const OBS_T::TObservationParams                     & params)
00874         {
00875             // Relative pose observation: 
00876             //  OUT_OBS_ERR = - pseudo-log( PREDICTED_REL_POSE \ominus Z_OBS )
00877             const POSE_T h = POSE_T(z_obs[0],z_obs[1],z_obs[2],z_obs[3],z_obs[4],z_obs[5]) - base_pose_wrt_observer;
00878 
00879             mrpt::poses::SE_traits<3>::pseudo_ln(h,out_obs_err);
00880         }
00881 
00899         static bool eval_jacob_dh_dx(
00900             TJacobian_dh_dx          & dh_dx,
00901             const array_landmark_t   & xji_l, 
00902             const TObservationParams & sensor_params)
00903         {
00904             MRPT_UNUSED_PARAM(xji_l); MRPT_UNUSED_PARAM(sensor_params);
00905             // h(z_obs \ominus p) = xji_l (the relative pose in SE(3)) 
00906             dh_dx.setIdentity();
00907             return true;
00908         }
00909 
00919         static void inverse_sensor_model(
00920             landmark_traits<LANDMARK_T>::array_landmark_t & out_lm_pos,
00921             const observation_traits<OBS_T>::obs_data_t   & obs, 
00922             const OBS_T::TObservationParams               & params)
00923         {
00924             MRPT_UNUSED_PARAM(params);
00925             out_lm_pos[0] = obs.x;   out_lm_pos[1] = obs.y;     out_lm_pos[2] = obs.z;
00926             out_lm_pos[3] = obs.yaw; out_lm_pos[4] = obs.pitch; out_lm_pos[5] = obs.roll; 
00927         }
00928 
00929     };  // end of struct sensor_model<landmarks::RelativePoses3D,observations::RelativePoses_3D>
00930 
00931     // -------------------------------------------------------------------------------------------------------------
00932 
00935 } // end NS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends