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

Generate mixers from description of multicopter geometry #8063

Merged
merged 20 commits into from
Nov 15, 2017

Conversation

jlecoeur
Copy link
Contributor

@jlecoeur jlecoeur commented Oct 5, 2017

closes #7382

  • adds script that generates multicopter mixer from the geometry of the multicopter. For reference, see this notebook: https://github.com/jlecoeur/servo_mix_matrix/blob/master/servo_mix_matrix.ipynb

  • adds folder containing one config file per multicopter geometry

  • auto-generates mixers by listing the *.toml files in this directory

  • Add geometries

    • quad_x
    • quad_h
    • quad_plus
    • quad_v
    • quad_wide
      • because of off-centered CG the previous mixer was wrong, but the new one should be correct
      • edit: I used the same geomety as SK450 deadcat but moved the cg backward to load all motors equally.
    • quad_s250aq
      • dimensions needed. This is the Spedix S250AQ.
    • quad_deadcat
      • for this one I used dimensions of SK450 deadcat, with CG and autopilot at coordinates 0,0,0. But it came out with completely different mixer from mixer_table.
    • hex_x
    • hex_plus
    • hex_cox
    • hex_t
      • for this one the doc is missing (https://dev.px4.io/en/airframes/airframe_reference.html). It is very similar to hex_cox except the direction for top&bottom motors is reverted -> *should we modify this mixer?
      • Also the CG is off-centered rel. to the motors, so the previous mixer was wrong, the new mixer generated with this PR is correct (i.e. the two rear motors are more loaded than the 4 front ones)
    • octa_x
    • octa_plus
    • octa_cox
    • octa_cox_wide
      • same off-centered CG as quad_wide so the new mixer is not equal to the previous one, it should be correct though. It does not matter anyway because this mixer was not handled in mixer_multirotor.cpp
    • twin_engine
    • tri_y
    • dodeca_top_cox
    • dodeca_bottom_cox
  • Compare output with previous script (i.e mixer_multirotor_normalized.generated.h and mixer_multirotor_legacy.generated.h

  • Fix CI

  • Flight tests

    • Tested in simulation with jmavsim
    • Real flights on all available multicopter test platforms

For later, the script is ready for 6dof control. There is an option --sixdof. For example see the geometry "quad_x_pusher" (or quadplane if you prefer) that has a 5th rotor to generate forward thrust.

@dagar @bresch


edit: for sake of compatibility, the mixer matrices are normalized so that they match the current mixers (see option --normalized). However that voids the advantage of modeling dimensions, mass, intertia, and thrust and moment coefficients.
This PR is a first step that introduces the script and the config files. Next independent steps will be to enable 6dof, and to remove normalization.

@dagar dagar self-requested a review October 5, 2017 13:44
@jlecoeur jlecoeur force-pushed the jl/mixers_script branch 3 times, most recently from dd052f8 to 0a099f5 Compare October 5, 2017 15:00
jlecoeur added a commit to jlecoeur/containers that referenced this pull request Oct 7, 2017
@jlecoeur jlecoeur force-pushed the jl/mixers_script branch 2 times, most recently from 291e060 to a541f5c Compare October 7, 2017 23:12
@jlecoeur jlecoeur changed the title [WIP] Generate mixers from description of multicopter geometry Generate mixers from description of multicopter geometry Oct 7, 2017
@TSC21
Copy link
Member

TSC21 commented Oct 8, 2017

@jlecoeur shouldn't toml be added to Tools as a git submodule? I don't think it is a good policy to integrate the src code on the repo.

@dagar
Copy link
Member

dagar commented Oct 8, 2017

If toml is available as an ubuntu package and through pip it doesn't need to be included at all.

@dagar
Copy link
Member

dagar commented Oct 8, 2017

In fact, that reminds me that we should drop the gencpp and genmsg submodules. #8089

@jlecoeur
Copy link
Contributor Author

jlecoeur commented Oct 9, 2017

@TSC21 @dagar fixed. I followed the example of uORB & genmsg and did not realize it was submodules!

@jlecoeur
Copy link
Contributor Author

jlecoeur commented Oct 9, 2017

I suggest to drop quad_v. It is used in 0 configs. It was introduced for TBS_discovery, but the TBS_discovery config uses quad_w : https://github.com/PX4/Firmware/search?utf8=%E2%9C%93&q=quad_w&type=Code

@jlecoeur
Copy link
Contributor Author

jlecoeur commented Oct 9, 2017

I added quad_y and quad_vtail. These are less conventional geometries that are good examples to show the script in action:

quad_y

This one has two coaxial rotors in the back (picture)

// quad_y
B_px = 	{ -0.707107,  0.353553, -0.000000,  1.000000 },
	{  0.707107, -0.353553,  1.000000,  1.000000 },
	{  0.707107,  0.353553,  0.000000,  1.000000 },
	{ -0.707107, -0.353553, -1.000000,  1.000000 },

On the 3rd column we see that only the two rear motors contribute to yaw. Also, as only the two front motors contribute to roll, they must provide more thrust for rolling than for pitching where all 4 motors contribute. The script takes it into account and the first column (roll) has larger gains than the 2nd column (pitch).

quad_vtail

This one has the two rear motors tilted to increase yaw authority (picture). This kind of platform has lot of roll/yaw coupling and it is difficult to find gains by hand, here is the output of the script:

// quad_vtail
B_px = 	{ -0.999862,  0.384973,  1.000000,  1.000000 },
	{ -0.016636, -0.544435, -0.282843,  0.808122 },
	{  0.999862,  0.384973, -1.000000,  1.000000 },
	{  0.016636, -0.544435,  0.282843,  0.808122 },

First thing, we see that the CG is too much forward and the two front motors are more loaded (4th column). Then the two front motors contribute mostly to roll, with small compensations from rear motors (1st column). On yaw (3rd column) we see that the tilted motors are less loaded.

When looking at the non-normalized mix, we see that the yaw gains are lower than the roll and pitch gains, this is because the platform has LOT of yaw authority:

// quad_vtail
B =	{ -2.361111,  0.909091,  0.555556,  0.318182 },
	{ -0.039284, -1.285649, -0.157135,  0.257130 },
	{  2.361111,  0.909091, -0.555556,  0.318182 },
	{  0.039284, -1.285649,  0.157135,  0.257130 },

For comparison, on non-normalized quad_x mix, the yaw gains are much higher than roll and pitch gains:

// quad_x
B = 	{ -0.353553,  0.353553,  5.000000,  0.250000 },
	{  0.353553, -0.353553,  5.000000,  0.250000 },
	{  0.353553,  0.353553, -5.000000,  0.250000 },
	{ -0.353553, -0.353553, -5.000000,  0.250000 },

Note that to maintain compatibility with current mixers, non-normalized mixes are not used.

@jlecoeur
Copy link
Contributor Author

@dagar I moved mixer to src/lib as you suggested.

@Stifael @MaEtUgR can you have a look?

dagar pushed a commit to PX4/PX4-containers that referenced this pull request Oct 12, 2017
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.

I've looked through this and added some comments. I like the generic approach.

Can you please rename geom to geometry (geoms -> geometries) in sources and file names? I prefer to type less too, but readability is more important.

I suggest we merge this after the release to avoid any regressions that this might have.

Since this adds a new config language, we should consider it for params as well (#6115). I think it's a good candidate, as it supports multi-lines.

lib/terrain_estimation
lib/mathlib
lib/mathlib/math/filter
lib/micro-CDR
Copy link
Member

Choose a reason for hiding this comment

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

Why did you add lib/micro-CDR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops that is a leftover from a rebase, will fix!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

# Generic Dodecacopter in X coax configuration, bottom half

[info]
name = "dodeca_bottom_cox"
Copy link
Member

Choose a reason for hiding this comment

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

name is redundant with the file name, I'd use the file name to avoid inconsistencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

if args.files is not None:
filenames = args.files
else:
filenames = glob.glob(args.dir + '/*.toml')
Copy link
Member

Choose a reason for hiding this comment

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

You should use os.path.join

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

def generate_mixer_multirotor_header(geom_list, use_normalized_mix=False, use_6dof=False):
'''
Generate C header file with same format as multi_tables.py
TODO: rewrite using templates (see generation of uORB headers)
Copy link
Member

Choose a reason for hiding this comment

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

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 that would be cleaner.
I was not sure whether the script should generate one big file (current behaviour), or one file per geometry (like uORB and params).
I decided to use the same output format as mixer_table.py (though writing to a buffer instead of stdout!), and I left templating for later.

Copy link
Member

Choose a reason for hiding this comment

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

One big file is fine, I'd say. I'm ok with changing to a template in a later step.

@@ -0,0 +1,356 @@
#!/usr/bin/env python
Copy link
Member

Choose a reason for hiding this comment

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

Nice script!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🕺

@chrisbrent
Copy link

This is amazing! Thank you.

@jlecoeur
Copy link
Contributor Author

Rebased again due to a minor conflict in integrationtests/run_tests.bash
The CI fails are related to the PR, toml is missing on the jenkins tests.

@jlecoeur
Copy link
Contributor Author

@MaEtUgR @bkueng your reviews were dismissed by the last rebase but there was no functional code change.
CI is all green (at last :-)) ! Can we still make it for v1.7 @LorenzMeier ?

Copy link
Member

@MaEtUgR MaEtUgR left a comment

Choose a reason for hiding this comment

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

No changes, renewing approval.

@LorenzMeier
Copy link
Member

I think this is good to go. What I'd like to potentially do later is move from the more obscure .toml files to something that is more widely available. This is relevant as this will facilitate generating the UI in QGroundControl or the documentation on the website.

@bkueng Does this PR affect the generation of mixer documentation for the documentation? If it does, we should not be merging it yet.

@bkueng
Copy link
Member

bkueng commented Nov 15, 2017

Does this PR affect the generation of mixer documentation for the documentation? If it does, we should not be merging it yet.

No. Let's get it in then!

@jlecoeur can you make sure the toml files get documented? Maybe by adding a sample file that explains all of the variables?

@nanthony21
Copy link
Contributor

@jlecoeur Very cool stuff. I'm wanting to do some work on the mixer and wanted to make sure I understood how the mixer scalers are being generated. For the most part it all makes sense but I had some questions about normalization that I'm hoping you can help me with.

1: Can you explain why it's necessary to normalize the B matrix?

2: Why is the normalization of roll and pitch linked and why is it divided by np.sqrt(B.shape[0] / 2.0)?

https://github.com/PX4/Firmware/blob/01f5f8862a0e1fe19575f6fd1532db2772f63eb5/src/lib/mixer/geometries/tools/px_generate_mixers.py#L201

For a completely symmetric geometry such as the quad_x I would think that the normalized matrix would simply be:

[[ -1 , 1 , 1 , 1 ],
[ 1 , -1 , 1 , 1 ],
[ 1 , 1 , -1 , 1 ],
[ -1 , -1 , -1 , 1 ]]

But instead it is being computed as:

[[ -0.707 , 0.707 , 1 , 1 ],
[ 0.707  , -0.707  , 1 , 1 ],
[ 0.707  , 0.707  , -1 , 1 ],
[ -0.707  , -0.707  , -1 , 1 ]]

Is this right?

@jlecoeur
Copy link
Contributor Author

Hi @nanthony21

  1. The normalization is here for compatibility with the previous mixer generator. I wanted this PR to allow you to create new geometries while not affecting the existing geometries. Had I used non-normalized mixers, basically every one would have had to retune PIDs.
  2. Same as above, the previous generator had motor positions described as radius&angle.

If you want to remove the normalization, please do! I would be happy to help if I can. You can open a new issue to move the discussion over.

@nanthony21
Copy link
Contributor

@jlecoeur Thanks, that helps.

Are there drawbacks to having it normalized? I wouldn't want to go changing everything if there isn't a good reason to.

@jlecoeur
Copy link
Contributor Author

The drawbacks are:

  • actuator_contols do not have physical meaning, they are normalized between -1 and 1, although it could be in Nm and N.
  • multirotors are usually less effective on yaw but this is not reflected in the normalized mixers
  • normalization makes the mixer independent to the size of the drone, and to the motor constants

However nb 1 and 3 are also advantages in terms of the generality of PX4.

@MaEtUgR
Copy link
Member

MaEtUgR commented Mar 26, 2018

  • multirotors are usually less effective on yaw but this is not reflected in the normalized mixers

This should and is reflected in the multicopter attitude controller. Because the attitude controller might choose a different optimal non-linear "attitude error direction" depending on less yaw autority which it can't do if the output is scaled linearly afterwards, see https://github.com/PX4/Firmware/blob/19a4f0988c42679207b9da101d54bc61432cdfb7/src/modules/mc_att_control/mc_att_control_main.cpp#L811

@jlecoeur
Copy link
Contributor Author

@MaEtUgR I think you are raising an important point but I am not sure that I follow you.
Are you opposed to the removal of the normalization? and if yes is it because of problems it would cause with the current implementation of the controller, or because of something more fundamental?

I do not see how the attitude gain yaw_w would be affected, I think only rate gains have to change.
Here are the current units:

attitude_setpoint (unit: rad) 
=> [att_control] => 
rate_setpoint (unit: rad/s) 
=> [rate control] => 
actuator_controls (unit: none)
=> [mixer (normalized)] => 
actuator_outputs (unit: none)

Here is what I have in mind in the case of non-normalized mixer:

attitude_setpoint (unit: rad) 
=> [att_control] => 
rate_setpoint (unit: rad/s) 
=> [rate control] => 
angular_accel_setpoint (unit: rad/s^2)
=> [inertia model] =>
torque_setpoint (unit: Nm)
=> [mixer] => 
actuator_outputs (unit: none)

@MaEtUgR
Copy link
Member

MaEtUgR commented Mar 26, 2018

Are you opposed to the removal of the normalization?

On the contrary, I'd support it. I only wanted to inform that scaling down yaw output linearly is not the optimal solution for multicopter attitude control. That's part of the insight of my master thesis and the attitude controller changes I recently introduced (#8003). This is generally independent of (non-)normalized thrust.

You're plan seems in theory super nice. You should even know the spacial geometry and hence the lever lengths with the mixer and have thrust (unit: N) as output. Then it should pass a motor model and get translated to the output corresponding the ESC e.g. [0,1] or rpm. I was working at a lab during my studies which had the complete model in place.

attitude_setpoint (unit: rad) 
=> [att_control] =>
rate_setpoint (unit: rad/s) 
=> [rate control] =>
angular_accel_setpoint (unit: rad/s^2)
=> [inertia model] =>
torque_setpoint (unit: Nm)
=> [mixer/frame geometry] =>
actuation_thrusts (unit: N)
=> [ESC/propeller model] =>
actuator_outputs (unit: [0,1], rpm, current)

But you should not forget the problems come in practise when you want to support a wide variety of vehicles without a model. I think it needs to be our goal to be backwards compatible in a sense that existing and arbitrary setups still work unrestricted. But enable and encourage usage of model based features. I think for a normal user/short-term prototype it's reasonable to measure mass and frame geometry but usually not moment of inertia and ESC signal to thrust. I think others like e.g. @priseborough would also have interest in units.

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.

Creating new mixer geometry - documentation required
9 participants