I will be trying to send data via UART from the Pi+Navigator to an arduino. The Arduino will handle motor control, receiving feedback from the motor’s Hall effect sensors, as well as receiving setpoint data input from the user through cockpit.
I have limited knowledge on pymavlink and communications protocols, so if there is any posts on here already providing a bit of a guid on where to get started, please let me know. I wasn’t able to find one with my first search. If anyone has any tips or samples that I can use, that will also be very useful.
A Navigator used with ArduPilot firmware typically expects motor outputs to be controlled using one of the available MOT_PWM_TYPE signals, output through the servo header.
There may be a way to use a Lua script in the autopilot to read the current intended motor outputs (or motion outputs, one abstraction level up) and communicate those through one of the serial buses to your Arduino, but I’m not sure there will be existing examples for that kind of application.
thanks for pointing that out. I found some Lua examples for reading serial communications in the link you provided.
What are the serial ports on the Navigator board intended to be used for? I expected some more straight forward support for serial communications since there is the physical connections already there.
Hi @DFord -
The serial ports on the Navigator can be used for any serial device connections - the input is either handled by the users code (via NodeRed, Jupyter, or another BlueOS Extension), or if ArduPilot has support for the device (like GPS, rangefinders, weather stations, etc.) than the port can be “connected” to the autopilot in the Autopilot Firmware menu (in pirate mode) and configured for that process to access. With the appropriate device type parameter set for the serial port, the autopilot takes it from there!
For your case, you could develop a BlueOS python extension that read motor values from Mavlink2Rest, and output them via the Serial ports in whatever format you require… However doing so with a Lua script may provide better performance!
That sounds like an interesting project. Ive been looking into Lua scripts and the Winch example you made a post about back in 2024 and I had a few follow up questions. How is the Lua script typically called/activated (from the code it looks like the Lua script is called when the boat reaches a certain way point and receives an activation signal) Is it a custom widget, joystick control, extension, other function I dont know about? For my use case I will likely not have enough button slots available on the joystick to control/call the Lua script and had planned to use a custom widget in cockpit or extension. Would it be straight forward to configure a Custom Action to send motor setpoint data from cockpit to the Lua script?
P.S. you say
but I am unable to find this file location in ardupilot but was able to find ardupilot/Tools/scripts. Are these the same?
Have you enabled lua scripts (SCR_ENABLE under Autopilot Paremeters in BlueOS), and restarted the autopilot (via power button in lower left of BlueOS)? What version of ArduSub are you running?
Lua scripts are always running, inside the autopilot! That particular winch example specifically is triggering at every waypoint not on the done list
function waypoint_is_done()
current_index = mission:get_current_nav_index()
for x=0, #done_waypoints do
if done_waypoints[x] == current_index then
return true
end
end
return false
end
function current_waypoint_should_lower_winch()
current_index = mission:get_current_nav_index()
if waypoint_is_done() then
return false
end
return true
-- for x=0, #winch_waypoints do
-- if winch_waypoints[x] == current_index then
-- return true
-- end
-- end
-- return false
end
The commented out code in the second half was left, to illustrate another approach to triggering based on waypoint #.
The script sits running in standingby state, sending 1500 pwm to the winch motor, waiting for a waypoint to be reached before “taking over” and switching out of auto to loiter mode, then running the winch operations. By switching back to auto mode when finished, the route continues, and the cycle will repeat when the next waypoint is reached!
Now that Ive got some time working with Lua scripts under my belt I had a few questions.
Ive worked out a quick and simple serial connection test. I have a serial connection from serial 4 to a arduino nano setup running a simple blinky script where the navigator sends a high signal (asci 76 ‘H’ and the low ‘L’ 72) to the nano and the nanos LED blinks every second.
On boot, it seems that any Lua script I create only runs for about 5 seconds before sending a const 255 high signal without end. I can fix this by restarting autopilot and the blinky code will run find with the odd 255 high signal mixed in between the intended 76 and 72 signals. Do you know why lua scripts might not work properly on cold boot and why I get the occasional Junk signal?
I have serial 4 set to 9600 and scripting
Lua:
local port = serial:find_serial(0)
if not port then
gcs:send_text(0, “Lua: no scripting serial found”)
return
end
– Match Arduino baud
port:begin(9600)
port:set_flow_control(0)
local state = false – false → L, true → H
function send_hi_lo()
local byte_to_send
local char_label
if state then
byte_to_send = string.byte(“H”) – 72
char_label = “H”
else
byte_to_send = string.byte(“L”) – 76
char_label = “L”
end
port:write(byte_to_send) – NOW a number, not a string
state = not state
gcs:send_text(0, “Lua sent: " .. char_label .. " (” .. byte_to_send .. “)”)
return send_hi_lo, 1000 – run again in 1 second
end
return send_hi_lo, 1000
Arduino:
#include <SoftwareSerial.h>
const uint8_t NAV_RX_PIN = 2; // From Navigator TX
const uint8_t NAV_TX_PIN = 3; // (not used yet)
SoftwareSerial navSerial(NAV_RX_PIN, NAV_TX_PIN); // RX, TX
void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600); // USB debug
navSerial.begin(9600); // Must match Lua
navSerial.listen();
Serial.println(“Nano: waiting for Navigator bytes…”);
}
void loop() {
while (navSerial.available()) {
char c = navSerial.read();
int code = (int)c & 0xFF; // force to 0–255
Serial.print("Byte: ");
Serial.print(code);
Serial.print(" char: '");
Serial.print((code >= 32 && code <= 126) ? c : '.');
Serial.println("'");
// LED control only on clean H/L
if (c == 'H') {
digitalWrite(13, HIGH);
} else if (c == 'L') {
digitalWrite(13, LOW);
}
}
}