-
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
Configurable Actuator Output Control #16808
Conversation
Awesome ! The design is exactly what I had in mind. |
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 reviewed anyway :-)
This definitely goes in the right direction. I have a concern regarding the function field in the topic output_control.
Neat, looks like the right direction.
|
All of this was motivated (from my side at least) with the idea that everything would be completely user accessible for editing, ultimately presented graphically in QGC. Everything that's a property of a physical output is captured as a parameter with appropriate index (PWM_MAIN, PWM_AUX, UAVCAN_ACT, DSHOT, etc). Only parameters for physical outputs that exist and are configured will be marked active and available in QGC. I actually haven't considered any of this in a COMPONENT_INFORMATION world, could you expand on how it might be used? Simple functions (eg landing gear) are configured directly on physical outputs, then for control allocation it's a set of outputs abstracted above that. A control allocation output is mapped to a physical output, but we do it from the output module side to keep things modular (similar to serial). For the gui I was thinking to aggregate all of the available output options so that visually you're configuring a control allocation output, but able to select from a dropdown populated with all available physical outputs (deconflicted). This is the same situation we need to solve graphically for serial port configuration where the port is configured per module, but we need to invert the configuration so that a user is able to configure a port directly. This might be easier to discuss on a call with diagrams...
I still don't have a great solution here, but one idea I'm considering is having a bitfield per output module that selects the outputs (think of a replacement for fmu_mode). When starting each module it's responsible for constraining the selection to what's actually possible, including the underlying pin allocation, timer grouping, etc. Then saving it back to the parameter so the user isn't completely oblivious. Pin configuration would be first come, first serve. Depending on the board we could then do things like this, completely user accessible.
Resulting in
At times it will be sloppy with the user inevitably fighting underlying constraints they don't really have visibility into, but I think it would at least enable the common use cases. Any other ideas? |
I think the per-pin enable makes a lot of sense; it could even clean up a lot of the One thing I hadn't mentioned yet is that is that my original plan was to make MixingGroup a standalone WorkItem so that it ran independently of any one output module, then add some metadata to each of the mixers to flag the outputs as multicopter motors, fixed-wing surfaces, heli motors, etc. and remap them to arbitrary physical outputs. This was motivated by our desire to use CAN ESCs and servos, without hacking servos to respond to ESC commands, allow UAVCAN + CANOpen, keep some simple functions on PWM, etc. - all at the same time, without having to constantly rewrite multiple mixer files. I'm still considering the idea of putting all mixing into a single (larger) MixingGroup that runs standalone, and then publishes to |
Not just clean up, but all the IOCTLs in and around output configuration will be gone by the time I'm "done" here.
The reason I was opposed to this particular architecture was how we'd actually handle the configuration of all these different things scalably. For example the number of MAIN and AUX outputs are different across boards, and then it gets in worse once you factor in dynamically adding UAVCAN actuators or configuring some outputs as DSHOT, some as PWM, etc. I think it could work if we can find a way to "register" the actually available outputs so that there's a central unified understanding of what's available on the system. |
I haven't worked through this completely, but here's what I had in mind. A build-time constant json file describing all possible physical + virtual outputs, which then can be used to build a UI:
Does that make sense? |
Most of it. This looks like the missing layer of metadata that ties quite a lot of it together properly instead of implicit grouping based on naming and numbering.
I wasn't even considering trying to expose this confusing aspect to users, but this actually sounds quite achievable now. We'll still need to figure out how to rework pwm_out/dshot/camera_trigger/camera_capture around this.
What do you mean by virtual? This is where I wanted to be careful to only show what physically exists and is present (and perhaps explicitly enabled).
I don't think I follow this part. The problem is we don't have motors 1...N, we have some variable combination of PWM_MAIN, PWM_AUX, DSHOT, UAVCAN (both ESCs & servos), Roboclaw, etc. How do we present that for configuration without abstraction? A not completely contrived example could be something like a quad plane with 4 DSHOT outputs for the multicopter, UAVCAN servos for the FW control surfaces (elevons), regular PWM for the pusher motor, and maybe another PWM for landing gear. Landing gear could be configured directly on the output, but all the rest need to go through control allocation (this is jumping ahead a bit).
|
I'll leave the UX details to others, but I like the idea of having hardware support being determined and put into some nice structure - including generating the relevant parameter instances - at build time, so you don't have to worry about whether something is supported or not on a given board; the parameter just won't exist if it isn't supported. I would perhaps push back on applying it in too much detail to UAVCAN, as technically, it allows an arbitrary number of outputs. Of course, we will need some limits, but a blanket limit of 16 outputs to start with would suffice. Something else that's been bugging me is: How do we know whether any given output is an ESC, servo, or some other device? This becomes crucial, I believe, when we start to talk about implementing actuator feedback, and even for handling the case of the "pre-armed" state, where servos can move but ESCs can't. |
Actual limits are pretty arbitrary and will grow as large as needed. I'm more worried about being able to represent what's physically there to a user so they can then put the pieces together and we try to limit the possible mistakes. I think that type of understanding of the world is also going to help us when it comes time to use feedback properly.
I think most of it can be derived first from the split between outputs being either 1) control allocation owned or 2) simple function.
We can certainly add some kind prearm configuration (or additional metadata that would answer the same question), but let's figure out if any of these cases are real. |
What about flaps? Their purpose is to provide lift (z-axis thrust), but it would be servo-controlled. I was thinking that it would be straightforward to add an additional field alongside function to determine actuator type; I'm just not sure exactly where this metadata would live. For the simple output functions - it's probably safe to assume it's not going to be connected to an ESC (unless someone can think of a use case)? But in regards to the prearm state, I think some ESCs require incoming values below some threshold for some length of time in order to initialize / "arm" before they will actually accept larger inputs and spin up. So for these, jumping from 0 input to "valid" input would fail. |
Isn't that going to be satisfied by the optional disarm value configured per physical output or are you thinking of a more specific sequence?
|
Standalone flaps are just another simple output, but flaperons are probably going to require some special handling to mix in the offset to ailerons that are otherwise handled by the control_allocator. |
Just a bad choice of words then, I was referring to having multiple parallel distinct messages on the same bus. The outputs would be added if the module is enabled at build.
Yes we do, the control allocation output defines motors 1..N. Which becomes
Maybe a mock UI would help, and a design document. |
@bkueng I like your suggestion of a json file to autogenerate parameters only for the required/real hardware outputs. I suggest creating params based on each ca-output type enum (CA_ACT{0-N}_TYPE) rather than an airframe enum (CA_AIRFRAME). In your example above, the configuration of the first output would look like this:
|
Yes we're mostly on the same page with that, I'm talking about how you pull it all together coherently for editing so that a user doesn't have to string together configuration across output modules and CA to understand how the vehicle is actually configured.
In your UAVCAN example servo 1 is "left elevon", but the user doesn't know that because the function is simply CA_ACT5. It's CA_ACT5 that's either configured as elevon (or more directly as separate roll and pitch torque in the effectiveness matrix). That's the part I want to be able to lump together configuration-wise so that from a user's perspective they're only configuring a single thing in a single place per output. Directly setting CA_ACT5 to UAVCAN servo 1 and the specifics of CA_ACT5 on one line. Another example would be configuring an arbitrary multicopter. Each motor is configured with a set of CA_MC_Rn_X parameters, but there are also properties of the physical output that matter and I think should be grouped together. From the user perspective you're configuring a single physical output, the fact that it happens to span across CA_MC_R1* and PWM_MAIN3* is a detail the user shouldn't have to care about. I want to click on a motor in that graphical multirotor and be able to set it's output (eg PWM_MAIN), position, direction, PWM min, PWM, max, etc.
Yes I think so. If we can get everyone aligned on the fundamentals there's then a fair amount of isolated work that needs to be done across quite a few areas (output modules, control allocation, QGC, etc) to realize the full end user configuration improvement. |
Did a short flight test this morning: https://logs.px4.io/plot_app?log=26ea1db8-8e57-4ffb-b32a-59f80c1216a0 |
That's the part I was missing how it would look like in the end (hence a design doc). If we can get it that flexible, even better, and yes, the metadata should be based on that then.
The user would know as the UI would replace CA_ACT5 with "left elevon". The tricky part is to get the semantic based on configuration + metadata.
|
Great, let's try to get a mock up of the user interface, then work our way to the implementation.
I think the GUI can be smart, like if
Which is good enough in my opinion.
No, no, this PR configures control channels per-hardware-output, so you can get a CA output to multiple hardware outputs. Ex: to get redundant link to actuator 0 with PWM + CAN, you do |
Correct, it would only be a UI limitation if it's turned around there. |
Correct, that's the simple way to do it. Where it gets interesting is when we have feedback enabled down the road. What I'm envisioning is that we can enable or disable updates to the CA table based on actuator feedback with some "Enable Feedback" option. If feedback is enabled, and if you truly have redundant actuators operating in parallel, then the GUI should, behind the scenes, duplicate that row of the CA table and assign the 2nd row to that 2nd physical output. This way, if feedback from one output shows a failure, the "bad" row can be zeroed out and the redundant output will take over seamlessly. If feedback is disabled, on the other hand, the same CA row can be assigned to multiple physical outputs with no worries, as no one output will cause that single row to be "zeroed out". |
I think we're actually talking about pretty much the same problem, and I hadn't even decided on one or the other I was just trying to keep the explanation remotely coherent. Let's try to sketch some of this out to more effectively brainstorm. |
I am not sure I follow this. This is a cool use case but I do not think this should happen 'behind the scenes'. Just to be sure that we make the same distinction between actuator redundancy and link redundancy. |
#16758 putting this here for reference, we're going to try to rebase it onto this PR. |
Esc Readiness pub/sub implemented Also add 'px4_fmu-v4_v1node' build target for a uavcan_v1-based CANnode To use the CANnode as a CAN-->PWM bridge: On the CAN node: + Set UCAN1_ESC0_SUB to the same value as UCAN1_ESC_PUB on the FC + Configure pwm_out to listen to output_control_mc: Set PWM_AUX_FUNCx to [200, 207] (motor1=200, motor8=207, etc.) On the Flight Controller (FC): + Set UCAN1_ESC_PUB - port ID to publish setpoints on + Configure uavcan_v1's MixingOutput -- for use with ControlAllocation module, set UCAN1_ACT_FUNCx to values in range [1000, 1015] e.g. UCAN1_ACT_FUNC1=1000 sets ESC index 1 to publish from CA output 1 + Set UCAN1_ACT_MINx to 0 and _MAXx to 8191 (Final range still TBD; this is what it is right now) + Configure the ControlAllocation module as needed (Note: no mixer-file needed!) + Note: You'll need an airframe that starts the CA module and cofigures all the relevant CA parameters for you (see 4018_s500_ctrlalloc for an example)
+ Add parameters for ESC Readiness pub/sub + Apply recent _subj_sub refactoring to ESC client + Give credit to Peter in ParamManager
a572588
to
dd3ff51
Compare
Dynamic creation of UavcanPublisher objects in the same manner as SubscriptionManager Also move Gnss and Readiness publishers to DS-015 folder Also add generic, templated uORB_over_UAVCAN_Publisher - any uORB topic can now easily be published over UAVCAN with a single line of code
dd3ff51
to
276ca1a
Compare
…re loading modules)
Use the included script to 'install' it in the sitl-gazebo plugin's models folder. Then do: 'make px4_sitl_ctrlalloc gazebo_iris_ctrlalloc'
Describe problem solved by this pull request
This is still a WIP, and is partially blocked by #16444, but is far enough along to demo features like simplified control of arbitrary actuators via MAVLink DO_SET_SERVO commands, and also allows simplified output configuration when using the Control Allocation module. The goal here is to allow each output module (pwm_out, px4io, uavcan, dshot, ...) to map specific functions to its outputs without loading a mixer file onto it specifically. For example, there are currently 8 functions assigned to MAVLink Servos 0-7.
Describe your solution
This adds a new uORB topic,
output_control
, which consists of an array of functions, and an array of values. Eachvalue
is associated with afunction
, with functions being, for example, Aileron, Elevator, Pusher, Landing Gear, etc. There's also a function for Mixer, which I'll explain later.Callbacks for this topic have been added to the MixingOutput class, which is now being used everywhere (except PX4IO, see #16444) to handle the "boilerplate" surrounding mixer files and actuator-output callbacks. Also added to MixingOutput is an output-module-specific parameter prefix (i.e. "PWM_MAIN") that is used to load the MIN / MAX / DIS / etc. parameters to configure the output scaling and limiting.
As modules publish
output_control
topics, the MixingOutput class looks at thefunction
values in the topic, and if any of its assigned functions match, it copies the value to that specific output. This value is expected to be a normalized value in the range [-1, 1] that will then be scaled to the range [MIN, MAX] of that output.To facilitate testing with the ControlAllocation module, I commented out its publication of
actuator_controls
and instead put the newoutput_control_ca
topic instance in place.Describe possible alternatives
This would be a rather long-winded discussion; feel free to ask questions if you have them.
Test data / coverage
I tested the pipeline by loading the S500 CtrolAlloc airframe (ID 4018) onto a Pixhawk 4 (
ctrlalloc
target), then set CAN_ACT_FUNC[1-4] to [1000 - 1003] in order to map the outputs of the ControlAllocator to UAVCAN "actuators" (currently just ESCs) 1-4. You should also set CAN_ACT_MINx / MAX / DIS accordingly. Once configured, you can see the expected output values using the UAVCAN GUI tool.You can also use the DO_SET_SERVO vehicle command to control a "MAVLink Servo". I've added a command-line option to Commander to publish and handle this vehicle command. Simply set, e.g.,
PWM_AUX_FUNC8
to 102 (MAVLink servo 2), then do:commander servo 2 <value>
, where<value>
is in the range [-1 to 1], and you'll get the mapped PWM output on AUX8.I'll add logs / screenshots the next time I do some testing.
Additional context
This fits into the broader goals of improving the UX of airframe setup. It also may assist with some of the goals surrounding the Control Allocation module, including providing part of the framework for implementing intelligent actuator feedback for dynamic effectiveness-matrix updates.
If you want to fly this, review the parameter changes first! MAIN outputs not currently supported.
Log Files
SITL log using Iris CtrlAlloc airframe (local mod to Iris to run Control Allocation module):
https://logs.px4.io/plot_app?log=3882db6f-1375-4d48-b0db-bd84bc663f17
Bench test on a Pixhawk 4:
https://logs.px4.io/plot_app?log=f8a5aadd-ca11-47a7-a506-2e0ea7c4eb45
Flight on a S500 quad using the Control Allocation module (sorry about the awful vibrations):
https://logs.px4.io/plot_app?log=22065129-5287-4154-b3a5-cc2aa243c2ba