The implementation of Problem::getState/getTimeStamp() first implement the case processor_is_motion_list.empty() (taking last KF state or zeroState) and otherwise, fill the state/timeStamp iterating over the processors. But they could be not initialized yet so returning empty state or 0 timestamp (see related issue #333).
The implementation should be in the opposite order: first iterate over processors and afterwards deal with incomplete or missing state/timestamp.
Also, in case of no KF and a prior has been provided by the user, it is better if getState() returns this state than zero.
Edited
Designs
Child items
...
Show closed items
Linked items
0
Link issues together to show that they're related.
Learn more.
I'll focus on getState, it is the only one requiring discussion.
There are 2 different getState now, one providing TimeStamp and the other without it (meaning the current state).
getState(TimeStamp, Structure)
Some (most) processors use it to initialize a frame state. Because of this, the old implementation of getState always provided a "valid" state (i.e. complete). In my opinion, that should stay like this.
From the point of view of the processors, this function means:
"Problem, give me the best initialization of this structure at this timestamp".
As a final consideration, zero is the final alternative only in case of missing ( or not initialized) is_motion processors, no KFs and no prior.state defined by the user.
getState(Structure) is quite more simple and less critical (it is used by ROS node to publish current state), I would discuss about the other case and apply the same criterion in this one.
VectorCompositeProblem::getState(constTimeStamp&_ts,constStateStructure&_structure)const{StateStructurestructure=(_structure==""?getFrameStructure():_structure);VectorCompositestate;for(constauto&prc:processor_is_motion_list_){constauto&prc_state=prc->getState(_ts);// transfer processor vector blocks to problem statefor(constauto&pair_key_vec:prc_state){constauto&key=pair_key_vec.first;if(state.count(key)==0)// Only write once. This gives priority to processors upfront in the liststate.insert(pair_key_vec);}}// check for empty blocks and fill them with the last KF or with zeros in the worst caseVectorCompositestate_last;constauto&last_kf_or_aux=trajectory_ptr_->closestKeyOrAuxFrameToTimeStamp(_ts);if(last_kf_or_aux)state_last=last_kf_or_aux->getState(structure);for(constauto&ckey:structure){constauto&key=string(1,ckey);if(state.count(key)==0){autostate_last_it=state_last.find(key);if(state_last_it!=state_last.end())state.emplace(key,state_last_it->second);elsestate.emplace(key,stateZero(key).at(key));}}returnstate;}
I would add that we may want to consider the prior information if provided by the user. I think it is only one line after checking KF:
VectorCompositeProblem::getState(constTimeStamp&_ts,constStateStructure&_structure)const{StateStructurestructure=(_structure==""?getFrameStructure():_structure);VectorCompositestate;for(constauto&prc:processor_is_motion_list_){constauto&prc_state=prc->getState(_ts);// transfer processor vector blocks to problem statefor(constauto&pair_key_vec:prc_state){constauto&key=pair_key_vec.first;if(state.count(key)==0)// Only write once. This gives priority to processors upfront in the liststate.insert(pair_key_vec);}}// check for empty blocks and fill them with the last KF or with zeros in the worst caseVectorCompositestate_last;constauto&last_kf_or_aux=trajectory_ptr_->closestKeyOrAuxFrameToTimeStamp(_ts);if(last_kf_or_aux)state_last=last_kf_or_aux->getState(structure);elseif(prior_optionsandprior_options_->mode!="nothing")state_last=prior_options_->state;for(constauto&ckey:structure){constauto&key=string(1,ckey);if(state.count(key)==0){autostate_last_it=state_last.find(key);if(state_last_it!=state_last.end())state.emplace(key,state_last_it->second);elsestate.emplace(key,stateZero(key).at(key));}}returnstate;}