Skip to content
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

Bring MPC to the new flight stack #60

Merged
merged 8 commits into from
May 10, 2018
Merged

Bring MPC to the new flight stack #60

merged 8 commits into from
May 10, 2018

Conversation

foehnx
Copy link
Contributor

@foehnx foehnx commented Apr 25, 2018

I made some changes to allow compatibility with our new MPC.
It includes mainly templating the autopilot on the controller type and parameter type, which requires the autopilot.cpp to move to the header file, solved as a head include.

Further changes were also mentioned in #5 and we concluded that references are always given in the form of a Trajectory (and no longer TrajectoryPoint) to the controller.
The position controller would then just take the first point in it, while the MPC can use the first (for a single reference) or a whole lookahead on a trajectory.

I made several changes and would be happy to hear your comments.

@Internals: also take a look at: uzh-rpg/rpg_mpc#5

@foehnx foehnx self-assigned this Apr 25, 2018
@foehnx foehnx requested review from tcies and kohlerj April 25, 2018 14:25
@@ -857,7 +878,7 @@ quadrotor_common::ControlCommand AutoPilot::start(
}

if (timeInCurrentState() > optitrack_start_land_timeout_
|| reference_state_.position.z() >= optitrack_start_height_)
|| state_estimate.position.z() >= optitrack_start_height_)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the change to state_estimate from reference_state ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats the intention behind checking what the reference height is? Doesn't it make more sense to check what your actual height is and cancel the take-off once you reached this height?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you look further in the function the reference is moved up and up as the loop is repeated. I would say that using the old method makes it more robust and smoother but this is only a feeling. By that I mean, hover WILL be reached even if you have an offset for idk which reason.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So ideally the drone does what the reference tells it to, and in that case it does not make much of a difference. However, if e.g. the drone has a wrong thrust mapping and flies much lower than the reference, when using the state estimate, it will go up until it reached the start height (with a reference much higher) but then when it switches back to hover the reference is set to the current state estimate and the drone will drop by that much again which also does not result in the desired height. So by checking the reference height at least we get a smooth behavior in this case. Anyhow, if the drone does not follow the reference well it needs to be fixed...
Bottom line: I would change this back to reference state

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There you go, the reason I was searching for! Make sense to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, clarification:
When using the MPC, it lags behind since your take-off maneuver has a rising position, fixed velocity but zero acceleration and hover thrust, which is unfeasible at the beginning of the start maneuver.
This is no problem for feasible control with the MPC, but it means that the it lags behind due to the compromise of positon-, velocity-, acceleration- and thrust-error.

Possible solution:

  1. Ignore ~0.15m z-offset after start.
  2. Add a takeoff acceleration (which could be a parameter) at the beginning of the start maneuver.


