Cant get LUA script to run

I have set SCR = 1 and heap size to a fairly large value, but I cannot get a LUA script to run. I get no errors when loading the script, but when I try to run, It always fails on the first line no matter what I do. The script is very simple and simply holds heading whenever RC6 is above 1500. I never get a chance to debug any functionality.

The code is below. There is nothing else in the script directory.

function update()
while( true )
    local rcChannel6 = rc_channels(6)
    if rcChannel6 > 1500 then
        local zeroRate = 0.0
        set_rc_override(4, zeroRate)  
        return update, 100
return update ()

To name a few issues: an unclosed function statement, bindings misused/misnamed, invalid PWM value, use of an infinite loop (ArduPilot will fail the script intentionally after a short duration due to CPU resource scheduling), and attempted use of sleep (not implemented in the ArduPilot Lua engine).

Try this:

local RC4 = rc:get_channel(4)
local RC4_MIN = param:get('RC4_MIN') or 1000

function update()
    if rc:get_pwm(6) > 1500 then
    return update, 100

return update()

Also, I don’t think this will do what you want, but it implements the logic you attempted above. RC overrides are a poor choice in the first place for course hold, and this, as implemented, will just command a hard left yaw.

What you probably want is a switch to guided mode with a target that is updated along the desired course, which should be set at the time of triggering. Will require some failsafe-like features and should probably use the aux switch function for polling RC6.

And have a look at the copious examples of how to use the bindings within the ArduPilot Lua sandbox:
ardupilot/libraries/AP_Scripting/examples at master · ArduPilot/ardupilot (

Search my username in the Lua category for a lot of examples and some videos as well.

1 Like

Thanks for the reply, but in this instance, the controller doesn’t have access to GPS OR Compass, so Guided mode isn’t an option. I simply want to hold heading as accurately as possible using whatever dead reckoning abilities the controller can provide. Holding the RCIn at fixed levels would be a start, but that wouldn’t deal with winds or other disturbances.

Well, I guess you can just override using the RC4_TRIM value instead of RC4_MIN, but this seems almost pointless. It’d be about as precise to simply trust the pilot not to move the yaw stick.

Also, most RC transmitters provide mixing features that would do exactly the same thing as this rather odd script.

Or you could just increase RC4_DZ such that it takes more stick motion to move the yaw command away from neutral.

Yes, it is an odd request for an odd application. I can’t set the deadzone to a huge value initially, because I need fine control until channel 6 is set to a high value. At that time I want the copter to try to say on the same path using the gyros regardless of the stick control.

When I try to run your script, I get the following in the MP ‘script’ console window.

Error running script
local RC4 = rc.get_channel(4)
SyntaxError: invalid syntax

This isn’t a Python script, and it cannot be run by Mission Planner.

Follow the instructions here to upload it to your autopilot:
Lua Scripts — Copter documentation (

I still think you should probably just implement this very basic feature on your RC transmitter directly. Use a script once you have some means of monitoring position and heading. IMU dead reckoning alone will not suffice for any meaningful heading hold or navigation features, as it seems you’re aware.

I already have it loaded into the subdirectory ‘scripts’ in the uSD card. I just thought I could load it directly using MP for faster testing. Apparently not.

The MP tab ‘scripts’ looked like it might be a way.

It will not run locally inside Mission Planner. Once the script is uploaded, and SCR_ENABLE is set to 1, it will automatically run on the autopilot upon boot.

I copied your script as-is into a CUBE Black.
I have deleted all the terrain and log files.
No matter what heap size I use, I always get the msg:

PreArm: Scripting:out of memory

or Scripting: Unable to allocate memory

Something has to be wrong.

The Cube Black is just barely capable of scripting, and I would not recommend using it if scripting is your goal. I have gotten a script to run on one, but just barely, and not well.

You could try 20480 or 10240 for heap sizes, but I’ll make zero promises that it works.

Nah. Same reason I retired the Pixracers.

Yep, we’ve come a long way since the days when ArduPilot’s entire feature set could be crammed into an Atmega chip. The STM32 F-series opened the path to where we are, but they are quickly being overcome by events, as well!

Recommend an STM32 H7 based autopilot if you want to leverage all of the features presently offered.

Thanks, I’ll try it on my Cube Orange or my Matek 743 Wing controller. But I really wanted to mess around with scripting on an older/cheaper flier. A mistake could be fatal to the airframe.

You can try a customized Cube Black firmware build that excludes unnecessary features using ArduPilot Custom Firmware Builder.

You can set the dead zone dynamically with the script.

But unless you explain your use case more thoroughly, I think I’m probably going to bow out for now.

Unfortunately, my use case must be kept secret. The script does appear to run on a CUBE Orange and an h743 board.

I do have a few more questions though. Please indulge me a bit more. I have read the docs but do not understand them fully.

If I set RCx option to 301 (script_2), does that automatically invoke a script I have placed in the file named SCR_USER2 and if I set RCx option to 302 (script_3), does that invoke the script named SCR_USER3?

Do RCx input values lower than 1500uSec equate to FALSE (don’t run the script) and values above 1500uSec equate to TRUE (do run the selected script)?

If I would set - say RC7 to 301, does it simply invoke the script or must other testing be done? In other words, if I invoke a script with RC7, do I have to again read the RC7 value from within the script in order to decide what action that script should take?

If I use an IF-THEN statement without an ELSE, do the parameters that I have set with the script return to their previous values if the IF-THEN statement is FALSE (not executed), or do I have to read the values before changing them with the script and restore them with the ELSE statement.

Similarly, if I use the RCx parameter set to (say) 301, and use that to invoke a script, does the parameter get automatically restored when I change the value of RCx to FALSE? In other words, if RCx invokes the script, what happens when RCx becomes FALSE?

I need to know these things because failure to restore values to their previous settings upon user command would almost certainly result in a crash.

Between this statement and another you made recently, I’m afraid I won’t be indulging this any farther.

You seem like a nice enough guy, but I can’t get involved with these kinds of “secrets.”