BehaviorTree.CPP
BehaviorTree.CPP copied to clipboard
Bad Expected Access Error
This is likely to be user error, but I would appreciate your opinion.
BT::NodeStatus FlipCoin::tick() {
/* initialize random seed */
auto pb = getInput<std::string>("bias");
std::cout << "bias: " << stod(pb.value()) << std::endl;
double bias = 0.7;
BT::NodeStatus status;
this->f = this->getFlip();
if (this->f < bias) {
status = BT::NodeStatus::SUCCESS;
std::cout << "We won! " << this->f << std::endl;
} else {
status = BT::NodeStatus::FAILURE;
std::cout << "We lost! " << this-> f << std::endl;
}
return status;
}
double FlipCoin::getFlip() {
srand(time(NULL));
double f = rand() / double (RAND_MAX);
return f;
}
BT::PortsList FlipCoin::providedPorts() {
return {BT::InputPort<std::string>("bias")};
}
Main
int main() {
std::cout << "Hello, World!" << std::endl;
// We use the BehaviorTreeFactory to register our custom nodes
BehaviorTreeFactory factory;
// The recommended way to create a Node is through inheritance.
factory.registerNodeType<FlipCoin>("FlipCoin");
factory.registerNodeType<ApproachObject>("ApproachObject");
auto tree = factory.createTreeFromFile("../my_tree.xml");
tree.tickRoot();
return 0;
}
The XML
<root main_tree_to_execute = "MainTree">
<BehaviorTree ID = "MainTree">
<Sequence>
<Action ID="FlipCoin" name="flip_coin" bias="0.7" />
<Action ID="ApproachObject" name="approach_object" />
</Sequence>
</BehaviorTree>
</root>
And I get the error
/mnt/c/Users/b/CLionProjects/beetree/cmake-build-debug/beetree
Hello, World!
terminate called after throwing an instance of 'nonstd::expected_lite::bad_expected_access<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >'
what(): bad_expected_access
Process finished with exit code 134
Thank you!
I tried a minimal example and everything looks fine...
static const char* xml_text = R"(
<root main_tree_to_execute = "MainTree">
<BehaviorTree ID = "MainTree">
<Action ID="FlipCoin" name="flip_coin" bias="0.7" />
</BehaviorTree>
</root>
)";
class FlipCoin : public BT::SyncActionNode
{
public:
FlipCoin(const std::string& name, const NodeConfiguration& config):
SyncActionNode(name, config) {}
BT::NodeStatus tick()
{
auto pb = getInput<std::string>("bias");
std::cout << "bias: " << stod(pb.value()) << std::endl;
return BT::NodeStatus::SUCCESS;
}
static BT::PortsList providedPorts()
{
return { BT::InputPort<std::string>("bias") };
}
};
int main()
{
BehaviorTreeFactory factory;
factory.registerNodeType<FlipCoin>("FlipCoin");
auto tree = factory.createTreeFromText( xml_text );
tree.tickRoot();
return 0;
}
@buddha314 I have seen this issue when attempting to call getInput on a string that was not provided as a port by mistake. I don't see that error in your example code however, but I am just throwing that idea out there.
Thanks! I'll see if that opens up some ideas.
If you send me the entire code, I can try to reproduce the issue (my minimal code doesn't reproduce it)
any update on this? as I said, I am not able to reproduce this. I will close this for the time being. Feeel free to open it again
I got a similar issue with a tree containing a subtree containing an action. I had a blackboard value initialized in the tree, given to the action in the subtree by port remapping.
I got the exact same error
terminate called after throwing an instance of 'nonstd::expected_lite::bad_expected_access<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >'
what(): bad_expected_access
With some debugging I found that in utils/expected.hpp the error is getInput() failed because it was unable to find the key [server_name] remapped to [server_name]
. Maybe this error should be printed on a bad_expected_access ?
If anyone get the same error this was my issue and how i fixed it :
<BehaviorTree ID="BehaviorTree">
<SubTree ID="SubTreeMove" delay_msec="5000" num_attempts="3" server_name="/move_goal" target="{pos}"/>
</BehaviorTree>
<!-- ////////// -->
<BehaviorTree ID="SubTreeMove">
<Fallback>
<Action ID="MoveBaseAction" server_name="{server_name}" target="{target}"/>
<Delay delay_msec="{delay_msec}">
<RetryUntilSuccesful num_attempts="{num_attempts}">
<Action ID="MoveBaseAction" server_name="{server_name}" target="{target}"/>
</RetryUntilSuccesful>
</Delay>
</Fallback>
</BehaviorTree>
The tree above doesn't work. I had misunderstood how remapping between a tree and a subtree works.
If I understood correctly, the arguments inside the SubTree xml tag must be keys and not values. Therefore I can't give a value server_name="/move_goal"
because it will look for the key /move_goal
and won't find it. It's the same for the other parameter, for example {pos}
is a mistake as well and must be pos
.
I think this imply that all the keys listed in the remapping must be initialized before by a SetBlackboard action (or something similar).
So since I don't want to have 3 SetBlackboard actions before my SubTree I have to do the following :
<BehaviorTree ID="BehaviorTree">
<SubTree ID="SubTreeMove" target="pos"/>
</BehaviorTree>
<!-- ////////// -->
<BehaviorTree ID="SubTreeMove">
<Fallback>
<Action ID="MoveBaseAction" server_name="/move_goal" target="{target}"/>
<Delay delay_msec="5000">
<RetryUntilSuccesful num_attempts="3">
<Action ID="MoveBaseAction" server_name="/move_goal" target="{target}"/>
</RetryUntilSuccesful>
</Delay>
</Fallback>
</BehaviorTree>
The documentation helped a bit but maybe it would benefit to be a bit clearer on this topic.
On a side remark, I'm not sure this is in the scope of the issue, but I think it would be better if a SubTree act like a function with value arguments (with the brackets you can still give a key) instead of working like a function with pointer arguments. It would be easier to be able to set values in a SubTree xml tag (like in a function) instead of having to pass the values by key (reference) and thus having to set them before.
It definitely seems like there is something buggy going on. I'm getting the same issue with a very simple tree that breaks in only one specific scenario.
Here is my failing tree:
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<SendActionMsg commanded_action="START_OF_PATH" lights="false" />
</BehaviorTree>
</root>
Here are two trees that will run with no error that are almost identical:
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<SendActionMsg commanded_action="START_OF_PATH" lights="false" blades_active="false" />
</BehaviorTree>
</root>
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<SendActionMsg commanded_action="START_OF_PATH" blades_active="false" />
</BehaviorTree>
</root>
The order of the ports doesn't matter (same results). The tree will not run with "lights" when it doesn't have "blades_active" with it, but "blades_active" can be by itself. Both are declared the same way as bools. It seems like something is fragile and breaking here in the code. I would assume it's my code, but it seems like others have had this issue too.
It's inconsistent enough that adding or removing certain ports seems to mask the issue, so that's probably why those that have commented have been able to find workarounds. I have been able to find workarounds too, but this seems to be a problem with the BT code itself.
As simchanu29 mentioned, it would at least be good to expand the error message to be more clear on what is failing exactly.
Please provide the entire code in a ZIP file to allow me to reproduce the problem
Hello
I have the same issue. Any progress in this matter?
@Ztubben , please provide a way to reproduce the error. A self contained example, that I can compile and run, and I will be happy to address this this week.
It would be very helpful id @cameronschloer and @simchanu29 do the same.
As I said, I was never able to reproduce the issue mentioned by @buddha314
closing for inactivity