AUX pass through in Joystick

@JulianOes
Hey Julian,
I had a query, I am trying to integrate Joystick with PX4, I want to access the AUX channel, similar to what we achieve in direct RC connection, where RC pass through is possible.
could you tell me whether it is possible or not , what would be the ideal approach to achieve it.
Please guide me it, any help will be deeply appreciated

Taking a step back and without jumping to implementation, what do you actually want to do, high level?

  1. I want to enable AUX pass through so that I could implement turtle mode
    also
  2. Read the pwm values from the pinouts and pass them to control a servo motor to control the gimbal.
    I was able to do both in RC, but not in joystick.
  1. Shouldn’t joystick be just the same? QGC sends manual_control messages, which are what RC is mapped to within PX4, and from there control is calculated per motor (+whatever control loops are active).
  2. Controlling gimbal with a joystick is something that I’ve seen a few people looking for in QGC and PX4. I am not very sure about the gimbal architecture in Mavlink, but I think it should be implemented using Gimbal Protocol. Sorry it doesn’t answer your question but I wanted it to be seen.

@JulianOes @dotanAtTrim I want to control the servo motor which I have attached to the PWM pin 5, of the FC. while it was RC transmitter I have able to control the servo through the gimbal pitch but when I changed to joystick the options are different and the servo is not able to be controlled.
I want similar options as RC transmitter on joystick.

I see. So, you want to send manual control including Aux1.

Do we have to use MAVSDK, My approach was by using the manual_control module and use the option of photo and video trigger in the ManualControl.cpp to trigger the servo connected to a PWM pinout to go up and down.
I tried this by making the required changes to the ManuakControl.cpp, but I was not able to compile the px4. If feel I am using the wrong msg . Could you help me the approach, if it is correct.
As for the AUX connection, I figured, I could do the same here. assign button to Channel and hard code it.

You can also use MavlinkPassthrough to send your own MANUAL_CONTROL message, or you can use the Gripper plugin if you just need open/close control.

If you need me to do it for you, it will have to be paid. I can’t do charity all day.

I understand you are busy and you need to be paid for doing the task. I just wanted some guidance, if you are fine with it.
I am able to read the joystick changes and give action commands but eventhough the actuator_servo msg is changing the servo is not moving. I just want to know what msg is responsible for the servo to rotate when i use RC communication and gimbal pitch in actuator tab in QGC
It would be of great help if you could guide me in the correct direction.

// custom_joystick_gimbal.cpp

#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/tasks.h>
#include <px4_platform_common/posix.h>
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/log.h>
#include <drivers/drv_hrt.h>
#include <lib/mathlib/mathlib.h>
#include <uORB/uORB.h>
#include <uORB/topics/manual_control_setpoint.h>
// #include <uORB/topics/actuator_controls.h> // <--- REMOVE OR COMMENT OUT THIS LINE
#include <uORB/topics/actuator_servos.h> // <--- ADD THIS LINE FOR DIRECT SERVO CONTROL
#include <uORB/Publication.hpp>
#include <uORB/Subscription.hpp>

// Define the index for your servo in the actuator_servos_s.control array.
// If your servo is on PWM pin 5 (AUX OUT 1), it usually corresponds to index 0
// in the actuator_servos.control array, as AUX outputs often map sequentially.
// You will need to confirm this mapping in QGC's Actuator Configuration.
#define SERVO_CONTROL_INDEX 0 // Assuming AUX OUT 1 is the first servo control index
//#define ACTUATOR_SET_INDEX 4
// Define desired PWM values for your servo (normalized -1 to 1)
// Adjust these based on your servo's physical travel and the mixer configuration in QGC.
#define GIMBAL_UP_PWM_NORM      1.0f    // Example: Max deflection (e.g., 2000us PWM)
#define GIMBAL_DOWN_PWM_NORM    -1.0f   // Example: Min deflection (e.g., 1000us PWM)
#define GIMBAL_CENTER_PWM_NORM  0.0f    // Example: Center position (e.g., 1500us PWM)

// Define the values from manual_control_setpoint.aux5 that correspond to your button presses
// THESE ARE BASED ON YOUR PROVIDED LISTENER OUTPUTS
#define BUTTON_UP_VALUE     2048.0f // Value when 'Gimbal Up' button is pressed
#define BUTTON_DOWN_VALUE   4096.0f // Value when 'Gimbal Down' button is pressed
#define BUTTON_CENTER_VALUE 16384.0f // Value when 'Gimbal Center' button is pressed
#define BUTTON_IDLE_VALUE   0.0f    // Value when no specific gimbal button is pressed

#define BUTTON_VALUE_TOLERANCE 0.01f // Small tolerance for float comparison, good practice

extern "C" __EXPORT int custom_joystick_gimbal_main(int argc, char *argv[]);

static bool thread_running = false;
static int custom_joystick_gimbal_task = -1;

static int custom_joystick_gimbal_thread_main(int argc, char *argv[]);
static void usage();

int custom_joystick_gimbal_main(int argc, char *argv[])
{
    if (argc < 2) {
        usage();
        return PX4_ERROR;
    }

    if (!strcmp(argv[1], "start")) {
        if (thread_running) {
            PX4_WARN("custom_joystick_gimbal already running");
            return PX4_OK;
        }
        thread_running = true;
        custom_joystick_gimbal_task = px4_task_spawn_cmd("custom_joystick_gimbal_main",
                                     SCHED_DEFAULT,
                                     SCHED_PRIORITY_DEFAULT,
                                     2000, // Stack size
                                     custom_joystick_gimbal_thread_main,
                                     (char *const *)argv);
        return PX4_OK;
    }

    if (!strcmp(argv[1], "stop")) {
        if (!thread_running) {
            PX4_WARN("custom_joystick_gimbal not running");
            return PX4_OK;
        }
        thread_running = false;
        return PX4_OK;
    }

    if (!strcmp(argv[1], "status")) {
        if (thread_running) {
            PX4_INFO("custom_joystick_gimbal is running");
        } else {
            PX4_INFO("custom_joystick_gimbal is stopped");
        }
        return PX4_OK;
    }

    usage();
    return PX4_ERROR;
}

static int custom_joystick_gimbal_thread_main(int argc, char *argv[])
{
    PX4_INFO("custom_joystick_gimbal started! Listening for manual_control_setpoint.aux5.");

    // Subscriber for manual_control_setpoint
    uORB::Subscription manual_control_sub{ORB_ID(manual_control_setpoint)};

    // Publisher for actuator_servos
    uORB::Publication<actuator_servos_s> actuator_servos_pub{ORB_ID(actuator_servos)};

    // Actuator servos message
    actuator_servos_s act_servos{};
    // Initialize all servo controls to a neutral value
    for (size_t i = 0; i < sizeof(act_servos.control) / sizeof(act_servos.control[0]); ++i) { // CORRECTED LINE
        act_servos.control[i] = 0.0f;
    }
    act_servos.control[SERVO_CONTROL_INDEX] = GIMBAL_CENTER_PWM_NORM; // Initialize specific servo to center

    manual_control_setpoint_s manual_control_setpoint{};

    while (thread_running) {
        // Wait for new manual_control_setpoint data
        manual_control_sub.update(&manual_control_setpoint);

        float observed_button_value = manual_control_setpoint.aux5;

        // Add debug log to see the raw aux5 value
        PX4_INFO("Aux5: %.2f", (double)observed_button_value); // Use (double) for PX4_INFO float formatting

        float target_pwm_norm = act_servos.control[SERVO_CONTROL_INDEX]; // Default to current position

        if (fabsf(observed_button_value - BUTTON_UP_VALUE) < BUTTON_VALUE_TOLERANCE) {
            target_pwm_norm = GIMBAL_UP_PWM_NORM;
            PX4_INFO("Gimbal Up button detected. Setting servo to UP (%.2f).", (double)target_pwm_norm);
        } else if (fabsf(observed_button_value - BUTTON_DOWN_VALUE) < BUTTON_VALUE_TOLERANCE) {
            target_pwm_norm = GIMBAL_DOWN_PWM_NORM;
            PX4_INFO("Gimbal Down button detected. Setting servo to DOWN (%.2f).", (double)target_pwm_norm);
        } else if (fabsf(observed_button_value - BUTTON_CENTER_VALUE) < BUTTON_VALUE_TOLERANCE) {
            target_pwm_norm = GIMBAL_CENTER_PWM_NORM;
            PX4_INFO("Gimbal Center button detected. Setting servo to CENTER (%.2f).", (double)target_pwm_norm);
        } else if (fabsf(observed_button_value - BUTTON_IDLE_VALUE) < BUTTON_VALUE_TOLERANCE) {
            // Optional: If you want the servo to return to center when no gimbal button is pressed
            // target_pwm_norm = GIMBAL_CENTER_PWM_NORM;
            // PX4_INFO("Gimbal buttons idle. Setting servo to CENTER (%.2f).", (double)target_pwm_norm);
        }


        // Apply limits
        target_pwm_norm = fmaxf(-1.0f, fminf(1.0f, target_pwm_norm));

        // Update the actuator servos message for the specific servo
        act_servos.control[SERVO_CONTROL_INDEX] = target_pwm_norm;
        act_servos.timestamp = hrt_absolute_time();

        // Add debug log to confirm what's being published
        PX4_INFO("Publishing actuator_servos.control[%d] = %.2f", SERVO_CONTROL_INDEX, (double)act_servos.control[SERVO_CONTROL_INDEX]);


        // Publish the command
        actuator_servos_pub.publish(act_servos);

        px4_usleep(10000); // 10ms delay, results in ~100Hz update rate
    }

    PX4_INFO("Exiting custom_joystick_gimbal task.");
    thread_running = false;
    return 0;
}

static void usage()
{
    PX4_INFO("Usage: custom_joystick_gimbal {start|stop|status}");
    PX4_INFO("  start: Start the custom joystick gimbal control module.");
    PX4_INFO("  stop: Stop the module.");
    PX4_INFO("  status: Check if the module is running.");
    PX4_INFO("This module controls a servo (e.g., gimbal) on an AUX PWM output");
    PX4_INFO("based on QGC joystick button input via manual_control_setpoint.aux5.");
    PX4_INFO("  Ensure the corresponding AUX PWM output is configured as 'Offboard Actuator Set 1' (or similar) in QGC.");
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.