reference_trajectory_ = quadrotor_common::Trajectory();
reference_trajectory_.trajectory_type =
quadrotor_common::Trajectory::TrajectoryType::GENERAL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick question, how about a constructor with the type as argument for the class quadrotor_common::Trajectory() ? to avoid code duplication. We could even have a constructor with one point as argument and automatically defined it as a general trajectory. It would make sense since we change the interface completely (i mean from point to trajectory in the run command...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree! Will do it tomorrow!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also agree ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quadrotor_common::ControlCommand AutoPilot::executeTrajectory(
template <typename Tcontroller, typename Tparams>
quadrotor_common::ControlCommand
AutoPilot<Tcontroller, Tparams>::executeTrajectory(
const quadrotor_common::QuadStateEstimate& state_estimate,
ros::Duration* trajectory_execution_left_duration,
Copy link
Contributor

@kohlerj kohlerj May 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general comment: really, a pointer to a ros::Duration and int ?!? ---> how about a smart pointer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meh... lets make it pass-by-reference!
then there's no pointer magic but still avoiding copying, ok?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it is our convention that arguments which are changed by the function are passed as pointers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conventions are here to be respected. Ok

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, mark as done


std::list<quadrotor_common::TrajectoryPoint>::const_iterator it_points;
std::list<quadrotor_common::Trajectory>::const_iterator it_trajectories;
bool lookahead_reached(false);
Copy link
Contributor

@kohlerj kohlerj May 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • could you comment the code, basic idea behind the heuristic (i'm lazy but so will be the next person working on it)
  • should it not be a separate function like mpc?
  • could we use specialization for these functions that change a lot ? I mean a definition for execute(mpc controller templated) and for execute(normal controller) ... Idk if it's possible but I think so. see here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3rd bullet: nope... if so we need to specify the template type in here... then we need the type at compile time.
but this is what we want to avoid, to be able to compile rpg_quadrotor_control without rpg_mpc.
I will think about making it more readable and understandable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look at this in more detail later then

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@foehnph Agreed for the 3rd bullet, you are right!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok temporary solution:
I commented the code there to make it understandable what it does.
I think this should be a separate class, like autopilot::Tracker, the trajectory queue could be passed as reference and it can have time-based tracking and spacial tracking, as well as restrictions to forward-only tracking (can speed up iterations massively).
Additionally it could also handle the trajectory queue if wanted, but I guess it's easier to leave that in the autopilot.

Copy link
Contributor

@mfaessle mfaessle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of comments but first of all thanks for this effort!

@@ -3,7 +3,8 @@
int main(int argc, char **argv)
{
ros::init(argc, argv, "autopilot");
autopilot::AutoPilot autopilot;
autopilot::AutoPilot<position_controller::PositionController,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also make the includes for the PositionController and PositionControllerParams in this file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -228,3 +231,5 @@ class AutoPilot
};

} // namespace autopilot

#include "./autopilot_inl.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No newline at end of file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -6,7 +6,7 @@ start_land_velocity: 0.5 # [m/s]
start_idle_duration: 2.0 # [s]
idle_thrust: 2.0 # [m/s]
optitrack_start_height: 1.0 # [m]
optitrack_start_land_timeout: 5 # [s]
optitrack_start_land_timeout: 6 # [s]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this this parameter change in this pull request?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry was testing... undone

@@ -27,3 +27,4 @@ emergency_land_thrust: 9.0 # [m/s^2]

control_command_input_timeout: 0.1 # [s]
enable_command_feedthrough: false
predictive_control_lookahead: 2.0 # [s]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No newline at end of file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -27,3 +27,4 @@ emergency_land_thrust: 9.0 # [m/s^2]

control_command_input_timeout: 0.1 # [s]
enable_command_feedthrough: true
predictive_control_lookahead: 2.0 # [s]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new line at end of file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

quadrotor_common::ControlCommand AutoPilot::executeTrajectory(
template <typename Tcontroller, typename Tparams>
quadrotor_common::ControlCommand
AutoPilot<Tcontroller, Tparams>::executeTrajectory(
const quadrotor_common::QuadStateEstimate& state_estimate,
ros::Duration* trajectory_execution_left_duration,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it is our convention that arguments which are changed by the function are passed as pointers.

@@ -1147,20 +1222,57 @@ quadrotor_common::ControlCommand AutoPilot::executeTrajectory(
*trajectory_execution_left_duration = ros::Duration(0.0);
*trajectories_left_in_queue = 0;
trajectory_queue_.pop_front();
setAutoPilotState(States::HOVER);
return base_controller_.run(state_estimate, reference_state_,
setAutoPilotStateForced(States::HOVER);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be forced to avoid jumpy behavior if for whatever reason the trajectory ends with a non zero velocity. So by not forcing it will do a smooth breaking if necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but the you do not guarantee that you reach the end state...
the end of a trajectory normally has zero velocity ;-) and even if not it just means that you get to a stop with an offset where the velocity error is compensated by the position error.

I propose to change setAutoPilotStateForced() so that it sets reference state velocity to zero when trigger to hover.

base_controller_params_);
}
else
{
time_start_trajectory_execution_ +=
trajectory_queue_.front().points.back().time_from_start;
trajectory_queue_.front().points.back().time_from_start;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw a few of those... Detail but this is just a thing because of non equal auto formatting which doesn't hurt but is also not necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use two spaces for tabs... so if I see it I change it :-)


std::list<quadrotor_common::TrajectoryPoint>::const_iterator it_points;
std::list<quadrotor_common::Trajectory>::const_iterator it_trajectories;
bool lookahead_reached(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look at this in more detail later then

@@ -137,10 +138,11 @@ class AutoPilot

state_predictor::StatePredictor state_predictor_;

position_controller::PositionController base_controller_;
position_controller::PositionControllerParams base_controller_params_;
Tcontroller base_controller_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I named this base controller because I thought that there might be new controllers that are only used for certain tasks but some of the basic tasks are always executed with the base controller (like start land etc.). @foehnph would something like this make sense (and then have two controller instances) or not?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @mfaessle, it makes it easier for you @foehnph since you don't need to implement the velocity mode in mpc, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really... then you would have to switch between controllers, implement state machine for that and generally reimplement a shitload of things if you want to use the autopilot with the new controller and not just have a different controller in feedthrough...

@mfaessle
Copy link
Contributor

mfaessle commented May 2, 2018

About transforming the cpp file into a header... I never used templates myself but maybe @tcies has some comments about naming conventions etc of such files.

Copy link
Contributor

@kohlerj kohlerj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See new comments

@foehnx
Copy link
Contributor Author

foehnx commented May 3, 2018

@mfaessle the autopilot_inl.h is done according to @tcies proposed convention

@foehnx
Copy link
Contributor Author

foehnx commented May 4, 2018

updated rpg_quadrotor_common with new Trajectory constructor, so...
@rpg-jenkins test this please

@foehnx
Copy link
Contributor Author

foehnx commented May 9, 2018

can someone approve this please?

Copy link
Contributor

@kohlerj kohlerj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@@ -877,16 +899,27 @@ quadrotor_common::ControlCommand AutoPilot::start(
+ start_land_velocity_
* (timeInCurrentState() - start_idle_duration_);
reference_state_.velocity.z() = start_land_velocity_;
if(timeInCurrentState() < start_idle_duration_ +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a hack since the velocity does not change with acceleration over time. But as long as it works for both controllers I can live with it ;) The nicest way would be if it would be a real trapezoidal velocity profile during the start maneuver.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna change that, test in simulation and request an approve again

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened an issue regarding this (#64). Feel free to adress it in a new pull request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already done here

@@ -877,16 +899,29 @@ quadrotor_common::ControlCommand AutoPilot::start(
+ start_land_velocity_
* (timeInCurrentState() - start_idle_duration_);
reference_state_.velocity.z() = start_land_velocity_;
if(timeInCurrentState() < start_idle_duration_ +
start_land_velocity_/start_land_acceleration_)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spaces around arithmetic symbols please

@foehnx
Copy link
Contributor Author

foehnx commented May 9, 2018

finally happy? I'll merge tomorrow morning... ;-)

@foehnx foehnx merged commit c93155e into master May 10, 2018
@mfaessle mfaessle deleted the dev/new_interface branch June 7, 2018 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants