Lua script - requesting recommandations

Hi,
I would appreciate some comments on what i have designed using lua script for drone excitation by commanding velocities. I have tested out this script and the drone flew nicely, but extremely slow. I have no experience in lua scripts nor Arducopter controller interface, but I am learning. Your help will prevent me to crash my drone.

I have re-written the script such that it fly faster and in a horizontal circular manner (sort of lissajou pattern). The script is shown below along with the list of hardware I am using to fly my drone. Who ever got knowledge in lua scripts, could you please give me some comments on what I coded in order to ensure that the maneuver is safe to be applied?

Hardware:
X500 V2 holybro
Pixhawk 6X
11 inch props
ESC Telemetery is used (AM60 Skystar)

Script:

-- copter-fly-lissajous-fast.lua
--
-- Increases Lissajous pattern frequency for faster horizontal speeds.
-- Vehicle will:
--   1) Wait for armed + RC6 > 1800
--   2) Switch to Guided
--   3) Take off to 15m
--   4) Once at altitude, fly a Lissajous pattern
--   5) Then switch to RTL after 'pattern_duration' seconds

local takeoff_alt_above_home = 15
local copter_guided_mode_num = 4
local copter_rtl_mode_num = 6

-- Lissajous parameters: increased freq for more speed
local freq_x    = 1.0     -- [Hz] horizontal frequency in X (was 0.5)
local freq_y    = 2.0     -- [Hz] horizontal frequency in Y (was 1.0)
local amp_x     = 3       -- [m] amplitude along X
local amp_y     = 3       -- [m] amplitude along Y
local phase_x   = 0
local phase_y   = 0

-- Fly the pattern for this many seconds before switching to RTL
local pattern_duration = 30  -- [s]

-- Script update rate: 0.1s (10 Hz)
local time_step = 0.1    

local stage  = 0
local time_s = 0

local yaw_cos = 0
local yaw_sin = 0

function update()
    if not arming:is_armed() then
        -- reset if disarmed
        stage  = 0
        time_s = 0
        return update, 100
    end

    local pwm6 = rc:get_pwm(6)
    if pwm6 and pwm6 > 1800 then
        if stage == 0 then
            -- Stage 0: switch to Guided mode
            if vehicle:set_mode(copter_guided_mode_num) then
                local yaw_rad = ahrs:get_yaw()
                yaw_cos = math.cos(yaw_rad)
                yaw_sin = math.sin(yaw_rad)
                stage = 1
                gcs:send_text(0, "Script: Switching to GUIDED")
            end

        elseif stage == 1 then
            -- Stage 1: take off to 15m
            if vehicle:start_takeoff(takeoff_alt_above_home) then
                stage = 2
                gcs:send_text(0, "Script: Takeoff initiated to 15m")
            end

        elseif stage == 2 then
            -- Stage 2: wait for altitude
            local home = ahrs:get_home()
            local curr_loc = ahrs:get_location()
            if home and curr_loc then
                local vec_from_home = home:get_distance_NED(curr_loc)
                local alt_above_home = -vec_from_home:z()  -- negative Z is up

                gcs:send_text(0, string.format("Current alt: %.1f / 15.0", alt_above_home))
                if math.abs(takeoff_alt_above_home - alt_above_home) < 1 then
                    stage = 3
                    gcs:send_text(0, "Script: Reached ~15m, starting fast Lissajous")
                end
            end

        elseif stage == 3 then
            -- Stage 3: Fly Lissajous pattern
            if time_s >= pattern_duration then
                stage = 4
            else
                time_s = time_s + time_step

                -- Derivatives for x(t)=amp_x*sin(freq_x*t + phase_x)
                local dx_local = amp_x * freq_x * math.cos(freq_x * time_s + phase_x)
                -- Derivatives for y(t)=amp_y*sin(freq_y*t + phase_y)
                local dy_local = amp_y * freq_y * math.cos(freq_y * time_s + phase_y)

                -- rotate local velocity by initial yaw
                local target_vel = Vector3f()
                target_vel:x(yaw_cos * dx_local - yaw_sin * dy_local)
                target_vel:y(yaw_sin * dx_local + yaw_cos * dy_local)
                target_vel:z(0)

                if not vehicle:set_target_velocity_NED(target_vel) then
                    gcs:send_text(0, "Script: Failed fast Lissajous velocity command")
                end
            end

        elseif stage == 4 then
            -- Stage 4: switch to RTL
            vehicle:set_mode(copter_rtl_mode_num)
            stage = 5
            gcs:send_text(0, "Script: Lissajous done → Switching to RTL")
        end
    end

    return update, 100  -- 0.1 seconds
end

return update()

no one got any recommendations how can i safely test it?

I can’t offer any help in the script, but you can test it in SITL. Load the simulator in Mission Planner and then you can load the script and run it just as you would on your drone.

I have never used SITL before from ardupilot. Ill give it a try by read the docs. Thank you for pointing it out

Hi again, so i had the chance to test on sitl and fly it in real life. Everything wen fine however, i am trying to achieve a higher speed maneuver.
Do you know what commands or functionality i shall code to control the speed using lua script?

Thank you in advance.

You could try

vehicle:set_desired_speed(param1)
1 Like

Hi, again. I have my lua script working and the behavior i am intending is being achieved.
I have one question: at the moment i arm the drone while on ground and then use RC6 channel to activate the lua script. Then the drone reaches a certain altitude and apply the mission. I was wondering if it is possible to do while in mid-air? Does the controller interface allow such thing?
I could not find such specific information in the lua script doc.. but maybe i missed it.

I have adjusted the lua script trying to activate it in mid-air the same why but with success so thats why i was wondering if the controller interface can accept it like that or not

Does it return an error? Or any kind of message back when it doesn’t work? I’m not clear what you’re trying to do.

You can’t activate a script in the air. You must run it in a continuous callback loop from boot time. You can alter its behavior based on any number of conditions. One of those behaviors can simply be to check for a trigger condition and then return a callback with no other actions if not met.

No idea what you’re trying to do, but RC inputs can be used as conditions just as easily during flight as they can on the ground. Waypoints can be written and overwritten just the same.

Some of what you’re suggesting seems like it could just be done entirely with an auto mission rather than employing a script, but your vague descriptions are unhelpful.

Thank you for your reply.

I am designed a lissajou pattern that allow the drone oscillate at specific amplitude and frequency. What i am trying to do is to have some sort of clear data. Letting the drone fly in mid air while its steady and then execute the maneuver. I would like to stop it and execute it again without the need of landing. I tried to adjust the script to do what i want but still no success.

Does it return an error? Or any kind of message back when it doesn’t work? I’m not clear what you’re trying to do.

My attempt did not show anything when i manually flew with alt-hold and then activated the channel that i set for lua script.

You must run it in a continuous callback loop from boot time.

My understanding to lua scripts is limited. This is my first time using it. So i could not fully understand what you said. Can i share the script? and if you had the time to guide a little more detailed then ill be grateful.

Do you think you are missing a state machine within the callback loop from boot time? One such example.