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

Quaternion based attitude control #8003

Merged
merged 10 commits into from
Mar 15, 2018
Merged

Quaternion based attitude control #8003

merged 10 commits into from
Mar 15, 2018

Conversation

MaEtUgR
Copy link
Member

@MaEtUgR MaEtUgR commented Sep 23, 2017

Introduction: I had the plan to port and contribute the quaternion based attitude controller I wrote for my master thesis running on PX4 for too long now. I guess it was a big mistake to wait for PX4/PX4-Matrix#34 to be merged which was pending for almost a year now. I was just too pigheaded for the incorrect quaternion convention because of a dramatic experience in the past. It's fixed and merged to PX4 with #7908 now and hence I started my work.

Documentation/Motivation: Here's a really good paper documenting the underlying math behind this type of attitude control which is very similar but still far from equal to the well known rotation matrix based algorithm by Kumar et al..
https://www.research-collection.ethz.ch/bitstream/handle/20.500.11850/154099/eth-7387-01.pdf

I'm also unhesitant to share my master thesis for further documentation. It contains a hopefully even easier to read in depth text description of my point of view and includes my findings. Just let me know if and where it should be hosted.

**State:**I started now by writing and testing the general quaternion attitude control law which with the current setpoint generation should generate the same result as running only the full attitude control of the paper and does not have any notion of reducing yaw authority. This was a lot simpler to implement as a first step and should already allow unrestricted flying. I checked stable multicopter flight in SITL. I will add the quaternion based roll pitch reduced attitude control and the mixing with the yaw now to enhance performance in extreme conditions.

  • Full attitude control (without lower yaw prioritisation)
  • Reduced attitude control (yaw neglected)
  • Mixing full and reduced
  • Logic to calculate yaw weight/priority from gains
  • Test and handle extreme corner cases
  • Refactor attitude controller with matrix library (as suggested in review comments)
    EDIT: I did only some refactoring and I think we should split it up here and make a separate PR for further such changes to keep it more focused and reviewable.

Note: Be very careful with tests on real hardware right now.

Context: This pr can soon be tested/compared with @bkueng's nice recent attitude enhancements:
#7940
#7997

EDIT: fixes #9077

/* calculate weight for yaw control */
float yaw_w = R_sp(2, 2) * R_sp(2, 2);
using namespace matrix;
float yaw_w = .4f;
Copy link
Member

Choose a reason for hiding this comment

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

Constant 0.4?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I can recommend you to read section 4.2 on page 16 of the paper I linked to about what this weight actually should represent and some comparison of resulting behaviours. I personally found 0.4 a good rule of thumb for a typical quadrotor setup in my past experience, that's why I put it there for the time being. I think this should be incorporated with the attitude yaw gain parameter in the end. Still to do.

It would be interesting where the current yaw weight calculation comes from and how it's justified from a control perspective. @bkueng told me already that it's done wrong and has his improvement suggestion here: https://github.com/PX4/Firmware/pull/7997/files#diff-81c4f50bdf837c4183b5d3cb81eb40eaR898


/* calculate weight for yaw control */
float yaw_w = R_sp(2, 2) * R_sp(2, 2);
using namespace matrix;
Copy link
Member

Choose a reason for hiding this comment

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

You can do this at the top for all of mc_att_control.

/* using sin(alpha/2) scaled rotation axis as attitude error (see quaternion definition by axis angle)
* also taking care of the antipodal unit quaternion ambiguity */
Vector3f eq = 2.f * math::sign(qe(0)) * qe.imag();
math::Vector<3> e_R(eq.data());
Copy link
Member

Choose a reason for hiding this comment

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

Can you do this without mixing math libraries?

Copy link
Member Author

Choose a reason for hiding this comment

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

I got asked this before in reviews but in my opinion the matrix library is like the name suggests no general math library. I see the matrix library covering linear algebra and the math library more general math functions like sin, cos, sign, expo. That's why I also added all my useful mathematical helper functions here: https://github.com/PX4/Firmware/blob/13e64d00a8b8afa7cedd201ee85842de4feeff6a/src/lib/mathlib/math/Functions.hpp

Let me know if I got something wrong there.

Copy link
Member

Choose a reason for hiding this comment

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

I'm fine with the existence of the math library, but I don't like that we have multiple types of Vector. Vector3f is from Matrix and math::Vector<3> is from the PX4 math library.

Copy link
Member Author

@MaEtUgR MaEtUgR Sep 24, 2017

Choose a reason for hiding this comment

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

I totally agree! I, like everyone else I talked to, clearly favor the matrix library initiated by @jgoppert and that's why I contributed to it and look at math::matrix as deprecated.

Like in this pr I port every instance I come along to matrix. I also plan to get rid of the parameters:
https://github.com/PX4/Firmware/pull/8003/files#diff-81c4f50bdf837c4183b5d3cb81eb40eaR875
and outputs:
https://github.com/PX4/Firmware/pull/8003/files#diff-81c4f50bdf837c4183b5d3cb81eb40eaR872
in math::vector.

This is not to confuse with the call to math::sign which is a nonlinear scalar function that is defined in the math library because I felt it fits there best.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am bit confused as well. What is the reason for using math::Vector<3> instead of matrix?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's there to stay compatible with the rest while not replacing all data types.

But I see the consensus is that I should not only replace the attitude control functionality but totally switch the entire module to the matrix library.

@Stifael
Copy link
Contributor

Stifael commented Sep 25, 2017

just a question about the implementation order.
I understand full and reduced attitude control as a method to compute an attitude based on thrust vector and yaw. This means that it is not a control law, but rather a method to compute a desired quaternion.
In this function here, I expect a control law. In fact, the inputs to this function are a desired and a current quaternion, so it is confusing to read the line here about full attitude control (the desired attitude was already computed). I would expect such a description at the location where the desired attitude is actually computed, and within the function "control_attitude" the control law:
omega(q) = 2/Tau * sgn(q_e0)q_e1:3

@MaEtUgR
Copy link
Member Author

MaEtUgR commented Sep 25, 2017

Yes @Stifael you understood it completely right.

Confusion: I think the only problem with your confusion was my imprecise phrasing with the name "full attitude control" with which I refered to the current algorithm effect and not the exact formulas written in the paper under the corresponding section. Sorry for that I've seen these terms for too long now and start to use them vague. I edited the description now.

Setpoint improvements: We definitely should not only improve the control law but also the setpoint generation.

  • Because now the controller needs to do back calculation to restore the reduced (roll/pitch, yaw) setpoint portions even though they were available before in form of for example a desired thrust vector. This inefficient back and forth calculation is of course not done in the paper.
  • The setpoint generation was suboptimal before like @bkueng already wrote and started to fix.

But these changes are bigger and could interfere also with fixed wing because of the required interface changes... We should tackle that step by step.

@Stifael
Copy link
Contributor

Stifael commented Oct 11, 2017

confusion solved

@MaEtUgR MaEtUgR force-pushed the pr-quaternion-control branch from a4c99ef to 8ba90c5 Compare March 2, 2018 12:50
@MaEtUgR
Copy link
Member Author

MaEtUgR commented Mar 2, 2018

Rebased, it still flies super nicely in SITL. I already wrote some scripts to do test calculations with the yaw adjustments and now I just need to port the correct implementation into the module.

@dagar dagar requested a review from RomanBapst March 2, 2018 16:26
to prioritize yaw compared to roll and pitch by combining
the shortest rotation to achieve a total thrust vector with
the full attitude respecting the desired yaw
not by scaling down the control output with the gains
@MaEtUgR MaEtUgR force-pushed the pr-quaternion-control branch from be1a86a to 83b5d32 Compare March 4, 2018 11:24
MaEtUgR added 3 commits March 4, 2018 11:39
Because the parameter does not make sense from a control theory
perspective. Either you have a gain with the unit 1/s or an inverse
gain or time constant with the unit s. But the time constant parameter
was neither bound to any exact unit nor did it apply instead of a gain.
Rather it adjusted multiple gains from rate and attitude control
according to an arbitrary scale. This can only by accident lead to
good tuning.
According to the paper the quaternion controller is built on
the yaw weight represents the ratio between the roll/pitch and
the yaw attitude control time constant. It also states that as a
thumb rule a value of ~0.4 works alright for most multicopter
platforms. The default attitude gains of PX4 which were determined
independent of the paper from experimental results have a ratio of
2.8/6.5 = 0.43 which matches.
@MaEtUgR MaEtUgR force-pushed the pr-quaternion-control branch 2 times, most recently from 8da9137 to ee97dc0 Compare March 5, 2018 03:52
- Delete left over identity matrix.

- Corner case with a zero element when using the signum function:
We always need a sign also for zero.

- Corner case with arbitrary yaw but and 180 degree roll or pitch:
Reduced attitude control calculation always rotates around roll
because there's no right choice when neglecting yaw. In that small
corner case it's better to just use full attitude contol and hence
rotate around the most efficient roll/pitch combination.
@MaEtUgR
Copy link
Member Author

MaEtUgR commented Mar 9, 2018

