Skip to content

Runtime Error| Any::copyInto fails when Remapping ports between subtrees #530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ephson24 opened this issue Mar 20, 2023 · 7 comments
Closed
Assignees

Comments

@ephson24
Copy link

ephson24 commented Mar 20, 2023

Hi Davide,
I am facing this issue and can't seem to figure out a solution. I have two subtrees (TreeA and TreeB) as children of a parallel node. The main idea is that TreeA receives user input, processes it and outputs the results in an output variable "request_o".
XML of sub-TreeA:

<BehaviorTree ID="UserActivityT">
  <ReactiveFallback>
    <IsValidActivity request_i="{UserRequest}"
                     _onSuccess="hasTask:=true"/>
    <RegisterActivity request_o="{UserRequest}"/>
    <Continue/>
  </ReactiveFallback>
</BehaviorTree>

TreeB uses the output from TreeA to decide the next cause of action.
XML of sub-TreeB:

<BehaviorTree ID="MapManagerT">
 <ReactiveSequence>
   <Script code=" isMapping:=false; hasTask:=false; UserRequest:='0;0;0;0;0;0;0;0;0' "/>
    <IsMapActivity request="{UserRequest}"
                   trigger="{hasTask}"/>
  </ReactiveSequence>
</BehaviorTree>

The the main tree containing the parallel node is composed as follows:

<BehaviorTree ID="GenericT">
    <Parallel failure_count="2"
              success_count="-1">
      <Script code=" hasTask:=false; UserRequest:='0;0;0;0;0;0;0;0;0' "/>
      <SubTree ID="UserActivityT" hasTask="{hasTask}" UserRequest="{UserRequest}"/>
      <SubTree ID="MapManagerT" hasTask="{hasTask}" UserRequest="{UserRequest}" />
    </Parallel>
  </BehaviorTree>

The programs runs if I comment out either one of the subtrees but fails with this error (after ticking once) otherwise:

[ INFO] [1679304221.514799260]: Processing Request ...
terminate called after throwing an instance of 'std::runtime_error'
  what():  Any::copyInto fails

This is my CPP structure being used:

struct RequestData_s
{
  RequestData_s()
  {
    cmd = map_id = msn_id = num_captures = loop_count = delay = 0;
    loop_once = false;
    map_name = map_desc = "";
    time = ros::Time::now();
  }
  RequestData_s(const RequestData_s &data)
  {
    cmd = data.cmd;
    map_id = data.map_id;
    msn_id = data.msn_id;
    num_captures = data.num_captures;
    loop_count = data.loop_count;
    loop_once = data.loop_once;
    delay = data.delay;
    map_name = data.map_name;
    map_desc = data.map_desc;
    time = data.time;
  }

  int cmd, map_id, msn_id, num_captures, loop_count, delay;
  bool loop_once;
  std::string map_name, map_desc;
  ros::Time time;
};

This is my BT Template definition for the corresponding structure:

namespace BT
{
  template <> inline RequestData_s convertFromString(StringView str)
  {//! cmd; map_id; map_name; map_desc; mission_id; loop_once; delay; num_capts; loop_count
    auto parts = splitString(str, ';');
    if(parts.size() != 9)
      throw RuntimeError("invalid input - requires 9 data points");
    else
    {
      RequestData_s output;
      output.cmd = convertFromString<int>(parts[0]);
      output.map_id = convertFromString<int>(parts[1]);
      output.map_name = parts[2];
      output.map_desc = parts[3];
      output.msn_id = convertFromString<int>(parts[4]);
      output.loop_once = convertFromString<bool>(parts[5]);
      output.delay = convertFromString<int>(parts[6]);
      output.num_captures = convertFromString<int>(parts[7]);
      output.loop_count = convertFromString<int>(parts[8]);
      return output;
    }
  }
} //end namespace BT`

I am not sure what I am doing wrong. It would be nice if you can shed some light on this issue since the error output is not very informative to aid in finding a solution.

@facontidavide
Copy link
Collaborator

  1. I had to update your message to make the code readable, please use the proper code block syntax 😉
  2. thanks for reporting, I will have a look

@facontidavide
Copy link
Collaborator

facontidavide commented Mar 20, 2023

Any::copyTo fails when copying between non-compatible types and it is used ONLY in Scripts.

Therefore, I have the feeling that it is related to UserRequest:='0;0;0;0;0;0;0;0;0' trying to convert from RequestData_s to std::string.

  • Is this something specific of the Parallel node? Could the same error be replicated with Sequence? If you confirm, I will create a unit test to reproduce this.

  • Also, it is not clear to me why you use Parallel here. My interpretation is that UserActivityT and MapManagerT must stay in RUNNING mode simultaneously, but I think that you should explain to me your intent.

  • Are you sure that what you want isn't this. i.e. Script being executed only once, before the Parallel? Arguably, it should be the same, tough.

