Hi Paul,
Would you mind sharing your full script for this please. I assume it is a lua script? Thanks, Ger.
Hi Paul,
Would you mind sharing your full script for this please. I assume it is a lua script? Thanks, Ger.
sorry, which script for what, iāve a few.
Hi Paul,
Thanks for replying.
The script you use for measuring the engine rpm and adjusting the travel speed automatically.
as below - I used Yuriās rough terrain detector script and modified it to read the rpm() sensor
you need to be able to read the RPM() - i used a magnet attached to the flywheel and a cheap sensor generating a pulse. Also need to be able to send speed up and slow down commands - check the script.
You need to be able to run lua scriptsā¦
This made a big difference to the 15hp mower, but upgrading to a bigger mower with more HP removed the problem (their is no substitute for cubes
example of it working - https://www.youtube.com/watch?v=sqJrKHLVQNo
--[[----------------------------------------------------------------------------
TerrainRPMDetector ArduPilot Lua script
Uses gyro and accelerometer data to detect rough terrain and slow the
vehicle's speed accordingly during auto missions.
Provides a set of custom tuning parameters:
ROUGH_SPEED : (m/s) rough terrain desired speed, set to -1 to disable detection
ROUGH_RPM_RED : Blade struggling - Do something
ROUGH_RPM_GREEN : Blade/motor at speed - Clear Red and get on with it
ROUGH_RPM_RED : 1000 RPM Or lower - STOP Until
ROUGH_RPM_GREEN : 2000 - Go
CAUTION: This script is capable of engaging and disengaging autonomous control
of a vehicle. Use this script AT YOUR OWN RISK.
-- Yuri -- Jul 2022 + Paul Dec 2023 with RPM Sensor on Robomower
LICENSE - GNU GPLv3 https://www.gnu.org/licenses/gpl-3.0.en.html
Concept first presented during this live stream:
https://www.youtube.com/watch?v=UdXGXjigxAo&t=7155s
Credit to @ktrussell for the idea and discussion!
------------------------------------------------------------------------------]]
local SCRIPT_NAME = 'LongGrassRPM'
local RUN_INTERVAL_MS = 25 -- needs to be pretty fast for good detection
local SBY_INTERVAL_MS = 500 -- slower interval when detection is disabled
local PARAM_TABLE_KEY = 118 -- unique index value between 0 and 200
-- GCS messages
local VERBOSE_MODE = 1 -- 0 to suppress all GCS messages,
-- 1 for normal status messages
-- 2 for additional debug messages
local MSG_NORMAL = 1
local MSG_DEBUG = 2
-- MAVLink values
local MAV_SEVERITY_WARNING = 4
local MAV_SEVERITY_INFO = 6
-- create custom parameter set
local function add_params(key, prefix, tbl)
assert(param:add_table(key, prefix, #tbl), string.format('Could not add %s param table.', prefix))
for num = 1, #tbl do
assert(param:add_param(key, num, tbl[num][1], tbl[num][2]), string.format('Could not add %s%s.', prefix, tbl[num][1]))
end
end
add_params(PARAM_TABLE_KEY, 'ROUGH_', {
-- { name, default value },
{ 'SPEED', 0.2 },
{ 'RPM_RED', 2140},
{ 'RPM_GREEN', 2170},
{ 'TIMEOUT_MS', 5000}
})
-- wrapper for gcs:send_text()
local function gcs_msg(msg_type, severity, txt)
if type(msg_type) == 'string' then
-- allow just a string to be passed for simple/routine messages
txt = msg_type
msg_type = MSG_NORMAL
severity = MAV_SEVERITY_INFO
end
if type(severity) == 'string' then
-- allow just severity and string to be passed for normal messages
txt = severity
severity = msg_type
msg_type = MSG_NORMAL
end
if msg_type <= VERBOSE_MODE then
gcs:send_text(severity, string.format('%s: %s', SCRIPT_NAME, txt))
end
end
-- debug values
local wp_speed_normal = nil
local wp_speed_rough = nil
function standby()
wp_speed_rough = param:get('ROUGH_SPEED')
if wp_speed_rough < 0 then return standby, SBY_INTERVAL_MS end
if mission:state() == mission.MISSION_RUNNING then
-- only poll remaining parameters at start of mission
wp_speed_normal = param:get('WP_SPEED')
revs_green = param:get('ROUGH_RPM_GREEN')
revs_red = param:get('ROUGH_RPM_RED')
-- if ROUGH_SPEED param not set or invalid, use half of WP_SPEED
if wp_speed_rough == 0 or wp_speed_rough > wp_speed_normal then
wp_speed_rough = wp_speed_normal / 2
if wp_speed_rough == nil then
gcs_msg(MAV_SEVERITY_WARNING, 'ROUGH_SPEED wp_rough_speed is nil')
end
gcs_msg(MAV_SEVERITY_WARNING, 'ROUGH_SPEED invalid, using half WP_SPEED')
end
return do_normal_speed, RUN_INTERVAL_MS
end
return standby, SBY_INTERVAL_MS
end
function initiate_rough_speed()
gcs_msg(MSG_NORMAL, MAV_SEVERITY_WARNING, 'Slowing for Long Grass : ',wp_speed_rough )
vehicle:set_desired_speed(wp_speed_rough)
return do_rough_speed, RUN_INTERVAL_MS
end
function initiate_zero_speed()
gcs_msg(MSG_NORMAL, MAV_SEVERITY_WARNING, 'STOPPING 5 sec for RPM recovery')
vehicle:set_desired_speed(0) -- stop the train
return do_rough_speed,RUN_INTERVAL_MS
end
function initiate_normal_speed()
gcs_msg(MSG_NORMAL, MAV_SEVERITY_WARNING, 'resume Normal speed',wp_speed_normal)
vehicle:set_desired_speed(wp_speed_normal)
return do_normal_speed, RUN_INTERVAL_MS
end
function do_normal_speed()
if mission:state() ~= mission.MISSION_RUNNING then
return standby, SBY_INTERVAL_MS
end
local revs = RPM:get_rpm(0) or 0 -- if nil -1 then sets it to zero so no error
if revs == 0 then -- slow down
gcs_msg(MSG_DEBUG, MAV_SEVERITY_INFO, string.format('ICE Motor Not running - HOLD mode', revs))
vehicle:set_mode(4) --mode HOLD
return initiate_zero_speed, RUN_INTERVAL_MS
end
if revs < revs_red then -- stop for a bit to recover
gcs_msg(MSG_DEBUG, MAV_SEVERITY_INFO, string.format('RPM RED - Stopping ', revs))
return initiate_zero_speed, RUN_INTERVAL_MS
end
if revs < revs_green then -- slow down
gcs_msg(MSG_DEBUG, MAV_SEVERITY_INFO, string.format('RPM Amber - Slowing ', revs))
return initiate_rough_speed, RUN_INTERVAL_MS
end
return do_normal_speed, RUN_INTERVAL_MS
end
function do_rough_speed()
if mission:state() ~= mission.MISSION_RUNNING then
return standby, SBY_INTERVAL_MS
end
local now = millis()
local revs = RPM:get_rpm(0) or 0
if revs > revs_green then -- no longer in rough terrain
gcs_msg(MSG_DEBUG, MAV_SEVERITY_INFO, string.format('Revs Recovered - normal speed ', wp_speed_normal))
return initiate_normal_speed, RUN_INTERVAL_MS
end
return do_rough_speed, RUN_INTERVAL_MS
end
gcs_msg('Script active')
return standby, SBY_INTERVAL_MS
Thanks for sharing this LUA script. I am definitely going to mount a sensor and use this.
Thanks Paul.
So I have a cube orange and have 2 lua scripts running already, the gps and tuning scripts. But I havent tried to write my own. I will have a go at adopting your script to my setup. Thanks.
I wasnt aware of Yuriās rough terrain script, thanks for that also.
We implemented an RPM monitoring/speed modulating script at MowStock 2025 while you were there, @SJohnson . This one by @kiwiPaul probably works just as well, though I havenāt really reviewed it myself. Iām glad my rough terrain script was a good starting point!
Yuri, is your version of this script on your website?
Thanks
I didnāt save a personal copy. It was a quick and dirty demo. @Swebre might have it.
I was a bit disappointed that Mowstock 2026 was postponed, but wanted to share what I think is the best deal for RTK setups.
For $160 you get 1GB data per month which has been enough for my RTK needs. Forever!
I have a base station on my roof sending correction data to rtk2go. Put the puck in my machine, connect to it via esp8266, and send correction data to my f9p gps modules. Seems to work pretty well as long as LTE is in the area.
My setup does not require any additional data purchase for the lifetime 1GB/month.
Just wanted to share.
-Allen