Mavproxy Server Implementation
MAVProxy can be used to control autopilots by using mavlink commands. As a first step into allowing an Android phone to control the autopilot using the famous applications such as 3DR's Tower wirelessly without the need for any new hardware, I allowed mavproxy to be controller through a Tcp/Udp client.
If you haven't installed Mavproxy yet, here is how to do it.
Through this post, I'll show you how you can modify Mavproxy to run a Tcp/Udp server. If you are not interested in how it is done, and just want the final code, you can find it here on github.
To run a TCP server:
To run a UDP server:
You can run both TCP and UDP servers simultaneously, but only the UDP server will be able to write mavlink commands. This is not advised.
Steps into getting there
Learn Tcp/Udp programming in Python
Since mavproxy is written in python, then we do have to modify it in python. For starters, to run a UDP server, this snippet of code would open port
4123 on the machine and print whatever is sent to it.
>>> import sys, socket >>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) >>> s.bind(('0.0.0.0', 4123)) >>> while 1: ... data,addr = s.recvfrom(1024) ... print data
To run a UDP client, that can be done easily through a linux terminal in bash.
nc 127.0.0.1 4123 -u -v
And you'd be able to send to the server.
If this worked locally for you, but remotely it didn't, check your firewall settings.
Modify mavproxy's input
Looking through mavproxy's code in
mavproxy.py, there is a function called
input_loop(). This function waits for user input. We would want to redirect the input from keyboard to the Tcp/Udp server set.
The previous code was:
def input_loop(): '''wait for user input''' while mpstate.status.exit != True: try: if mpstate.status.exit != True: line = raw_input(mpstate.rl.prompt) except EOFError: mpstate.status.exit = True sys.exit(1) mpstate.input_queue.put(line)
If we want a UDP server to listen to input here, recklessly we can modify it as such:
def input_loop(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(('0.0.0.0', 4123)) '''wait for user input''' while mpstate.status.exit != True: try: if mpstate.status.exit != True: data,addr = s.recvfrom(1024) line = data # line = raw_input(mpstate.rl.prompt) except EOFError: mpstate.status.exit = True sys.exit(1) mpstate.input_queue.put(line)
Remember to add the
And that is it. Whatever now is sent through UDP on this port will be run as a command.
Modify mavproxy's output
To read the log, we would also have to send the log back to the UDP client. If we look around, you'd find that writing is done by
console is a
TextConsole class that is available in
modules/lib/textconsole.py. Looking at its output code:
def write(self, text, fg='black', bg='white'): '''write to the console''' if isinstance(text, str): sys.stdout.write(text) else: sys.stdout.write(str(text)) sys.stdout.flush()
We can add
s.sendto(data, address), to be able to send to the client.
You would have to be able to read the socket
Cleaning things up
To clean things up:
Create a class for UdpServer and TcpServer. In my project, you can find them under
Add parser options in
--tcpoptions to allow you to run the servers upon will.
Put everything where it should be.
Now that I can connect and send commands remotely to the autopilot, it is time to be able to use the Android applications to control the autopilot. Maybe someone can add a functionality for mavproxy to understand mavlink packets directly.