-
Notifications
You must be signed in to change notification settings - Fork 13.7k
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
MC: improve manual stick input handling #7940
Conversation
daf2cf5
to
96cb576
Compare
More flights at higher angles:
I noticed the same yawing issues as with HIL, especially with 75 degrees max tilt. This makes it pretty much unflyable. I created an issue in #7949. |
The math looks ok, but in the computation you only compute
Either we compute the twist attitude setpoint directly from yaw, or we compute the twist attitude setpoint from quaternions:
|
@Stifael Thanks for the review. You probably have overlooked |
@bkueng, yes I missed that. However, it is also kind of an interesting order of implementation. |
96cb576
to
ee2580c
Compare
I agree and I first had it with quaternions only, but the next block (https://github.com/PX4/Firmware/blob/96cb5760ae3180f65ea514da9a32e4ef7fb420c3/src/modules/mc_pos_control/mc_pos_control_main.cpp#L2159:L2193) then again uses Eulers, so I kept Eulers as well to reduce the number of CPU cycles. I rebased to master. |
At 90 degrees the yaw is extremely unstable (tested with HIL), it overshoots and only very slowly converges to the correct value. This behavior is also noticable with lower angles, but not so extreme. It definitely needs to be looked into further, but for now this makes it safer.
ee2580c
to
b2a6624
Compare
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 a lot for thinking this through. I just have some implementation order comments.
The idea behind your implementation is very nice!
What I still don't get exactly is why it should influence yaw at all... I need to think this through again.
I would favor the most quaternion near implementation as possible (without unnecessary conversions) as well.
* ---------------------------------------- | ||
* This simplest thing to do is map the y & x inputs directly to roll and pitch, and scale according to the max | ||
* tilt angle. | ||
* But this has several issue: |
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.
typo? "issues"
*/ | ||
const float x = _manual.x * _params.man_tilt_max; | ||
const float y = _manual.y * _params.man_tilt_max; | ||
const float tilt_angle_sp = math::min(_params.man_tilt_max, sqrtf(x * x + y * y)); |
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.
Nitpicking: You could calculate v
and v_norm
before this line and use v_norm instead of sqrtf(x * x + y * y)
.
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.
You're right, this is much simpler now: 773df45
float v_norm = v.norm(); | ||
|
||
if (v_norm > FLT_EPSILON) { | ||
v /= v_norm; |
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.
v.normalize()
?
v /= v_norm; | ||
} | ||
|
||
v *= tilt_angle_sp; // the norm of v defines the tilt angle |
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.
you're basically multiplying by v_norm
here again which means you could only treat the case v_norm
is bigger than _params.man_tilt_max
to safe steps.
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.
Nice work!
} | ||
|
||
matrix::Quatf q_sp_rpy = matrix::AxisAnglef(v(0), v(1), 0.f); | ||
// The axis angle can change the yaw as well (but only at higher tilt angles). |
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 think these comments are very useful. What made me finally understand why the yaw changes here in your spoken explanation is the hint "it's yaw in world frame". Maybe this hint could also help others reading the comments.
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 added that.
I was quite surprised when I noticed the following in manual mode:
MPC_MAN_TILT_MAX
) can easily be exceeded just by using a combination of roll & pitch (e.g. by moving the stick to the right upper corner). The formula for the tilt angle isacos(cos(roll) * cos(pitch))
. By inserting the maximum angle, the limit is exceeded by roughly 15 degrees (with the default maximum tilt of 35 degrees). The full graph can be seen here: https://www.desmos.com/calculator/5zykbcnn93atan(sin(roll) / (sin(pitch) * cos(roll)))
. Forroll == pitch
, this is the graph by how much the direction is off from the diagonal: https://www.desmos.com/calculator/3poijoayhx. With a larger maximum tilt angle, this becomes noticeable as well.I confirmed both points by looking at logs & doing simulations.
At first I only noticed 1. and implemented a solution for that, when I noticed the second point. They cannot be solved independently, so I propose a completely new approach to handle manual input. x and y input are used to control two (different) angles:
sqrt(x*x + y*y)
). This allows a simple limitation of the maximum tilt (it adds a small dead-zone in the corners of the stick range)Benefits:
However there is one point to note: the new behavior changes the yaw as well, when roll & pitch are combined. This can be seen if you pick up an x-quad at 2 diagonal motors, and start rotating it around those 2 motors: the yaw changes a bit.
If
a
is the tilt angle andb
is the angle of the direction of the tilt angle, then the yaw angle is given byyaw = atan((-2 * sin(b) * cos(b) * sin^2(a/2)) / (1 - 2 * cos^2(b) * sin^2(a/2)))
, and as a graph (x=tilt angle): https://www.desmos.com/calculator/y2mnebvl0jTesting
I did extensive testing in HIL, including combinations of yawing and maximum tilt angles up to 90 degrees. I noticed that the yaw becomes very uncontrolled (overshoots and slow convergence) at high angles (around 80+). But this is a separate issue, I had the same behavior before this PR.
Then I tested on 2 different quads. So far, with a maximum tilt angle up to 55 degrees:
In this log the position estimation is off, not sure why. Also the yaw lost tracking when I quickly changed roll & pitch angles. This happens with both the old & new behavior, it's not a setpoint issue.