00001
00002
00003
00004
00005
00006
00007
00008 #include "structs.h"
00009 #include "hogman_wrapper.h"
00010 #include "boost/tuple/tuple.hpp"
00011
00012 using namespace std;
00013 using namespace articulation_models;
00014 using namespace geometry_msgs;
00015 using namespace articulation_msgs;
00016 using namespace std_msgs;
00017 using namespace sensor_msgs;
00018 using namespace articulation_structure;
00019 using namespace Eigen;
00020
00021 KinematicParams::KinematicParams() {
00022 sigma_position = 0.005;
00023 sigma_orientation = 0.001;
00024 eval_every = 1;
00025 eval_every_power = 1.0;
00026 supress_similar = false;
00027 reuse_model = true;
00028 restricted_graphs = "";
00029 restrict_graphs = false;
00030 reduce_dofs = false;
00031 search_all_models = false;
00032 full_eval="tree";
00033 }
00034
00035 void KinematicParams::LoadParams(ros::NodeHandle &nh_local,bool show) {
00036 string filter_models("rigid rotational prismatic");
00037 nh_local.getParam("filter_models", filter_models);
00038 nh_local.getParam("sigma_position", sigma_position);
00039 nh_local.getParam("sigma_orientation", sigma_orientation);
00040 nh_local.getParam("sigmax_position", sigmax_position);
00041 nh_local.getParam("sigmax_orientation", sigmax_orientation);
00042 nh_local.getParam("full_eval", full_eval);
00043 nh_local.getParam("eval_every", eval_every);
00044 nh_local.getParam("eval_every_power", eval_every_power);
00045 nh_local.getParam("restricted_graphs", restricted_graphs);
00046 restricted_graphs = " "+restricted_graphs+" ";
00047 nh_local.getParam("restrict_graphs", restrict_graphs);
00048
00049 nh_local.getParam("reuse_model", reuse_model);
00050 nh_local.getParam("supress_similar", supress_similar);
00051 nh_local.getParam("reduce_dofs", reduce_dofs);
00052 nh_local.getParam("search_all_models", search_all_models);
00053
00054 factory.setFilter(filter_models);
00055
00056 }
00057
00058 void KinematicData::addPose(PoseStamped pose1, PoseStamped pose2, size_t id1, size_t id2,KinematicParams ¶ms) {
00059 TrackMsgPtr& track = trajectories[id1][id2];
00060 if (!track) {
00061 track = boost::make_shared<TrackMsg>();
00062 ChannelFloat32 ch;
00063 ch.name = "stamp";
00064 track->channels.push_back(ch);
00065 }
00066
00067 tf::Transform transf1 = poseToTransform(pose1.pose);
00068 tf::Transform transf2 = poseToTransform(pose2.pose);
00069 tf::Transform diff = transf1.inverseTimes(transf2);
00070
00071 for(size_t i=0;i<trajectories[id1][id2]->pose.size();i++) {
00072 tf::Transform diff_to_known;
00073 Pose p;
00074 p = trajectories[id1][id2]->pose[i];
00075 tf::Transform t;
00076 t = poseToTransform( p );
00077 diff_to_known = t.inverseTimes( diff );
00078 double diff_position = diff_to_known.getOrigin().length();
00079 double diff_orientation = fabs(diff_to_known.getRotation().getAngle());
00080 if(params.supress_similar && diff_position < params.sigma_position/2 && diff_orientation < params.sigma_orientation/2) {
00081
00082 return;
00083 }
00084 }
00085
00086 poseIndex[id1][id2][ pose1.header.stamp.toSec() ] = track->pose.size();
00087
00088 track->pose.push_back(transformToPose( diff));
00089 track->channels[0].values.push_back( pose1.header.stamp.toSec() );
00090 track->header = pose1.header;
00091
00092
00093 }
00094
00095 void KinematicData::updateModel(size_t id1, size_t id2,KinematicParams ¶ms) {
00096 TrackMsgPtr& track = trajectories[id1][id2];
00097 GenericModelPtr& model = models[id1][id2];
00098
00099 articulation_msgs::ModelMsg model_track;
00100 model_track.track = *track;
00101 model_track.header = track->header;
00102 setParamIfNotDefined(model_track.params, "sigma_position",
00103 params.sigma_position, ParamMsg::PRIOR);
00104 setParamIfNotDefined(model_track.params, "sigma_orientation",
00105 params.sigma_orientation, ParamMsg::PRIOR);
00106
00107 GenericModelVector models_new = params.factory.createModels(model_track);
00108 map<double,GenericModelPtr> models_sorted;
00109 models_all[id1][id2].clear();
00110 for (size_t i = 0; i < models_new.size(); i++) {
00111 if (!models_new[i]->fitModel()) continue;
00112 if (!models_new[i]->fitMinMaxConfigurations()) continue;
00113 if (!models_new[i]->evaluateModel()) continue;
00114 if(isnan( models_new[i]->getBIC() )) continue;
00115
00116 if(params.reuse_model && model && model->getModelName()==models_new[i]->getModelName()) {
00117 model->setTrack(*track);
00118 model->optimizeParameters();
00119 model->evaluateModel();
00120 if(!isnan( model->getBIC() ) &&
00121 (models_new[i]->getBIC() > model->getBIC())) {
00122 models_new[i] = model;
00123 }
00124 }
00125
00126 models_sorted[models_new[i]->getBIC()] = models_new[i];
00127 models_all[id1][id2].push_back( models_new[i] );
00128 }
00129
00130 if(models_sorted.size()==0) {
00131 ROS_INFO_STREAM("no models!! model["<<id1<<","<<id2<<"]: poses="<<track->pose.size());
00132 model.reset();
00133 return;
00134 }
00135 map<double,GenericModelPtr>::iterator it = models_sorted.begin();
00136 model = it->second;
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 }
00150
00151 std::vector<double> KinematicData::intersectionOfStamps() {
00152
00153 std::vector<double> intersection;
00154
00155 size_t num_markers = markerStamped.size();
00156 for(map<double, map<int, PoseStampedIdMsgConstPtr> >::iterator it = stampedMarker.begin();
00157 it != stampedMarker.end();
00158 it++) {
00159 if(it->second.size() == num_markers) {
00160 intersection.push_back( it->first );
00161 }
00162
00163
00164
00165
00166
00167
00168 }
00169
00170
00171 return(intersection);
00172 }
00173
00174 PoseMap KinematicData::getObservation(double timestamp) {
00175 PoseMap observedMarkers;
00176 for(std::map<int, articulation_structure::PoseStampedIdMsgConstPtr>::iterator it = stampedMarker[timestamp].begin();
00177 it != stampedMarker[timestamp].end();it++) {
00178 observedMarkers[it->first] = it->second->pose.pose;
00179 }
00180 return observedMarkers;
00181 }
00182
00183 KinematicGraph::KinematicGraph() {
00184 BIC = DBL_MAX;
00185 DOF = -1;
00186 avg_pos_err = -1;
00187 avg_orient_err = -1;
00188 loglh = DBL_MAX;
00189 }
00190
00191 KinematicGraph::KinematicGraph(const KinematicGraph &other):
00192 KinematicGraphType( other ), BIC(other.BIC),DOF(other.DOF),avg_pos_err(other.avg_pos_err),avg_orient_err(other.avg_orient_err),loglh(other.loglh)
00193 {
00194 }
00195
00196 KinematicGraph::KinematicGraph(const KinematicGraph &other,bool deepcopy):
00197 KinematicGraphType( other ), BIC(other.BIC),DOF(other.DOF),avg_pos_err(other.avg_pos_err),avg_orient_err(other.avg_orient_err),loglh(other.loglh)
00198 {
00199 if(deepcopy) {
00200 CopyFrom(other);
00201 }
00202 }
00203
00204 void KinematicGraph::CopyFrom(const KinematicGraph &other) {
00205 *this = other;
00206 static MultiModelFactory factory;
00207 for(KinematicGraph::iterator it=begin();it!=end();it++) {
00208 it->second = factory.restoreModel(it->second->getModel());
00209 }
00210 }
00211
00212
00213 size_t KinematicGraph::getNumberOfParameters() {
00214 size_t k = 0;
00215 for(KinematicGraph::iterator it=begin(); it != end();it++) {
00216 k += (size_t) it->second->complexity;
00217 }
00218 return k;
00219 }
00220
00221
00222
00223 int KinematicGraph::getNominalDOFs() {
00224 int DOFs = 0;
00225 for(KinematicGraph::iterator it=begin(); it != end();it++) {
00226 DOFs += it->second->getDOFs();
00227 }
00228 return(DOFs);
00229 }
00230
00231 PoseMap KinematicGraph::getPrediction(double timestamp, PoseMap &observedMarkers, PoseMap &predictedMarkersEmpty, KinematicParams ¶ms,KinematicData &data) {
00232 return hogman_solver(*this, data.poseIndex, observedMarkers, predictedMarkersEmpty, params.sigma_position,params.sigma_orientation, timestamp);
00233 }
00234
00235 string KinematicGraph::getTreeName(bool show_name,bool show_samples,bool show_dof) {
00236 stringstream s;
00237 if(show_dof) {
00238 s << DOF<<"-DOF ";
00239 }
00240 for(KinematicGraph::iterator it=begin(); it != end();it++) {
00241 if(it != begin()) s<<",";
00242 s << "(";
00243 if(show_name) {
00244 s <<it->second->getModelName().substr(0,2)<<":";
00245 }
00246 s <<it->first.first<<","<<it->first.second;
00247 if(show_samples)
00248 s << "/"<<it->second->getSamples();
00249 s<<")";
00250 }
00251 return s.str();
00252 }
00253
00254 void KinematicGraph::evaluateSingleStamp(double timestamp,
00255 double &avgPositionError,
00256 double &avgOrientationError,
00257 double &loglikelihood,KinematicParams ¶ms,KinematicData &data) {
00258
00259 if (size()==0) return;
00260
00261 PoseMap observationMarkers = data.getObservation(timestamp);
00262 PoseMap predictedMarkers = getPrediction(timestamp,observationMarkers,observationMarkers,params,data);
00263
00264
00265 for(PoseMap::iterator i=predictedMarkers.begin();i!=predictedMarkers.end();i++) {
00266 PoseStampedIdMsg p = *data.stampedMarker[timestamp][i->first];
00267 p.pose.pose = i->second;
00268 PoseStampedIdMsgConstPtr pptr = boost::make_shared<PoseStampedIdMsg>(p);
00269 data.stampedMarkerProjected[timestamp][i->first] = pptr;
00270 }
00271
00272
00273 double sum_loglh = 0;
00274 double sum_pos2_err = 0;
00275 double sum_orient2_err = 0;
00276
00277 double sigma2_position = SQR(params.sigmax_position);
00278 double sigma2_orientation = SQR(params.sigmax_orientation);
00279
00280 for(PoseMap::iterator it = observationMarkers.begin();
00281 it != observationMarkers.end(); it++ ) {
00282 tf::Transform p1 = poseToTransform(observationMarkers[it->first]);
00283 tf::Transform p2 = poseToTransform(predictedMarkers[it->first]);
00284
00285 tf::Transform diff = p1.inverseTimes(p2);
00286 double err_position2 = diff.getOrigin().length2();
00287 if(isnan(err_position2 )) err_position2 =0;
00288 double err_orientation2 = SQR(diff.getRotation().getAngle());
00289 if(isnan(err_orientation2 )) err_orientation2 =0;
00290
00291 sum_pos2_err += err_position2;
00292 sum_orient2_err += err_orientation2;
00293
00294 double loglikelihood =
00295 - log(2*M_PI * params.sigma_position*params.sigma_orientation)
00296 - 0.5*(
00297 ( err_position2 / (sigma2_position) ) +
00298 ( err_orientation2 / (sigma2_orientation) ) );
00299 sum_loglh += loglikelihood;
00300 }
00301
00302 size_t n = observationMarkers.size();
00303 avgPositionError = sqrt(sum_pos2_err/n);
00304 avgOrientationError = sqrt(sum_orient2_err/n);
00305 loglikelihood = sum_loglh;
00306 }
00307
00308 void KinematicGraph::evaluate(
00309 std::vector<double> stamps,
00310 KinematicParams ¶ms,KinematicData &data) {
00311
00312 static MultiModelFactory factory;
00313 for(KinematicGraph::iterator it=begin();it!=end();it++) {
00314 it->second = factory.restoreModel(it->second->getModel());
00315 }
00316
00317 BIC = DBL_MAX;
00318 avg_pos_err = DBL_MAX;
00319 avg_orient_err = DBL_MAX;
00320 loglh = DBL_MIN;
00321
00322 if (size()==0) return;
00323
00324 if(DOF != getNominalDOFs())
00325 projectConfigurationSpace(DOF,stamps,params,data);
00326
00327
00328
00329 double sum_pos2_err = 0;
00330 double sum_orient2_err = 0;
00331 double sum_loglh = 0;
00332
00333 double pos_err,orient_err;
00334
00335 data.stampedMarkerProjected.clear();
00336 for(size_t i=0;i<stamps.size();i++) {
00337 evaluateSingleStamp(stamps[i],pos_err, orient_err, loglh,params,data );
00338 sum_loglh += loglh;
00339 sum_pos2_err += SQR(pos_err);
00340 sum_orient2_err += SQR(orient_err);
00341 }
00342
00343 avg_pos_err = sqrt(sum_pos2_err/stamps.size());
00344 avg_orient_err = sqrt(orient_err/stamps.size());
00345 loglh = sum_loglh;
00346
00347 k = getNumberOfParameters();
00348 int k_pca = 0;
00349 double loglh_pca;
00350 if(DOF != getNominalDOFs()) {
00351 k_pca = getNominalDOFs() * DOF;
00352 loglh_pca = stamps.size() * (getNominalDOFs() - DOF) * log(stamps.size());
00353 }
00354 BIC = getBIC( loglh + loglh_pca, k + k_pca,stamps.size() );
00355
00356 return;
00357 }
00358
00359 void KinematicGraph::projectConfigurationSpace(int reducedDOFs,std::vector<double> stamps, KinematicParams ¶ms,KinematicData &data) {
00360 if(reducedDOFs == 0) return;
00361 if(stamps.size() == 0) return;
00362
00363 map< GenericModelPtr, int> DOFoffsets;
00364 int DOFs = 0;
00365 for(KinematicGraph::iterator it=begin(); it != end();it++) {
00366 DOFoffsets[it->second] = DOFs;
00367 DOFs += it->second->getDOFs();
00368 }
00369 if(DOFs==0) return;
00370
00371 MatrixXf X_trans(stamps.size(), DOFs);
00372
00373 for(KinematicGraph::iterator it=begin(); it != end();it++) {
00374 GenericModelPtr model = it->second;
00375 int DOFoffset = DOFoffsets[model];
00376
00377 if(model->getDOFs()==0) continue;
00378
00379 for(size_t timestamp_idx = 0;timestamp_idx < stamps.size();timestamp_idx++) {
00380 int idx = data.poseIndex[ it->first.first ][it->first.second][ stamps[timestamp_idx]];
00381
00382 VectorXd c = model->getConfiguration(idx);
00383 for(size_t d=0;d< model->getDOFs();d++) {
00384 X_trans( timestamp_idx,DOFoffset + d ) = c(d);
00385 }
00386 }
00387 }
00388
00389 VectorXf X_mean = VectorXf::Zero(DOFs,1);
00390 for( size_t i=0;i< stamps.size();i++) {
00391 for( int j=0;j< DOFs;j++) {
00392 X_mean(j) += X_trans(i,j);
00393 }
00394 }
00395 X_mean /= stamps.size();
00396
00397
00398
00399 for( int j=0;j< DOFs;j++) {
00400 if(isnan((double)X_mean(j))) {
00401 cout << X_trans << endl<<endl;
00402 cout << X_mean << endl;
00403 cout <<"reducing DOFs failed, NaN value"<<endl;
00404 return;
00405 }
00406 if(fabs((double)X_mean(j))>100) {
00407 cout << X_trans << endl<<endl;
00408 cout << X_mean << endl;
00409 cout <<"reducing DOFs failed, large value"<<endl;
00410 return;
00411 }
00412 }
00413
00414 MatrixXf X_center(stamps.size(), DOFs);
00415 for( size_t i=0;i< stamps.size();i++) {
00416 for( int j=0;j< DOFs;j++) {
00417 X_center(i,j) = X_trans(i,j) - X_mean(j);
00418 }
00419 }
00420
00421 if(stamps.size() < (size_t)DOFs) return;
00422
00423 JacobiSVD<MatrixXf> svdOfA(X_center);
00424
00425 const Eigen::MatrixXf U = svdOfA.matrixU();
00426 const Eigen::MatrixXf V = svdOfA.matrixV();
00427 const Eigen::VectorXf S = svdOfA.singularValues();
00428
00429
00430 Eigen::MatrixXf V_projection = V.block(0,0,DOFs,reducedDOFs);
00431 MatrixXf X_reduced(stamps.size(),reducedDOFs);
00432
00433 for( size_t i=0;i< stamps.size();i++) {
00434 for( int k=0;k< reducedDOFs;k++) {
00435 X_reduced(i,k) = 0.0;
00436 for( int j=0;j< DOFs;j++) {
00437 X_reduced(i,k) += V(j,k) * X_center(i,j);
00438 }
00439 }
00440 }
00441
00442 MatrixXf X_projected(stamps.size(),DOFs);
00443 for( size_t i=0;i< stamps.size();i++) {
00444 for( int j=0;j< DOFs;j++) {
00445 X_projected(i,j) = X_mean(j);
00446 for( int k=0;k< reducedDOFs;k++) {
00447 X_projected(i,j) += V(j,k) * X_reduced(i,k);
00448 }
00449 }
00450 }
00451
00452 for(KinematicGraph::iterator it=begin(); it != end();it++) {
00453 GenericModelPtr model = it->second;
00454 if(model->getDOFs()==0) continue;
00455 int DOFoffset = DOFoffsets[model];
00456
00457 for(size_t timestamp_idx = 0;timestamp_idx < stamps.size();timestamp_idx++) {
00458 int idx = data.poseIndex[ it->first.first ][it->first.second][ stamps[timestamp_idx]];
00459
00460 VectorXd c(model->getDOFs());
00461 for(size_t d=0;d< model->getDOFs();d++) {
00462 c(d) =X_projected( timestamp_idx,DOFoffset + d );
00463 }
00464
00465 model->setConfiguration(idx,c);
00466 model->model.track.pose_projected[idx] = model->predictPose( c );
00467 }
00468 }
00469 DOF = reducedDOFs;
00470 }
00471
00472 #include "boost/tuple/tuple.hpp"
00473
00474 int KinematicGraph::distanceTo(KinematicGraph &other) {
00475 int distance = 0;
00476 distance +=fabs((getNominalDOFs()-DOF) - (other.getNominalDOFs()-other.DOF));
00477
00478
00479 set< pair<int,int> > my_edges,other_edges,diff_edges;
00480 for(KinematicGraph::iterator it=begin();it!=end();it++) my_edges.insert( pair<int,int>(it->first.first,it->first.second) );
00481 for(KinematicGraph::iterator it = other.begin();it!=other.end();it++) other_edges.insert(pair<int,int>(it->first.first,it->first.second) );
00482 set_symmetric_difference(my_edges.begin(),my_edges.end(),other_edges.begin(),other_edges.end(),insert_iterator<set< pair<int,int> > >(diff_edges,diff_edges.begin()) );
00483 distance += diff_edges.size();
00484
00485
00486 set< pair<pair<int,int>,string> > my_models,other_models,intersec_models,diff_models;
00487 for(KinematicGraph::iterator it=begin();it!=end();it++)
00488 if(diff_edges.find(it->first)==diff_edges.end())
00489 my_models.insert( pair<pair<int,int>,string>(pair<int,int>(it->first.first,it->first.second),it->second->getModelName()) );
00490 for(KinematicGraph::iterator it = other.begin();it!=other.end();it++)
00491 if(diff_edges.find(it->first)==diff_edges.end())
00492 other_models.insert(pair<pair<int,int>,string>(pair<int,int>(it->first.first,it->first.second),it->second->getModelName()) );
00493 set_symmetric_difference(my_models.begin(),my_models.end(),other_models.begin(),other_models.end(),insert_iterator<set< pair<pair<int,int>,string> > >(diff_models,diff_models.begin()) );
00494 distance += diff_models.size()/2;
00495
00496 return distance;
00497 }