GithubHelp home page GithubHelp logo

Comments (11)

SteveMacenski avatar SteveMacenski commented on June 14, 2024

The best I can tell its this node, which has the optional start field which isn't used in that BT XML because the start is implied by the server as current_pose if no specific start is provided. I suspect that its not even the only issue, its just the first it found. We have alot of optional input ports.

@facontidavide with Groot2's BT node index, is there a new mechanic for marking optional input ports? I couldn't find any documentation on the BT.CPP website on this

from navigation2.

facontidavide avatar facontidavide commented on June 14, 2024

Let me check this.

from navigation2.

facontidavide avatar facontidavide commented on June 14, 2024

Sooo. the problem is that in the model you specified:

<Action ID="RemovePassedGoals">
      <input_port name="input_goals">Input goals to remove if passed</input_port>
      <input_port name="radius">Radius tolerance on a goal to consider it passed</input_port>
      <input_port name="global_frame">Global frame</input_port>
      <input_port name="robot_base_frame">Robot base frame</input_port>
      <output_port name="output_goals">Set of goals after removing any passed</output_port>
    </Action>

But in the mentioned behavior tree:

<RemovePassedGoals input_goals="{goals}" output_goals="{goals}" radius="0.7"/>

The model doesn't contain the default value, that makes them optional.

The wird thing is that, checking the source code of class RemovePassedGoals, the port global_frame is defined but never used.

Therefore, this line must be removed: https://github.com/ros-planning/navigation2/blob/main/nav2_behavior_tree/include/nav2_behavior_tree/plugins/action/remove_passed_goals_action.hpp#L50

Additionally, "robot_base_frame" is missing too in the XML, but seems like you alternatively read it from other sources.
The solution is to add a default value like this:

BT::InputPort<std::string>("robot_base_frame", std::string(), "Robot base frame"),

But then, deconflictPortAndParamFrame will not work anymore, because we need to consider the empty string case too.

I can try to make Groot2 a little bit more permissive, i.e add an empty port instead of failing.
But I still suggest addressing this

from navigation2.

SteveMacenski avatar SteveMacenski commented on June 14, 2024

RemovePassedGoals is a good point - but I think they're failing on something simpler with start optional port in ComputePathToPose, given their error message.

I can try to make Groot2 a little bit more permissive, i.e add an empty port instead of failing.

OK!

from navigation2.

facontidavide avatar facontidavide commented on June 14, 2024

😄 I focused on that because it is the first error I saw when testing myself

But the problem seems to be widespread... many ports are meant to be optional but they are not declared as optional.

The problem is NOT that Groot2 fails, the actual problem is that the BehaviorTree.CPP executor should be the one failing, to catch these issues earlier

from navigation2.

SteveMacenski avatar SteveMacenski commented on June 14, 2024

but they are not declared as optional.

How do you declare optional? I don't think that's something I was aware of a option to set. the vast majority of our ports are optional. Very, very few are required

from navigation2.

facontidavide avatar facontidavide commented on June 14, 2024

You need to use this overload: https://github.com/BehaviorTree/BehaviorTree.CPP/blob/master/include/behaviortree_cpp/basic_types.h#L407-L414

This gives a default value to the port. If the port is NOT specified in the XML, the default value will be used.

Note that getInput() will succeed and return the default value. So, you can not use that method to determine if we are using the default.

In the case of deconflictPortAndParamFrame, I would probably change it to

template<typename T1, typename T2>
T1 deconflictPortAndParamFrame(
  rclcpp::Node::SharedPtr node,
  std::string param_name,
  T2 * behavior_tree_node)
{
  const auto param_value = behavior_tree_node->getInput(param_name);
  bool is_empty = false;
  if constexpr (std::is_same_v<T1, std::string>)
  {
    // empty if port doesn't exist or it is an empty string
    is_empty = !param_value || param_value->empty();
  }
  if (is_empty) {
    RCLCPP_DEBUG(
      node->get_logger(),
      "Parameter '%s' not provided by behavior tree xml file, "
      "using parameter from ros2 parameter file",
      param_name.c_str());
    node->get_parameter(param_name, *param_value);
    return *param_value;
  } else {
    RCLCPP_DEBUG(
      node->get_logger(),
      "Parameter '%s' provided by behavior tree xml file",
      param_name.c_str());
    return *param_value;
  }
}

from navigation2.

facontidavide avatar facontidavide commented on June 14, 2024

If instead of default, what you really want is to keep that port undefined (so... real "optional"), I may consider to implement something like:

BT::InputPort<std::string>("robot_base_frame", "Robot base frame")->optional();

or

BT::InputPortOptional<std::string>("robot_base_frame", "Robot base frame");

from navigation2.

facontidavide avatar facontidavide commented on June 14, 2024

Follow up: I am trying to be consistent with the behavior of the BT.CPP executor.

  1. When the XML doesn't contain a port value, getInput will "only" fail. Not what I intended, but I understand from @SteveMacenski that Nav2 extensively rely on this.

  2. When the XML contains the name of a port that is not in the model, BT.CPP throws an exception. See here

I am changing Groot2 to be consistent with that (will be fixed in version 1.5.1), but I think you still have problem 2, for instance Spin seems to have a wrong model.

    <Action ID="Spin">
      <input_port name="spin_dist">Spin distance</input_port>
      <input_port name="time_allowance">Allowed time for spinning</input_port>
      <input_port name="server_name">Server name</input_port>
      <input_port name="server_timeout">Server timeout</input_port>
      <output_port name="error_code_id">Spin error code</output_port>
    </Action>

But in C++

  static BT::PortsList providedPorts()
  {
    return providedBasicPorts(
      {
        BT::InputPort<double>("spin_dist", 1.57, "Spin distance"),
        BT::InputPort<double>("time_allowance", 10.0, "Allowed time for spinning"),
        BT::InputPort<bool>("is_recovery", true, "True if recovery"),
        BT::OutputPort<ActionResult::_error_code_type>(
          "error_code_id", "The spin behavior error code")
      });
  }

from navigation2.

facontidavide avatar facontidavide commented on June 14, 2024

Version 1.5.1 was released and includes this particular fix (but others may be needed in the future).
Shall we close this issue or keep it open to follow up on this topic?

from navigation2.

SteveMacenski avatar SteveMacenski commented on June 14, 2024

How do you declare optional?

You need to use this overload

That overload involves a default value, what I mean is that they are entirely optional and when not specified they should have no value. Having the getInput() return false is how we detect that its not set. If there's a default value, then alot of that logic would simply fail to function properly.

This gives a default value to the port. If the port is NOT specified in the XML, the default value will be used.

That's not the behavior we want. They're not optional in the sense that if not specified, there's some viable value for it. They're optional as in there are multiple, mutually-exclusive settings going on at which if some values are not provided, that tells us which to use.

If instead of default, what you really want is to keep that port undefined (so... real "optional"), I may consider to implement something

That's more in line with what I'm thinking. Though, we have something without that working right now perfectly fine. Making things explicit is never bad, so I support that as a future improvement -- but that's not really the issue at hand that the user is reporting wrt groot handling of optional inputs

If you're saying the new groot handles, happy to close! We have some potential follow ups here on the BT.CPP side, but perhaps that's sensible in our other BT.CPPv4 thread.

Thanks! Sorry for the delay, I was in London on biz travel.

from navigation2.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.