@bkueng I took your branch and debugged how NaNs get produced.

  • On initialization _v_att_sp gets filled with zeros (that's ok)
  • While not armed mc_pos_control does not publish any attitude setpoint (not sure why that should be)
  • The attitude control just uses the data in _v_att_sp if it was (ever) updated or not

The old controller just ignores the invalid setpoint and generates useless valid output and the new controller produces NaN in the same case. It's good that you found it, let's come up with a better general solution for this case. But it's not about the changes in this PR, they just reveal the problem that was always there.

@bkueng
Copy link
Member

bkueng commented Mar 10, 2018

You're right. I think we should just initialize q_d with a valid identity quaterion.

But there's another NaN case, which is due to numerical inaccuracies. See bkueng@e47017a, which contains a fix as well.

@MaEtUgR
Copy link
Member Author

MaEtUgR commented Mar 11, 2018

@bkueng Yes, you're right, I found multiple corner cases I'm just too slow in writing, the one with numerical values exceeding the domain of acos adn asin I also found as well thanks to your analysis branch and fixed exactly the same way. Now I wanted to initialize the q and q_d and found a strange case again depending on which values I take which I'm analyzing right now.

EDIT: With this branch https://github.com/MaEtUgR/Firmware/tree/pr-quaternion-control-loop-stop SITL stops the entire attitude control loop reproducable within seconds/some minutes when it's just idle.
The wrong initialization with q_d[1] = 1.f; which should still work seems to play a role but I don't find why it happens.

@bkueng
Copy link
Member

bkueng commented Mar 12, 2018

I did some flight testing with the added constrain's. It flies really well, the improved yaw tracking is also noticeable when flying sharp curves or fast small circles.
Here's a log (I switched a few times to the old controller): https://logs.px4.io/plot_app?log=2c353752-fec2-4f58-95d5-3bad7781c6d0

SITL stops the entire attitude control loop reproducable within seconds/some minutes when it's just idle.

I tested that branch and let it run for around 10 minutes, but didn't have any issues. Maybe it's just too many printf's to the console?

MaEtUgR added 2 commits March 13, 2018 08:37
While operating on exactly normalized float quaternions
it can aparently still happen that one of the elements
gets just slightly above 1 or below -1 and hence out of
the domain of the acosf and asinf functions resulting in
NaN. The constrain function uses stricly smaller/bigger
comparisons and catches all tested cases.
@MaEtUgR
Copy link
Member Author

MaEtUgR commented Mar 13, 2018

@bkueng Thanks for all your super useful help! I just pushed fixes for the domain problem and initialization of the messages. I intentionally ommited checks for valid input quaternions on every loop iteration like MaEtUgR@a85c97c#diff-81c4f50bdf837c4183b5d3cb81eb40eaR947 because that's too much overhead and possible warnings in my eyes. What do you think?

@bkueng
Copy link
Member

bkueng commented Mar 13, 2018

What do you think?

That's fine. Can you check CI, it fails due to style problems.

- On initialization _v_att_sp got filled with zeros
  leaving invalid quaternions
- While not armed mc_pos_control did not publish any
  attitude setpoint which makes no sense
- The attitude control just uses the data in _v_att_sp
  if it was (ever) updated or not
@MaEtUgR MaEtUgR force-pushed the pr-quaternion-control branch from 60ad986 to 8694819 Compare March 13, 2018 09:23
@MaEtUgR
Copy link
Member Author

MaEtUgR commented Mar 13, 2018

Astyle on my windows toolchain passed... I need to check what's going wrong.
Fixed stlye now.

@bkueng
Copy link
Member

bkueng commented Mar 13, 2018

@PX4/testflights Can you test this please? On different multicopters in Manual, Position & Mission.

@santiago3dr
Copy link

Couple flights on the Pixracer (V4):
https://logs.px4.io/plot_app?log=3494ddf1-772c-4ca7-b956-372b18b19ae7
https://logs.px4.io/plot_app?log=9afc5d72-6a4a-41c3-bf4d-87b2ff5283ad

good flights; nice flight performance; no perceivable difference from master

@Avysuarez
Copy link

flight with pixhawk 1 V2. good flight, but i had some issues with baro.
https://review.px4.io/plot_app?log=edadf374-49d9-4c60-82ec-1339c86a2c74

flight with pixhawk 2.1 V3. good flight no isuuses.
https://review.px4.io/plot_app?log=b2a6a473-4d55-4292-889a-2ef2f4fb387a

flight with pixhawk 3 Pro V4pro. good flight, no issues.
https://review.px4.io/plot_app?log=1a90b8e3-d7df-4697-bbdc-c80e239f9671

@dannyfpv
Copy link

Copy link
Member

@bkueng bkueng left a comment

Choose a reason for hiding this comment

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

This looks good now. I checked the CPU load, it marginally increases by ~0.05%, which is acceptable.

Let's wait for @RomanBapst to have a look at this as well, and then I think it's good to merge.

@MaEtUgR
Copy link
Member Author

MaEtUgR commented Mar 14, 2018

@bkueng I was expecting CPU load to decrease 😲 I actually concentrated to make all the quaternion calculations as efficient as possible... Probably this line https://github.com/PX4/Firmware/pull/8003/files#diff-81c4f50bdf837c4183b5d3cb81eb40eaR868 uses most cycles... but it's necessary to have linearisation for the yaw weight to have a correct implementation according to the paper.

@dagar
Copy link
Member

dagar commented Mar 14, 2018

I was expecting CPU load to decrease 

I've found the actual math of the controllers is a tiny portion. #8731 (comment)

@MaEtUgR MaEtUgR merged commit ff25c7f into master Mar 15, 2018
@MaEtUgR MaEtUgR deleted the pr-quaternion-control branch March 15, 2018 16:16
bkueng added a commit that referenced this pull request Apr 23, 2018
…term

The meaning of the yaw weight changed with #8003:
- before, the yaw weight decreased with increasing tilt angle error, so
  it was mostly 1
- now, it is constant and depends on the tuning gains (around 0.4 by default)

It means that #8003 reduced the feedforward term, and we get the closer
behavior as before with this change.
It also reduces coupling between different parameters.
LorenzMeier pushed a commit that referenced this pull request Apr 25, 2018
…term

The meaning of the yaw weight changed with #8003:
- before, the yaw weight decreased with increasing tilt angle error, so
  it was mostly 1
- now, it is constant and depends on the tuning gains (around 0.4 by default)

It means that #8003 reduced the feedforward term, and we get the closer
behavior as before with this change.
It also reduces coupling between different parameters.
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.

【mc_att_control】 Remove unnecessary defaults.
9 participants