-
Notifications
You must be signed in to change notification settings - Fork 55
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
Disable automatic retreat #330
Conversation
Signed-off-by: Xiyu Oh <xiyu@openrobotics.org>
Signed-off-by: Xiyu Oh <xiyu@openrobotics.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on the fix but I feel the implementation should be as follows:
FleetUpdateHandle::set_task_planner_params()
should accept anstd::optional<rmf_traffic::Duration>
param.- Add a
TaskManager::retreat_to_charger(std::optional<rmf_traffic::Duration> duration)
method. If a value is provided this method will executermf_ros2/rmf_fleet_adapter/src/rmf_fleet_adapter/TaskManager.cpp
Lines 184 to 192 in a2269ab
mgr->_retreat_timer = mgr->context()->node()->try_create_wall_timer( std::chrono::seconds(10), [w = mgr->weak_from_this()]() { if (auto mgr = w.lock()) { mgr->retreat_to_charger(); } }); std::nullopt
, it will callmgr->_retreat_timer.reset()
to disable the timer. - Setting the task planner params or using the new setter in
FleetUpdateHandle
will invoke the method in 2. This would allow for more efficient processing as if the check is not needed, the timer callback will not execute thereby saving some cycles for the ROS 2 executor.
/// Get whether or not to trigger automatic retreat to charger. | ||
bool retreat_to_charger() const; | ||
|
||
/// Set whether or not to trigger automatic retreat to charger. | ||
void set_retreat_to_charger(bool value); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think these APIs should be added here. Instead they should be present in FleetUpdateHandle
instead. Users who rely on EasyFullControl
API can get a FleetUpdateHandler
handler using the EasyFullControl::more() API and set this config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment below on setting/getting this value as an std::optional<rmf_traffic::Duration>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, what is stopping us from allowing this to be parsed in automatically via FleetConfiguration? This API is used within set_task_planner_params
to retrieve the configured values. Without it, users will have to modify the default value from the fleet adapter implementation itself.
@@ -1628,6 +1628,10 @@ void TaskManager::retreat_to_charger() | |||
|
|||
if (!task_planner->configuration().constraints().drain_battery()) | |||
return; | |||
if (!task_planner->configuration().constraints().retreat_to_charger()) | |||
return; | |||
if (_idle_task && _idle_task->request_type() == "Charge") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't have comparison to magic stings like this. The rmf_task::Request
class should have a virtual static member function that should return the request type. Then you can call _idle_task && _idle_task->request_type() == ParkRobotIndefinitely::request_type()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the proposed refactor, we no longer rely on checking request types.
@@ -308,7 +313,8 @@ class FleetUpdateHandle : public std::enable_shared_from_this<FleetUpdateHandle> | |||
double recharge_threshold, | |||
double recharge_soc, | |||
bool account_for_battery_drain, | |||
rmf_task::ConstRequestFactoryPtr finishing_request = nullptr); | |||
rmf_task::ConstRequestFactoryPtr finishing_request = nullptr, | |||
bool retreat_to_charger = true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be a bool. Instead it should be the timer period. If this is set to std::nullopt
, we reset the timer thereby disabling the automatic retreat to charger behavior. This way we not only expose the ability to enable/disable this feature but also allow users to configure the rate at which the check happens. Else we will need to add another parameter for that.
The docstring above should also be updated and it's worth mentioning the timer there so users know how this check is performed.
bool retreat_to_charger = true); | |
std::optional<rmf_traffic::Duration> check_retreat_to_charger_interval = rmf_traffic::time::from_seconds(10)); |
Signed-off-by: Xiyu Oh <xiyu@openrobotics.org>
Signed-off-by: Xiyu Oh <xiyu@openrobotics.org>
Signed-off-by: Xiyu Oh <xiyu@openrobotics.org>
Signed-off-by: Xiyu Oh <xiyu@openrobotics.org>
Signed-off-by: Xiyu Oh <xiyu@openrobotics.org>
Updated according to the changes requested, without the check for the fleet's configured idle task before deciding whether to proceed with the automatic retreat to charger. I'll work on that in a separate PR. |
Signed-off-by: Michael X. Grey <mxgrey@intrinsic.ai>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made some changes to prevent the API from breaking and for a few other nitpicky reasons.
I've left in-line comments as part of this review to explain the changes that are being made, but no further action is needed.
@@ -568,6 +574,7 @@ class EasyFullControl::FleetConfiguration | |||
double recharge_threshold, | |||
double recharge_soc, | |||
bool account_for_battery_drain, | |||
std::optional<rmf_traffic::Duration> retreat_to_charger_interval, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a field to the constructor breaks the API in a way that isn't backwards compatible.
We should leave this argument out of the constructor and instead provide a set_retreat_to_charger_interval(std::optional<rmf_traffic::Duration>)
member function.
We could also consider putting this as the last argument in the constructor and giving it a default value. That would probably be an ABI break, but we can probably have some flexibility on that, as opposed to breaking the API which we should not do for anything less serious than a security vulnerability.
@@ -1753,7 +1743,33 @@ std::function<void()> TaskManager::_make_resume_from_waiting() | |||
} | |||
|
|||
//============================================================================== | |||
void TaskManager::retreat_to_charger() | |||
void TaskManager::retreat_to_charger( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is somewhat of a nitpick, but I don't like that we're changing the meaning of the retreat_to_charger
function. I think I'd prefer we keep the current retreat_to_charger
function as it was, and introduce a new function called configure_retreat_to_charger(std::optional<rmf_traffic::Duration>)
.
} | ||
else | ||
{ | ||
const auto retreat_to_charger_interval_sec = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parsing logic doesn't seem very sound to me.
This assumes that if a value is given for retreat_to_charger_interval
then it will definitely be a double. I believe this line would throw an exception if it's not a double. We should endeavor to return std::nullopt
from this function in cases where things cannot be parsed correctly instead of throwing an exception.
Also this treats values of 0.0
as null, which is ... not an unusual convention historically speaking, but I think it's a practice that should be left behind. Instead we should support the user providing a yaml null
value for cases where they want to turn off this behavior.
@@ -45,6 +45,7 @@ | |||
|
|||
#include <rmf_task_sequence/phases/SimplePhase.hpp> | |||
|
|||
#include <iostream> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this was put in for debugging and not needed anymore.
@@ -308,7 +314,8 @@ class FleetUpdateHandle : public std::enable_shared_from_this<FleetUpdateHandle> | |||
double recharge_threshold, | |||
double recharge_soc, | |||
bool account_for_battery_drain, | |||
rmf_task::ConstRequestFactoryPtr finishing_request = nullptr); | |||
rmf_task::ConstRequestFactoryPtr finishing_request = nullptr, | |||
std::optional<rmf_traffic::Duration> retreat_to_charger_interval = std::nullopt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This default value isn't backwards compatible. An old fleet adapter that was using the API as it used to be will unintentionally turn off the retreat behavior after updating to this version of the library.
Since we have a separate function for modifying the interval, let's just keep this fully separate and remove this argument.
if (_retreat_timer) | ||
_retreat_timer->reset(); | ||
_retreat_timer = _context->node()->try_create_wall_timer( | ||
duration.value(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not checking if duration <= 0, which could cause the timer to behave in ways we don't actually want. We should issue an error message in that situation.
|
||
/// Set whether or not to trigger automatic retreat to charger with a | ||
/// duration between checks for automatic retreat. | ||
FleetUpdateHandle& retreat_to_charger_interval( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overloading the function name makes it messy to produce python bindings, so let's add set_
in front of this function.
* Add retreat_to_charger param Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> * If idle task is charge, do not retreat to charger Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> * Use duration instead of boolean for retreat to charger Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> * Undo adding request type Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> * Change retreat to timer from bool to optional duration Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> * Store param in FleetUpdateHandle Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> * Uncrustify and remove request_type from ChargeBattery Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> * Tweak some details and remove API breakages Signed-off-by: Michael X. Grey <mxgrey@intrinsic.ai> * Fix style Signed-off-by: Michael X. Grey <mxgrey@intrinsic.ai> --------- Signed-off-by: Xiyu Oh <xiyu@openrobotics.org> Signed-off-by: Michael X. Grey <mxgrey@intrinsic.ai> Co-authored-by: Michael X. Grey <mxgrey@intrinsic.ai> Co-authored-by: Grey <grey@openrobotics.org> Signed-off-by: Arjo Chakravarty <arjoc@google.com>
This PR aims to
retreat_to_charger
configurable from the fleet config, andretreat_to_charger
from being triggered if the robot's finishing task is already a Charge taskWe ran into scenarios where the robot is on its way back to the charger (as part of the finishing task) while its battery level is nearing the recharge threshold. This sometimes triggers a retreat to charger that overrides the finishing task. As a result, the robot is unable to perform other tasks queued later on until its current battery SOC reaches the recharge SOC.
In the
retreat_to_charger
callback, we now check the fleet's configured behavior before initiating automatic retreat.This depends on open-rmf/rmf_task#114