diff --git a/boards/ark/fmu-v6x/default.px4board b/boards/ark/fmu-v6x/default.px4board index e2433a53cb..d72a3f8a4e 100644 --- a/boards/ark/fmu-v6x/default.px4board +++ b/boards/ark/fmu-v6x/default.px4board @@ -40,6 +40,7 @@ CONFIG_DRIVERS_MAGNETOMETER_ST_IIS2MDC=y CONFIG_DRIVERS_POWER_MONITOR_INA226=y CONFIG_DRIVERS_POWER_MONITOR_INA228=y CONFIG_DRIVERS_POWER_MONITOR_INA238=y +CONFIG_DRIVERS_PCA9685_PWM_OUT=y CONFIG_DRIVERS_PWM_OUT=y CONFIG_DRIVERS_PX4IO=y CONFIG_COMMON_RC=y diff --git a/boards/ark/fmu-v6x/init/rc.board_sensors b/boards/ark/fmu-v6x/init/rc.board_sensors index c16ed31f69..7b2259f8ad 100644 --- a/boards/ark/fmu-v6x/init/rc.board_sensors +++ b/boards/ark/fmu-v6x/init/rc.board_sensors @@ -97,5 +97,11 @@ bmm150 -I start # Internal Baro on I2C bmp388 -I start +# Start an external PWM generator +if param greater PCA9685_EN_BUS 0 +then + pca9685_pwm_out start +fi + unset HAVE_PM2 unset HAVE_PM3 diff --git a/boards/ark/fpv/default.px4board b/boards/ark/fpv/default.px4board index abea5574b0..d4515d5f67 100644 --- a/boards/ark/fpv/default.px4board +++ b/boards/ark/fpv/default.px4board @@ -21,6 +21,7 @@ CONFIG_DRIVERS_IMU_MURATA_SCH16T=y CONFIG_COMMON_LIGHT=y CONFIG_COMMON_MAGNETOMETER=y CONFIG_DRIVERS_OSD_MSP_OSD=y +CONFIG_DRIVERS_PCA9685_PWM_OUT=y CONFIG_DRIVERS_PWM_OUT=y CONFIG_COMMON_RC=y CONFIG_DRIVERS_UAVCAN=y diff --git a/boards/ark/fpv/init/rc.board_sensors b/boards/ark/fpv/init/rc.board_sensors index 896b9ffd7d..e719938f86 100644 --- a/boards/ark/fpv/init/rc.board_sensors +++ b/boards/ark/fpv/init/rc.board_sensors @@ -16,3 +16,9 @@ iis2mdc -R 0 -I -b 4 start # Internal Baro on I2C bmp388 -I -b 2 start + +# Start an external PWM generator +if param greater PCA9685_EN_BUS 0 +then + pca9685_pwm_out start +fi diff --git a/boards/ark/pi6x/default.px4board b/boards/ark/pi6x/default.px4board index dda45cdf23..6ad26366b3 100644 --- a/boards/ark/pi6x/default.px4board +++ b/boards/ark/pi6x/default.px4board @@ -19,6 +19,7 @@ CONFIG_COMMON_LIGHT=y CONFIG_DRIVERS_MAGNETOMETER_MEMSIC_MMC5983MA=y CONFIG_DRIVERS_MAGNETOMETER_ST_IIS2MDC=y CONFIG_DRIVERS_OPTICAL_FLOW_PAW3902=y +CONFIG_DRIVERS_PCA9685_PWM_OUT=y CONFIG_DRIVERS_POWER_MONITOR_INA226=y CONFIG_DRIVERS_PWM_OUT=y CONFIG_COMMON_RC=y diff --git a/boards/ark/pi6x/init/rc.board_sensors b/boards/ark/pi6x/init/rc.board_sensors index cc97b1d601..c128fbca35 100644 --- a/boards/ark/pi6x/init/rc.board_sensors +++ b/boards/ark/pi6x/init/rc.board_sensors @@ -34,3 +34,9 @@ paw3902 -s -b 3 start -Y 90 # Internal distance sensor afbrs50 start + +# Start an external PWM generator +if param greater PCA9685_EN_BUS 0 +then + pca9685_pwm_out start +fi diff --git a/boards/auterion/fmu-v6s/init/rc.board_sensors b/boards/auterion/fmu-v6s/init/rc.board_sensors index 4c4be283d7..ccf6536cf0 100644 --- a/boards/auterion/fmu-v6s/init/rc.board_sensors +++ b/boards/auterion/fmu-v6s/init/rc.board_sensors @@ -74,5 +74,5 @@ ist8310 -X -b 1 -R 10 start # Start an external PWM generator if param greater PCA9685_EN_BUS 0 then - pca9685_pwm_out start -b 1 + pca9685_pwm_out start fi diff --git a/boards/bluerobotics/navigator/init/rc.board_defaults b/boards/bluerobotics/navigator/init/rc.board_defaults index 18dc930ba7..ca136db1e3 100644 --- a/boards/bluerobotics/navigator/init/rc.board_defaults +++ b/boards/bluerobotics/navigator/init/rc.board_defaults @@ -11,3 +11,7 @@ param set BAT1_V_DIV 5.7 # Always keep current config param set SYS_AUTOCONFIG 0 + +# PCA9685 PWM Out defaults +param set-default PCA9685_EN_BUS 4 +param set-default PCA9685_I2C_ADDR 64 diff --git a/boards/bluerobotics/navigator/init/rc.board_sensors b/boards/bluerobotics/navigator/init/rc.board_sensors index 411995664b..790099d8af 100644 --- a/boards/bluerobotics/navigator/init/rc.board_sensors +++ b/boards/bluerobotics/navigator/init/rc.board_sensors @@ -28,7 +28,7 @@ then echo "ads1115 not found." fi -if ! pca9685_pwm_out start -a 0x40 -b 4 +if ! pca9685_pwm_out start then echo "pca9685_pwm_out not found." fi diff --git a/docs/en/advanced_config/parameter_reference.md b/docs/en/advanced_config/parameter_reference.md index a9a13e4984..aa05292a85 100644 --- a/docs/en/advanced_config/parameter_reference.md +++ b/docs/en/advanced_config/parameter_reference.md @@ -486,6 +486,16 @@ The integer refers to the I2C bus number where PCA9685 is connected. | ------ | -------- | -------- | --------- | ------- | ---- | |   | 0 | 10 | | 0 | +### PCA9685_I2C_ADDR (`INT32`) {#PCA9685_I2C_ADDR} + +I2C address of PCA9685. + +The default address is 0x40 (64). + +| Reboot | minValue | maxValue | increment | default | unit | +| ------ | -------- | -------- | --------- | ------- | ---- | +|   | 0 | 127 | | 64 | + ### PCA9685_FAIL1 (`INT32`) {#PCA9685_FAIL1} PCA9685 Output Channel 1 Failsafe Value. diff --git a/docs/en/modules/modules_driver.md b/docs/en/modules/modules_driver.md index 2b0b2a6b7e..9db2c26c0c 100644 --- a/docs/en/modules/modules_driver.md +++ b/docs/en/modules/modules_driver.md @@ -899,6 +899,8 @@ fetching the latest mixing result and write them to PCA9685 at its scheduling ti It can do full 12bits output as duty-cycle mode, while also able to output precious pulse width that can be accepted by most ESCs and servos. +The I2C bus and address can be configured via parameters `PCA9685_EN_BUS` and `PCA9685_I2C_ADDR`, or via command line arguments. + ### Examples It is typically started with: diff --git a/platforms/common/Serial.cpp b/platforms/common/Serial.cpp index 748dcba9b2..a129fe2492 100644 --- a/platforms/common/Serial.cpp +++ b/platforms/common/Serial.cpp @@ -74,6 +74,11 @@ ssize_t Serial::bytesAvailable() return _impl.bytesAvailable(); } +ssize_t Serial::txSpaceAvailable() +{ + return _impl.txSpaceAvailable(); +} + ssize_t Serial::read(uint8_t *buffer, size_t buffer_size) { return _impl.read(buffer, buffer_size); diff --git a/platforms/common/include/px4_platform_common/Serial.hpp b/platforms/common/include/px4_platform_common/Serial.hpp index 983834ccf6..bf14035a5e 100644 --- a/platforms/common/include/px4_platform_common/Serial.hpp +++ b/platforms/common/include/px4_platform_common/Serial.hpp @@ -62,6 +62,7 @@ public: bool close(); ssize_t bytesAvailable(); + ssize_t txSpaceAvailable(); ssize_t read(uint8_t *buffer, size_t buffer_size); ssize_t readAtLeast(uint8_t *buffer, size_t buffer_size, size_t character_count = 1, uint32_t timeout_ms = 0); diff --git a/platforms/nuttx/src/px4/common/SerialImpl.cpp b/platforms/nuttx/src/px4/common/SerialImpl.cpp index f8968e4881..9bee2ddf23 100644 --- a/platforms/nuttx/src/px4/common/SerialImpl.cpp +++ b/platforms/nuttx/src/px4/common/SerialImpl.cpp @@ -293,12 +293,36 @@ ssize_t SerialImpl::bytesAvailable() { if (!_open) { PX4_ERR("Device not open!"); + errno = EBADF; return -1; } ssize_t bytes_available = 0; int ret = ioctl(_serial_fd, FIONREAD, &bytes_available); - return ret >= 0 ? bytes_available : 0; + + if (ret < 0) { + return -1; + } + + return bytes_available; +} + +ssize_t SerialImpl::txSpaceAvailable() +{ + if (!_open) { + PX4_ERR("Device not open!"); + errno = EBADF; + return -1; + } + + ssize_t space_available = 0; + int ret = ioctl(_serial_fd, FIONSPACE, &space_available); + + if (ret < 0) { + return -1; + } + + return space_available; } ssize_t SerialImpl::read(uint8_t *buffer, size_t buffer_size) diff --git a/platforms/nuttx/src/px4/common/include/SerialImpl.hpp b/platforms/nuttx/src/px4/common/include/SerialImpl.hpp index 82e4ddd29d..32c549ad6e 100644 --- a/platforms/nuttx/src/px4/common/include/SerialImpl.hpp +++ b/platforms/nuttx/src/px4/common/include/SerialImpl.hpp @@ -60,6 +60,7 @@ public: bool close(); ssize_t bytesAvailable(); + ssize_t txSpaceAvailable(); ssize_t read(uint8_t *buffer, size_t buffer_size); ssize_t readAtLeast(uint8_t *buffer, size_t buffer_size, size_t character_count = 1, uint32_t timeout_us = 0); diff --git a/platforms/posix/include/SerialImpl.hpp b/platforms/posix/include/SerialImpl.hpp index 82e4ddd29d..32c549ad6e 100644 --- a/platforms/posix/include/SerialImpl.hpp +++ b/platforms/posix/include/SerialImpl.hpp @@ -60,6 +60,7 @@ public: bool close(); ssize_t bytesAvailable(); + ssize_t txSpaceAvailable(); ssize_t read(uint8_t *buffer, size_t buffer_size); ssize_t readAtLeast(uint8_t *buffer, size_t buffer_size, size_t character_count = 1, uint32_t timeout_us = 0); diff --git a/platforms/posix/src/px4/common/SerialImpl.cpp b/platforms/posix/src/px4/common/SerialImpl.cpp index cb12b6919d..4859832829 100644 --- a/platforms/posix/src/px4/common/SerialImpl.cpp +++ b/platforms/posix/src/px4/common/SerialImpl.cpp @@ -281,12 +281,31 @@ ssize_t SerialImpl::bytesAvailable() { if (!_open) { PX4_ERR("Device not open!"); + errno = EBADF; return -1; } ssize_t bytes_available = 0; int ret = ioctl(_serial_fd, FIONREAD, &bytes_available); - return ret >= 0 ? bytes_available : 0; + + if (ret < 0) { + return -1; + } + + return bytes_available; +} + +ssize_t SerialImpl::txSpaceAvailable() +{ + if (!_open) { + PX4_ERR("Device not open!"); + errno = EBADF; + return -1; + } + + // POSIX/Linux doesn't have a direct equivalent to NuttX's FIONSPACE + errno = ENOSYS; + return -1; } ssize_t SerialImpl::read(uint8_t *buffer, size_t buffer_size) diff --git a/platforms/qurt/include/SerialImpl.hpp b/platforms/qurt/include/SerialImpl.hpp index c7739429ef..09797a33f7 100644 --- a/platforms/qurt/include/SerialImpl.hpp +++ b/platforms/qurt/include/SerialImpl.hpp @@ -59,6 +59,7 @@ public: bool close(); ssize_t bytesAvailable(); + ssize_t txSpaceAvailable(); ssize_t read(uint8_t *buffer, size_t buffer_size); ssize_t readAtLeast(uint8_t *buffer, size_t buffer_size, size_t character_count = 1, uint32_t timeout_us = 0); diff --git a/platforms/qurt/src/px4/SerialImpl.cpp b/platforms/qurt/src/px4/SerialImpl.cpp index 5c31be9a5c..c7d78baffe 100644 --- a/platforms/qurt/src/px4/SerialImpl.cpp +++ b/platforms/qurt/src/px4/SerialImpl.cpp @@ -156,14 +156,33 @@ ssize_t SerialImpl::bytesAvailable() { if (!_open) { PX4_ERR("Device not open!"); + errno = EBADF; return -1; } uint32_t rx_bytes = 0; - (void) fc_uart_rx_available(_serial_fd, &rx_bytes); + int ret = fc_uart_rx_available(_serial_fd, &rx_bytes); + + if (ret < 0) { + return -1; + } + return (ssize_t) rx_bytes; } +ssize_t SerialImpl::txSpaceAvailable() +{ + if (!_open) { + PX4_ERR("Device not open!"); + errno = EBADF; + return -1; + } + + // QURT doesn't have a direct equivalent to NuttX's FIONSPACE + errno = ENOSYS; + return -1; +} + ssize_t SerialImpl::read(uint8_t *buffer, size_t buffer_size) { if (!_open) { diff --git a/src/drivers/pca9685_pwm_out/main.cpp b/src/drivers/pca9685_pwm_out/main.cpp index 2d22c36a77..44464e9511 100644 --- a/src/drivers/pca9685_pwm_out/main.cpp +++ b/src/drivers/pca9685_pwm_out/main.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include "PCA9685.h" @@ -356,8 +357,30 @@ int PCA9685Wrapper::custom_command(int argc, char **argv) { int PCA9685Wrapper::task_spawn(int argc, char **argv) { int ch; - int address=PCA9685_DEFAULT_ADDRESS; - int iicbus=PCA9685_DEFAULT_IICBUS; + int address = PCA9685_DEFAULT_ADDRESS; + int iicbus = PCA9685_DEFAULT_IICBUS; + + int32_t en_bus = 0; + param_t param_handle = param_find("PCA9685_EN_BUS"); + + if (param_handle != PARAM_INVALID) { + param_get(param_handle, &en_bus); + + if (en_bus > 0) { + iicbus = en_bus; + } + } + + int32_t i2c_addr = 0; + param_handle = param_find("PCA9685_I2C_ADDR"); + + if (param_handle != PARAM_INVALID) { + param_get(param_handle, &i2c_addr); + + if (i2c_addr > 0) { + address = i2c_addr; + } + } int myoptind = 1; const char *myoptarg = nullptr; diff --git a/src/drivers/pca9685_pwm_out/module.yaml b/src/drivers/pca9685_pwm_out/module.yaml index 57294c0c81..18d999830a 100644 --- a/src/drivers/pca9685_pwm_out/module.yaml +++ b/src/drivers/pca9685_pwm_out/module.yaml @@ -29,6 +29,16 @@ parameters: min: 0 max: 10 default: 0 + PCA9685_I2C_ADDR: + description: + short: I2C address of PCA9685 + long: | + I2C address of PCA9685. + The default address is 0x40 (64). + type: int32 + min: 1 + max: 127 + default: 64 PCA9685_SCHD_HZ: description: short: PWM update rate diff --git a/src/modules/esc_battery/EscBattery.cpp b/src/modules/esc_battery/EscBattery.cpp index 78d1c2c71f..6dfc17aeb3 100644 --- a/src/modules/esc_battery/EscBattery.cpp +++ b/src/modules/esc_battery/EscBattery.cpp @@ -105,7 +105,6 @@ EscBattery::Run() } average_voltage_v /= online_esc_count; - total_current_a /= online_esc_count; average_temperature_c /= online_esc_count; _battery.setConnected(true);