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

driver/pca9685_pwm_output: bugfixs & QGC integration & support outputting in duty-cycle mode #21528

Merged
merged 5 commits into from Oct 21, 2023

Conversation

SalimTerryLi
Copy link
Contributor

@SalimTerryLi SalimTerryLi commented Apr 30, 2023

This PR fixes pca9685_pwm_out. Now it should works again.

Blocker #20594 got merged.

Fixed things:

  • Parameters for setting PWM frequency
  • May looks better now, comparing to what I've done years before...

Imporvements

  • Move scheduling rate from cmdline argument into parameters
  • Support output duty-cycle signals per channel
  • Support configuring CLK source of PCA9685 with Kconfig
  • Now it should be able to act as an alternative to the old pca9685 module, which is deprecated in 0e2df5a

Test Coverage

  • RPi 4B with my expansion board using PCA9685 as main output
  • CUAV pixhack v3 with PCA9685 connected to I2C1

@junwoo091400 junwoo091400 added Drivers 🔧 Sensors, Actuators, etc bugfix 🐞 labels May 1, 2023
@SalimTerryLi SalimTerryLi force-pushed the pr-pca9685-maintaince-update branch from f6124ac to 8faefca Compare May 2, 2023 08:14
@SalimTerryLi SalimTerryLi marked this pull request as ready for review May 2, 2023 08:15
@SalimTerryLi
Copy link
Contributor Author

Anyone interested in this stuff...? Maybe I need to find a pca9685 module and driving some LEDs mapped to RC inputs with this new driver on a pixhawk as a video demo to attract some attemtion......

@dagar dagar self-requested a review May 17, 2023 15:36
@DronecodeBot
Copy link

This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there:

https://discuss.px4.io/t/px4-community-q-a-may-17-2023/32159/1

@SalimTerryLi
Copy link
Contributor Author

This guide might be moved somewhere later:

PCA9685 PWM Expander

Adafruit PCA9685 Module

By using one of the PCA9685 module, you'll get another 16 PWM outputs on your Flight Controller. You can control servos, ESCs, as well as LEDs, even a single MOSFET which drives another brushed motor!

Before going ahead, the following conditions is suggested to meet to make use of the module:

  • fmu_v3 or later
  • There is at least one I2C port available on the FC

The driver does work on fmu_v2 but it is not included in the firmware by default. Even if you choose to manually build one by yourself, the missing Actuator Tab in QGC still makes it difficult to configure the outputs.

Almost every FC has I2C buses exported. If there's already something connected to those ports, simply grabbing an I2C expander board and connect all your peripherals to that board. It should be fine to connect PCA9685 with external compass on the same I2C bus, as long as the update rate of PCA9685 is limited to lower value like 50Hz. But please avoid it if possible, due to the heavy bandwidth consumed by PCA9685.

Note that currently there is no support for multiple PCA9685 instances.

The following guide is based on CUAV Pixhack V3, with a piece of PCA9685 module that is easy to find on-line. FS-IA6B paired with FS-TH9X is used as RC system to finish the minimum setup of PX4.

Initial Setup

Hardware Connection

The I2C port on Pixhack V3 is available through a 20pin connector. An I2C expander board is shipped alongside with FC so let's use it to connect PCA9685 module to FC.

image

Also because PCA9685 module has 2.54mm pin header for DuPont wire connection, you still need to make your own wire by your self. Pixhack V3 ships its I2C expander board compatible to old APM style 1.25mm connector, so I just cut one side of the wire and soldered another side with 2.54mm DuPont pin socket.

image

It is too risky to let those barely connected wires fly in to the sky. Strongly recommends to solder everything together before taking it to real flights!

image

Only four wires are needed to be connected:

  • GND
  • SCL
  • SDA
  • VCC

If you are going to connect servos to this module, An extra V+ pin can be used to power the rail. This pin can also be left unconnected if there is ESC connected to one of the channel, which provides BEC output to all other channels. Otherwise there will be no power output but only PWM signals on yellow pin headers.

Firmware Configuration

Now power the FC via USB and open QGC to test it. Click on the left top QGC icon and select Analyze Tools. Then click MAVLink Console and type the following command:

i2cdetect -b 1

The parameter -b 1 specifies the I2C bus in use. Adjust the bus number if using a different setup.

image

If 40 shows up then PCA9685 is successfully connected to FC. Note that 0x40 is the default I2C address of PCA9685. If it is changed by hardware modification, there may be 41, 42 or else show up.

Now try to start the driver:

pca9685_pwm_out start -b 1 -a 0x40

If there is no error reported, verify the status by:

pca9685_pwm_out status

image

Congratulations!

Now it's time to make PX4 start the driver on boot. Poweroff the FC, pull out the sdcard and put it onto your computer.

Create a directory named etc, if not exist:

image

Enter that directory and create a new file, named extras.txt:

image

Open and write following script to that file:

#!/bin/sh

pca9685_pwm_out start -b 1 -a 0x40

Save. Now eject the sdcard and insert it back to FC. Power on the FC.

Open the MAVLink Shell as described before. Here we do a simple verification to ensure the driver is running now:

