Skip to content

Unexpected output of _chainAsVector() #749

@JohannesErnst

Description

@JohannesErnst

Bug report / Missing functionality

Required Info:

  • Operating System:
    • OpenSUSE 15.5
  • Installation type:
    • binaries
  • Version or commit hash:
    • Humble
  • DDS implementation:
    • N/A
  • Client library (if applicable):
    • rclpy

Explanation

In tf2 for ros1 there existed a function to retrieve the chain of two frames as a list of strings. Now migrating to ros2, we need the functionality of this function. The corresponding function of tf2 for ros2 is here:

void BufferCore::_chainAsVector(
const std::string & target_frame, TimePoint target_time,
const std::string & source_frame, TimePoint source_time,
const std::string & fixed_frame,
std::vector<std::string> & output) const
{
std::string error_string;
output.clear(); // empty vector
std::unique_lock<std::mutex> lock(frame_mutex_);
TransformAccum accum;
// Get source frame/time using getFrame
CompactFrameID source_id = lookupFrameNumber(source_frame);
CompactFrameID fixed_id = lookupFrameNumber(fixed_frame);
CompactFrameID target_id = lookupFrameNumber(target_frame);
std::vector<CompactFrameID> source_frame_chain;
tf2::TF2Error retval = walkToTopParent(
accum, source_time, fixed_id, source_id, &error_string,
&source_frame_chain);
if (retval != tf2::TF2Error::TF2_NO_ERROR) {
switch (retval) {
case tf2::TF2Error::TF2_CONNECTIVITY_ERROR:
throw ConnectivityException(error_string);
case tf2::TF2Error::TF2_EXTRAPOLATION_ERROR:
throw ExtrapolationException(error_string);
case tf2::TF2Error::TF2_LOOKUP_ERROR:
throw LookupException(error_string);
default:
CONSOLE_BRIDGE_logError("Unknown error code: %d", retval);
assert(0);
}
}
if (source_time != target_time) {
std::vector<CompactFrameID> target_frame_chain;
retval = walkToTopParent(
accum, target_time, target_id, fixed_id, &error_string,
&target_frame_chain);
if (retval != tf2::TF2Error::TF2_NO_ERROR) {
switch (retval) {
case tf2::TF2Error::TF2_CONNECTIVITY_ERROR:
throw ConnectivityException(error_string);
case tf2::TF2Error::TF2_EXTRAPOLATION_ERROR:
throw ExtrapolationException(error_string);
case tf2::TF2Error::TF2_LOOKUP_ERROR:
throw LookupException(error_string);
default:
CONSOLE_BRIDGE_logError("Unknown error code: %d", retval);
assert(0);
}
}
size_t m = target_frame_chain.size();
size_t n = source_frame_chain.size();
while (m > 0u && n > 0u) {
--m;
--n;
if (source_frame_chain[n] != target_frame_chain[m]) {
break;
}
}
// Erase all duplicate items from frame_chain
if (n > 0u) {
source_frame_chain.erase(source_frame_chain.begin() + (n - 1u), source_frame_chain.end());
}
if (m < target_frame_chain.size()) {
for (size_t i = 0u; i <= m; ++i) {
source_frame_chain.push_back(target_frame_chain[i]);
}
}
}
// Write each element of source_frame_chain as string
for (size_t i = 0u; i < source_frame_chain.size(); ++i) {
output.push_back(lookupFrameString(source_frame_chain[i]));
}
}
} // namespace tf2

However, it is now not wrapped as a listener function but can only be accessed via the private member function buffer._chain(). The bigger problem is that the implementation seems erroneous. Consider this simple tf tree:

   A
 /   \
B     D
|
C

Querying _chainAsVector(target_frame=D, source_frame=C, fixed_frame=A) (regardless of the time), yields the chain ['C', 'B'] and not as expected ['C', 'B', 'A', 'D'].

Does anyone have an idea why it is like this?

And also why the implementation changed from ros1 tf2 to ros2 tf2 (compare upper links) while the previous implementation worked just fine?

Is there a similar function that I don't know of that can achieve the same thing (python)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions