-
Notifications
You must be signed in to change notification settings - Fork 21
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
Mission handler #331
Mission handler #331
Conversation
…to get rid of references in waypoint class
… to mission planner handler
float radius; | ||
if (!waypoint_.radius(radius)) | ||
{ | ||
radius = 0.0f; |
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 useless since waypoint.radius() is already setting the radius to zero in case no radius correspond to that type of waypoint
/******************** | ||
Determine status code | ||
********************/ | ||
if (waypoint_.autocontinue() == 1 && is_landed_) |
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 am still not sure I understood why we have this check on autocontinue to determine if mission is finished or not !?
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.
Sounds like copy paste error. I would even think the mission is finished if we landed and the waypoint is not autocontinue
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.
When you land through the landing handler, the drone will disarm automatically, which means that the next iteration, the drone will switch to standby.
Autocontinue is used to determine if the drone should start to handle the next waypoint. Because when we land through the button, I assumed that we want the mission to be over so I made the button not be autocontinue. That means that the handler will not change to the interrupted waypoint in the list and will just switch to standby later. The handlers don't have to finish, they can be interrupted.
If autocontinue is set to on, then the drone will switch to standby in two methods based on how the landing waypoint was created. If the landing was a part of the mission, it will just switch to standby. If the mission was interrupted through a button or something, it will setup the interrupted waypoint again and then overwrite it with standby next iteration (this due to the drone resuming the mission after an inserted waypoint has been completed).
I left the autocontinue in there as I could see the mission plan requiring more than one landing and takeoff (e.g. delivery of goods). In that case, you would have the drone land with autocontinue on into some new mission item such as release goods and then takeoff or something. Of course, the mission planner will need to be modified a bit to allow mission items to be handled when the drone has disarmed and to not force the drone into standby after landing.
If you'd prefer, the entire if (autocontinue && is_landed_) { return MISSION_FINISHED; }
part can be removed and then it would just go to standby next iteration with no check of autocontinue.
|
||
// Determine distance to the waypoint | ||
local_position_t wpt_pos = waypoint_.local_pos(); | ||
float xy_radius_sqr = wpt_pos[Z]*wpt_pos[Z]*0.16f; |
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.
something weird here, isn't it ?
xy_dist2wp_sqr = vectors_norm_sqr(rel_pos); | ||
|
||
// Determine if finished | ||
if (xy_dist2wp_sqr <= xy_radius_sqr && ins_.position_lf()[Z] <= 0.9f * wpt_pos[Z]) |
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 weird as well !
0.9f should be a parameter at least,
But what happen if you are upper than this limit for some reason ?
Don't you want to use maths_fabs(ins_.position_lf()[Z] - wpt_pos[Z]) <= takeoff_acceptance_range_ ?
} | ||
|
||
// Return true if waiting at waypoint and autocontinue | ||
if (finished && waypoint_.autocontinue() == 1) |
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.
idem here , why autocontinue ?
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.
It is needed because when the waypoint is not autocontinue, we want to hover on the waypoint after take-off. By returning MISSION_IN_PROGRESS, the handler will be called next time to keep hovering on waypoint.
However I still believe the autocontinue field should be tested outside handlers... That would make them much simpler, and less error-prone.
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 could check the autocontinue field in Mission_planner.
update current handler
if current handler is finished
| if waypoint is autocontinue
| | fetch next waypoint and next handler
| else
| | insert hover waypoint and fetch handler
| endif
endif
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.
If autocontinue is off, you don't want the drone to advance to the next mission item.
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.
yes my bad, I fixed my comment
(comment still valid though)
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.
If we check the autocontinue in Mission_planner, it would reduce some flexibility. For example, if we want to ignore the autocontinue flag for some reason (like a timeout if no commands have been received within a set time), the handler could advance anyways.
Though as you said, autocontinue checks within the mission planner would make it less error prone.
break; | ||
case MAV_CMD_OVERRIDE_GOTO: | ||
return MISSION_FINISHED; | ||
} |
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.
don't you want to add a default case ?
float radius; | ||
if (!waypoint_.radius(radius)) | ||
{ | ||
radius = 4.0f; |
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 4.0f should be a parameter
if (waypoint_reached_) | ||
{ | ||
// Then ensure that we are in autocontinue | ||
if ((waypoint_.autocontinue() == 1) && (waypoint_handler_.waypoint_count() > 1)) |
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.
idem autocontinue
& why do you check if there is more than 1 waypoint to know if mission is finished ?
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.
The check for the waypoint count is to not uselessly advance to the same waypoint that you're at. If there's only 1 waypoint and we just arrived at it, should we be advancing to that same waypoint.
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.
sounds like a very common thing to check, IMHO it would make more sense in the planner
if (mode_local.is_guided()) | ||
{ | ||
mission_planner->critical_handler(); | ||
} |
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.
else we just crash ?
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.
Is guided is set only during hold position and auto. If it's not guided we are in attitude or velocity which has the pilot controlling the drone.
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 am not really comfortable with this middle ground approach.
The two tasks mission_planner and main_task are both writing into the controller, but only in certain modes.
- It is very difficult to be sure at one point who wrote into the controller
- we have to make sure that these modes do not overlap, in which case the behaviour is undefined and depend on which task is run first.
- we also have to make sure there is no gap between these sets of modes, in which case the drone would simply do nothing and crash.
It would be much safer and easy to read if we had a single point where commands are written to the controller.
I also fear -- that because of all the edge cases in on ground, paused, critical, and manual states -- mission_planner is growing more than expected, and that we do not gain much in readability compared to our beloved waypoint_handler_state_navigation_t
.
Solution A: Mission planner is responsible
The two tasks would be sensing_plus_cascade_controller_update()
and mission_planner.update()
. (best to keep the two separate to allow different update freqs)
Mission_planner
would check which mode we are in, then call the appropriate handler.
A new Manual_handler
would contain the code we have now in main task.
Solution B: Main task is responsible
Still two tasks: Mission_planner::update()
and LEQuad::main_task()
Mission_planner
would be yet another source of command. It does not directly write into the controller. But it has a method to get its desired command. In auto mode, LEQuad::main_task()
reads the desired command from Mission_planner
, and writes it into the controller. In other modes, LEQuad::main_task()
reads from remote and writes into the controller.
Solution C: Big brother
This is kind of a mix of A and B.
The scope of Mission_planner
is reduced to autonomous mode only, and mission only. No critical handler, no paused state, no position_hold mode. Handlers do not write into a controller by themselves, but they have a method to return the desired command.
A new Critical_handler
class is created, it is responsible for everything related to critical state. It can contains a small list of waypoints that it fills based on the desired behaviour. It can use the same Mission_handlers
as Mission_planner
. Same as Mission_planner
, it does not directly know the controller, but can give its desired command.
A new Critical_detector
class is created. Its only purpose is to check various aspects of the drone (battery, fence, connexion to GCS...), and indicate which critical state we are in, or if everything is fine.
A Manual_handler
is created as for solution A
The Big_brother
module contains all of them. It can be configured by filling it with a list of mission_handlers, by specifying the type of critical handler to use, the type of critical detector, the type of manual handler, and the type of controller to use.
In its update loop, it will check the current mav mode. And check the critical state using its Critical_detector
member. It will call the update of either Manual_handler
, Mission_planner
or Critical_handler
. Ask them the desired command and give it to the controller (single entry point of the controller).
The two tasks would be big_brother_update
(relatively slow) and sensing_plus_cascade_controller_update
(high speed)
I tend towards C. But if you ask short term solution, I think solution B would be the easier to debug, and later easier to bend towards solution C. What is your opinion @GregoireH @basil-huber ?
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 also prefer solution C
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.
Speaking of this, I took a look at the code again and we are guided if in velocity control as well. I did add a check in the critical handler to make sure we are in auto or hold position, but if that was not there, there would be two modules competing for the control command. This is a good argument for your Solution C as well, putting the decision for who has control within only one module.
Fixes Issue #306.
This is still a work in progress but there have been several major changes to the Mavlink_waypoint_handler class as well as the creation of several other classes.
Changes that have been made already:
Waypoint::send()
function and passing in the appropriate arguments.Mavlink_waypoint_handler::current_waypoint()
,Mavlink_waypoint_handler::next_waypoint()
, andMavlink_waypoint_handler::waypoint_from_index(int i)
.Mavlink_waypoint_handler::advance_to_next_waypoint()
.hold_waypoint_
andhold_waypoint_set_
that should be set whenever the hold position needs to be changed. As they are private, these subclasses will therefore not have access to it but can manipulate them with the functionsreset_hold_waypoint()
,hold_waypoint_set()
,set_hold_waypoint(local_position_t hold_position)
,set_hold_waypoint(local_position_t hold_position, float heading)
,set_hold_waypoint(Waypoint wpt)
, andhold_waypoint()
. These functions will automatically control both private variables. If something tries to access the hold_waypoint before it has been set (or after it has been reset), it will return the local position of the drone and set the hold waypoint.goal()
andset_goal(Waypoint wpt)
.internal_state()
andset_internal_state(internal_state_t new_internal_state)
. The set internal state will automatically output a debug message of a state change.Things that still need to be changed:
Some recommendations/comments would be very helpful.