pca9685_pwm_out status

image

This indicates the driver is started on boot and is ready to use.

Driver Configuration

Things that may needed to be tuned:

  • PWM frequency
  • update rate

PWM frequency will determine how many pulses will be sent out from PCA9685 in one second. Update rate (aka. schedule rate) determines how fast FC will notify PCA9685 to change its output.

Setting of PWM freq has a side effect: lower PWM freq will result in lower PWM resolution. at the freq of 50Hz, PCA9685 will have about 205 steps between 1000us and 2000us signal range. That is between 7 and 8 bits resolution. At the freq of 400Hz, there are about 1638 steps between 1000us and 2000us, equal to 10~11 bits resolution. But some legacy servo or ESCs doesn't support higher PWM frequency.

Setting of update rate also trades off. The higher update rate, the heavier load that CPU and I2C bus will facing. If the I2C bus is shared my multiple sensors then the update rate of PCA9685 should be kept minimal, to avoid sensor data congestion.

It's OK to set PWM freq and update rate to different value, but it won't make sense if update rate is higher than PWM freq.

The corresponding parameters:

  • PWM frequency: PCA9685_PWM_FREQ
  • update rate: PCA9685_SCHD_HZ

Output Configuration

Thanks to the code refactor around mixer and actuator, now it is much easier to configure those custom outputs:

image

It is very straight-forward in Actuator tab. Just select the required function and configure the standard parameters (min. max, disarmed, reverse).

PCA9685 driver has one extra flag that will put the channel into Duty-Cycle output mode, if enabled.

When Duty-Cycle mode is enabled for one channel:

  • This channel of PCA9685 becomes an "analog output", which can be used to blink an LED, or drive a L298N based brushed motor, etc.
  • min, max and disarmed value can be set between 0 and 4096, corresponding to no output (always low) and full output (always high)
  • if all channels are put into Duty-Cycle mode, then the maximum PWM frequency of 1536 can be set

Otherwise its output can be used to drive an ESC or servo, and PWM frequency is limited up to 400Hz.

In the above image, I've configured the first channel into Duty-Cycle mode and made it outputs RC AUX1. RC AUX1 is mapped to one of the knob on my radio. The first channel is connected to an LED directly (as there is already a 220R resistor on PCA9685 module per channel). Then after the vehicle is armed, the LED brightness is directly mapped to the knob input.

image

image

Final Words

It is not recommended to mix the usage of this module and FC's built-in outputs onto the same function, like controlling each half of motors on a multirotor with different modules, as they has different output capacity and latency, which may cause troubles.

The signal outputted from PCA9685 also has limited capacity, which can not be used to drive large RGB lights directly.

@SalimTerryLi
Copy link
Contributor Author

@dagar Made a guide about how to use this driver on a PIXHAWK. Any revision comments on that?

@DronecodeBot
Copy link

This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there:

https://discuss.px4.io/t/px4-community-q-a-may-24-2023/32263/1

if (param != PARAM_INVALID) {
param_get(param, &param_pwm_freq);
} else {
PX4_ERR("param PCA9685_SCHD_HZ not found");
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this say "param PCA9685_PWM_FREQ not found"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing :)

@SalimTerryLi
Copy link
Contributor Author

Any chance to get this one merged? Seems there are still some users here

@christianrauch Would you mind trying this branch?

@christianrauch
Copy link
Contributor

Any chance to get this one merged? Seems there are still some users here

@christianrauch Would you mind trying this branch?

I sent a PR that only adds the parameter for setting _targetFreq: #21937. This works for me.

@SalimTerryLi SalimTerryLi changed the title driver/pca9685_pwm_output: maintaince updates driver/pca9685_pwm_output: bugfixs & QGC integration & support outputting in duty-cycle mode Aug 8, 2023
@dagar
Copy link
Member

dagar commented Aug 8, 2023

I don't have this hardware, @christianrauch would you be interested in doing a quick review and regression test?

@SalimTerryLi
Copy link
Contributor Author

Any chance to get this one merged? Seems there are still some users here
@christianrauch Would you mind trying this branch?

I sent a PR that only adds the parameter for setting _targetFreq: #21937. This works for me.

Thanks for your feedback. PR title is adjusted according to the actual work done here. Hoping this may help someone later

Comment on lines 7 to 10
disarmed: { min: 800, max: 2200, default: 1000 }
min: { min: 800, max: 1400, default: 1000 }
max: { min: 1600, max: 2200, default: 2000 }
failsafe: { min: 800, max: 2200 }
disarmed: { min: 0, max: 4096, default: 1000 }
min: { min: 0, max: 4096, default: 1100 }
max: { min: 0, max: 4096, default: 1900 }
failsafe: { min: 0, max: 4096 }
Copy link
Contributor

Choose a reason for hiding this comment

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

This used to be the range 800...2200 to accommodate ESCs that are controlled by a PWM signal. Why change this to 0...4096?

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 it is capable to output in a totally different manner, according to:

PCA9685 driver has one extra flag that will put the channel into Duty-Cycle output mode, if enabled.

When Duty-Cycle mode is enabled for one channel:

  • This channel of PCA9685 becomes an "analog output", which can be used to blink an LED, or drive a L298N based brushed motor, etc.
  • min, max and disarmed value can be set between 0 and 4096, corresponding to no output (always low) and full output (always high)
  • if all channels are put into Duty-Cycle mode, then the maximum PWM frequency of 1536 can be set

Otherwise its output can be used to drive an ESC or servo, and PWM frequency is limited up to 400Hz.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. Still, could we keep the default values of 1000 / 2000?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see. Still, could we keep the default values of 1000 / 2000?

I have no strong opinion against that... @dagar any suggests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted back to normal mix/max values

@christianrauch
Copy link
Contributor

Can you rebase this on the current main? I am getting the compiler error: PCA9685.cpp:43:33: error: ‘CONFIG_PCA9685_INTERNAL_CRYSTAL_FREQ’ was not declared in this scope.

You can also squash your "typo fix" commit as it changes one of your earlier commits in the same PR.

@SalimTerryLi
Copy link
Contributor Author

Can you rebase this on the current main? I am getting the compiler error: PCA9685.cpp:43:33: error: ‘CONFIG_PCA9685_INTERNAL_CRYSTAL_FREQ’ was not declared in this scope.

You can also squash your "typo fix" commit as it changes one of your earlier commits in the same PR.

It is already sync with latest main branch, and CI is passing as well. Those macros comes from https://github.com/PX4/PX4-Autopilot/pull/21528/files#diff-f2c1d45a2903a6c0b039644a1de99115b809e6ddf209b28f8c3afa67c34486f0 , I'd suggest doing make xxx_your_board boardconfig and see if helps

@christianrauch
Copy link
Contributor

This seems to work.

But I am still confused about the parameter and their names. For PCA9685_SCHD_HZ can we not keep the "old" RATE as this is closer to the old behaviour? I understand that PCA9685_SCHD_HZ is the frequency at which PX4 sends commands to the PCA9685, and PCA9685_PWM_FREQ is a setting internal to the PCA9685. But this is not clear from the parameter names. One ends with "HZ" and the other with "FREQ". Aren't all frequencies given in Hz? Then for PCA9685_PWM_FREQ, there is a constraint on "MUST NOT exceed upper limit" which is dependent on the pulse width but not expressed in the min/max value. Is it possible to express this in terms of the "PWM update rate" (currently PCA9685_SCHD_HZ)?

@christianrauch
Copy link
Contributor

Btw, I noticed that the PWM will still be continuously sent after the PX4 process finishes if it does not get disarmed before.

Is there a way to have the PCA9685 timeout or similar so that it stops sending PWM signals if it does not get a new command via I2C in time? Can this be controlled via PCA9685_PWM_FREQ, i.e. do not send PWM signals if not commanded by the FC?

@SalimTerryLi
Copy link
Contributor Author

SalimTerryLi commented Aug 9, 2023

For PCA9685_SCHD_HZ can we not keep the "old" RATE as this is closer to the old behaviour?

That makes sense. I really have bad taste on naming stuffs... The old parameter really affects both the update rate from PX4 and the PWM frequency inside PCA9685

Is it possible to express this in terms of the "PWM update rate"

No, it is only related to PCA9685_PWM_FREQ which come from PCA9685 limitation. PCA9685_SCHD_HZ (or better PCA9685_SCHD_RATE) is only limited by I2C bus bandwidth. But since there is the proposal to keep the min/max to standard 1k~2k range, I think the change to PWM_FREQ can be done in sync with that. This will effectively make the duty-cycle mode an advanced usage but will ensure no one will accidentally wrongly mixing those two modes and create an invalid combination.

Is there a way to have the PCA9685 timeout or similar

No it is currently impossible due to the fact that the shutdown progress of px4 process is simply an exit(0) without any housekeeping. To solve that problem, a bunch of changes should be done to make PX4 gracefully shutdown. I'm slowly working on that, but it really is a pain. FYI the first step I take is #21578

But You may want to wrap the px4 process inside a script which will call another program once px4 exits, to disable the output of PCA9685, as a workaround

@dagar dagar merged commit f68f88b into PX4:main Oct 21, 2023
86 checks passed
@slgrobotics
Copy link
Contributor

slgrobotics commented Oct 26, 2023

I tested this on my lawnmower (using "main" branch), and it works great. I had a one-liner fix for the old code, just added a missing call to initialize output frequency to 50Hz. The new code works out of the box. Nice improvement showing actual frequency on "status". Old code accepted decimal port number ("-a 64"), new code works with hexes: "-a 0x40".
I am using the board in a "servo/ESC" mode, each wheel and other actuators behave like a common R/C servo.
@SalimTerryLi - Thanks for doing this work, you do have a happy user ;-)

@SalimTerryLi SalimTerryLi deleted the pr-pca9685-maintaince-update branch October 26, 2023 17:35
@DronecodeBot
Copy link

This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there:

https://discuss.px4.io/t/parameters-that-dont-show-up-in-qgc/36019/3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix 🐞 Drivers 🔧 Sensors, Actuators, etc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants