-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Mellinger: support to change gains in bindings #1180
Conversation
To use the controller in a simulator (and for testing), we need two changes: 1.) have a data structure that holds the state, so we can instantiate multiple controllers. 2.) the ability to change gains without recompiling. This change introduces a state/param struct to achieve both objectives, similar to the logic in collision_avoidance.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.
I have some larger generic comments, just to enhance my understanding of what you are trying to achieve in the PR 😄
const state_t *state, | ||
const uint32_t tick); | ||
|
||
#ifdef CRAZYFLIE_FW |
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 actually never noticed the CRAZYFLIE_FW define before. Is this to separate functionality for the python bindings build and the firmware build? Will there be an build error if you don't use it?
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 copied this logic from collision_avoidance.c - might have been introduced there by @jpreiss. We want it here to avoid that these functions end up in the bindings, since they are "internal". A cleaner way could be to have separate files, but that makes code navigation more annoying.
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 considered both choices. IIRC, I didn't have particularly strong motivation for choosing one file with #ifdef
over two files. I probably just did it to reduce the number of files. I don't see any discussion in #567 either.
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.
There is also the option to use the UNIT_TEST_MODE
define that is used in unit tests to show that some part of the code is added/removed to make the code testable. I just added it to the python tests in PR #1183 that I'm working on. Maybe it should be renamed though?
I prefer a solution where there are as few #if
s and buts as possible in the code, especially modifications related to test. I vote for separating the generic functionality and the global state into two files, even though it is a bit trickier to navigate.
As an extra input to this I also would like to add that we have (sort of) wanted to separate code that depends on FreeRTOS and the platform in src/modules
, while generic code that could be used on other platforms goes into src/utils
(I can see that this is not completely true at the moment...). I'm not sure it has been communicated outside the office but has been part of internal discussions. For the mellinger controller this would translate to maybe moving the generic file to utils
while the file with the global state stays in modules
. I think this is outside the scope of this PR but I just wanted to put it out there. To me this is related to cleaning up dependencies and make it easier to re-use/test code.
LOG_GROUP_STOP(ctrlMel) | ||
|
||
#endif // CRAZYFLIE_FW |
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 not ideal that we put all this code and logging and variables in the CRAZYFLIE_FW define... Technically the struct exists but it is just not written in ? I had a question about the use of this define in one of my earlier questions.
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 if/endif preprocessor doesn't need to go around logging/params. In this file, it might not technically be needed at all, since the binding compilation process only generates bindings from a given header file.
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.
Ah yeah that is true. Would it be okay for you to remove this define in case it is not necessary? I just want to prevent more ifdefs to be added if necessary as it complicates the code eventually.
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.
Technically the struct exists but it is just not written in ?
In collision_avoidance.c
the global state struct is defined inside the #ifdef CRAZYFLIE_FW
. The bindings shouldn't need it at all.
The if/endif preprocessor doesn't need to go around logging/params.
If they are moved outside the #ifdef CRAZYFLIE_FW
, then the C compiler for the bindings will need to know about the logging/param system, right? When I was working on collision_avoidance.c
I assumed we wouldn't want that.
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 need/want it to load default params (by copying). Otherwise we would need a function that fills in the default values.
I think the bindings already have some trickery to basically ignore the LOG/PARAM defines, so technically they can be unguarded.
Repeating my inline comment: There was no strong motivation for choosing |
Next to the question on what to do with define, it all looks good to me! But for obvious reasons, I do want to flight test this 😄 Tomorrow it's a holiday in Sweden so that will be next week. |
I got rid of the define in the *.c file (and made sure it still works fine). For the one in the header I see four options:
I think options 1 or 3 would be best, but perhaps best if the firmware maintainers raise their preferences. Flight test: I did one before submitting the PR, but a second one is certainly even better! |
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.
Looking good!
const state_t *state, | ||
const uint32_t tick); | ||
|
||
#ifdef CRAZYFLIE_FW |
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.
There is also the option to use the UNIT_TEST_MODE
define that is used in unit tests to show that some part of the code is added/removed to make the code testable. I just added it to the python tests in PR #1183 that I'm working on. Maybe it should be renamed though?
I prefer a solution where there are as few #if
s and buts as possible in the code, especially modifications related to test. I vote for separating the generic functionality and the global state into two files, even though it is a bit trickier to navigate.
As an extra input to this I also would like to add that we have (sort of) wanted to separate code that depends on FreeRTOS and the platform in src/modules
, while generic code that could be used on other platforms goes into src/utils
(I can see that this is not completely true at the moment...). I'm not sure it has been communicated outside the office but has been part of internal discussions. For the mellinger controller this would translate to maybe moving the generic file to utils
while the file with the global state stays in modules
. I think this is outside the scope of this PR but I just wanted to put it out there. To me this is related to cleaning up dependencies and make it easier to re-use/test code.
I flight tested btw, so I'll give the approve! @whoenig do you want to do something still with @krichardsson comments or do you like us to merge it? |
I like @krichardsson ideas, just not sure about the naming |
@whoenig I agree, let's keep this PR as it is and refactor later. |
To use the controller in a simulator (and for testing), we need two
changes:
1.) have a data structure that holds the state, so we can instantiate
multiple controllers.
2.) the ability to change gains without recompiling.
This change introduces a state/param struct to achieve both objectives,
similar to the logic in collision_avoidance.c.