<BehaviorTree ID="GenericT">
   <Sequence>
   <Script code=" hasTask:=false; UserRequest:='0;0;0;0;0;0;0;0;0' "/>
      <Parallel failure_count="2" success_count="-1">
         <SubTree ID="UserActivityT" hasTask="{hasTask}" UserRequest="{UserRequest}"/>
         <SubTree ID="MapManagerT" hasTask="{hasTask}" UserRequest="{UserRequest}" />
      </Parallel>
   <Sequence>
</BehaviorTree>

@facontidavide
Copy link
Collaborator

Also, I am not sure that this looks good:

<BehaviorTree ID="MapManagerT">
 <ReactiveSequence>
    <Script code=" isMapping:=false; hasTask:=false; UserRequest:='0;0;0;0;0;0;0;0;0' "/>
    <IsMapActivity request="{UserRequest}"  trigger="{hasTask}"/>
  </ReactiveSequence>
</BehaviorTree>

This means that at EACH tick, we reset hasTask to false and UserRequest to zeros. Also IsMapActivity sounds like a synchronous action, therefore using ReactiveSequence seems pointless.

@ephson24
Copy link
Author

ephson24 commented Mar 20, 2023

Therefore, I have the feeling that it is related to UserRequest:='0;0;0;0;0;0;0;0;0' trying to convert from RequestData_s to std::string.

I think so too but as you can see the syntax for the struct as well as its corresponding template is ok. What I don't seem to understand is that if I run the MapManagerT alone. It works. I would assume that if there was an issue with the conversion from RequestData_s to std::string, it should appear here as well right?

Is this something specific of the Parallel node? Could the same error be replicated with Sequence? If you confirm, I will create a unit test to reproduce this.

Yes. Changing the parent from Parallel to Sequence node makes no difference and I get the same error output.

Also, it is not clear to me why you use Parallel here. My interpretation is that UserActivityT and MapManagerT must stay in RUNNING mode simultaneously, but I think that you should explain to me your intent.

Your interpretation is on point. I intend to have UserActivityT and MapmanagerT running simultaneously in order to be able to process user requests and also have the robot performing any previously received input at the same time. I know UserActivityT doesn't make a lot of sense as it is shown here but the final tree is also going to have EmergencyT and PowerManagerT in RUNNING mode simultaneously so as to be able to interrupt the current operation should the emergency button be triggered or the battery level go below a certain level. If you can recommend an alternative way to achieve a similar effect, I will be willing to try it out.

Are you sure that what you want isn't this. i.e. Script being executed only once, before the Parallel? Arguably, it should be the same, tough.

You are right about this. The Script should only be executed once. I will re-organize the stack as shown.

@ephson24
Copy link
Author

Also, I am not sure that this looks good:

<BehaviorTree ID="MapManagerT">
 <ReactiveSequence>
    <Script code=" isMapping:=false; hasTask:=false; UserRequest:='0;0;0;0;0;0;0;0;0' "/>
    <IsMapActivity request="{UserRequest}"  trigger="{hasTask}"/>
  </ReactiveSequence>
</BehaviorTree>

This means that at EACH tick, we reset hasTask to false and UserRequest to zeros. Also IsMapActivity sounds like a synchronous action, therefore using ReactiveSequence seems pointless.

That was a setup I used for testing the subtree alone. The final subtree has no Script tag in it. That was my fault.

Regarding IsMapActivity, yes that is a synchronous node. But that tree is just an extract from the actual tree. The complete MapManagerT has many other nodes that can return RUNNING hence the reason I use a ReactiveSequence. I don't know if that makes any sense but that's what seemed logical considering I want some nodes like IsMapActivity to always be ticked.

@facontidavide
Copy link
Collaborator

Ok, I need to find a succinct unit test to reproduce the error. I think there is an error somewhere, but also that you may express your logic in a simpler way.

I will let you know if I find anything

@facontidavide
Copy link
Collaborator

facontidavide commented Mar 21, 2023

Problem fixed. A very simple example was sufficient to reproduce it:

  <BehaviorTree ID="MainTree">
    <Sequence>
      <Script code=" pose:='1;2;3' "/>
      <ModifyPose pose="{pose}"/>
      <Script code=" pose:='1;2;3' "/>
    </Sequence>
  </BehaviorTree>

Also, I added a MUCH more informative error message.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants