INTRODUCTION
You can write your own software running to send commands and receive live data using UDP (and soon TCP) protocols to send and receive plain ASCII text to / from Ground Control application ("GC") connected to a live plane. You can use any language, platform, machine and location to/from which UDP/TCP packets can be sent and received.
Ruby will only accept control commands from GC if the handheld user has explicitly handed control over to the PC by flipping the mode switch, or if no handheld signal is being received. See [flight control].
Contact jim@uthere.com to obtain sample and utility applications written in C#: "follow_the_leader" and "udp_terminal".
Commands shown in brown, GC parameters and variables shown in blue.
CONNECTING TO GROUND CONTROL
UDP ports set using GC parameters: "udp_port_in"
udp_port_in |
GC incoming / your application outgoing port number. Default: 10000 |
udp_port_out |
GC outgoing / your application incoming port number. Default: 10001 |
Currently only supporting UDP packets, not yet TCP. Having occasional issues with lost packets, especially if many are sent over the internet without pause in between. When added, TCP support should remove lost packets but with higher bandwidth requirement.
If your software is running on same machine, use IP address 127.0.0.1
GETTING PLANE ID
request_plane_list - list of planeids hosted at this ip.
These are used with "plane=" in subsequent commands that you send to ensure that your command is sent to the correct plane.
DATA REQUEST COMMANDS
data_request(plane=12345,variable=airspeed,interval = 0.5) - request data sending
data_request(plane=12345,variable=latitude,interval = 0.5)
data_request(plane=12345,variable=longitude,interval = 0.5)
data_request(plane=12345,variable=altitude,interval = 0.5)
data_request(plane=12345,variable=course,interval = 0.5)
data_request(plane=12345,variable=power_battery_voltage,interval = 0.5)
... In addition, any variable displayed in "Variables" display in GC may be monitored using data_request. Just change spaces in the variable name to underscore "_".
data_request(plane=12345,variable=all, interval = 0.5) - request all variables in one packet
data_pause - suspend sending data from host for all planes
data_resume - resume sending data for all planes
data_remove(plane=12345,variable=longitude) - remove a variable
data_clear - clear all data send variables
PACKETS RETURNED BY data_request COMMAND
data(1208472993.743, plane=1234, latitude=75.012)
data_all(1208472993.743, plane=1234, latitude=75.012, longitude=-123.54, altitude=400, airspeed=20)
WAYPOINT COMMANDS
fly_to(plane=12345,latitude=75.13345,longitude=-123.4556,altitude=123,airspeed=21)
- sends this waypoint directly to plane with true option, waypoint bypasses buffer
waypoint_clear_all - clears all waypoints from buffer
waypoint_add(waypointid=14, nextwaypointid=16, plane=102, latitude=75.13345,longitude=-123.4556,altitude=123,airspeed=21)
- adds a waypoint to the buffer, but does not send it to the plane
fly_to_waypoint(12) - will start sending the buffered waypoints from this waypoint. Waypoints are chained together with the nextwaypointids.
Here's a complete [sample script] which skywrites letters "Ruby" using waypoints.
CONTROL TARGET STATE DIRECTLY ("fly()" command)
fly(plane=###,{latitude+longitude | course | heading | roll}=###, {airspeed | pitch}=###, {altitude | climb | throttle}=###)
Units:
all headings / angles in degrees
climb: feet per second,
throttle: % (set to zero for gliding)
examples:
fly(plane=12345,roll=-15,pitch=10.3,throttle=65)
fly(plane=12345,heading=265,airspeed=19.5,climb=5.0)
Certain combinations of parameters not currently supported. For instance, pitch = can't be used with airspeed= climb= (latter is possible to implement, but I'll omit now to reduce complexity)
User will typically stream fly commands at rate of 1 to 5 hz.
Ruby will switch to waypoint or return to home mode and ignore subsequent fly() commands if:
- "deadman timeout": more than 2 secs elapse without receiving a new fly command, or
- any "cage" threshold is exceeded (see variables)
fly_engage(plane=###) // reset Ruby "cage" to allow fly() commands to be recognized. You should immediately begin streaming fly commands after this
fly_disenage(plane=###) // tell Ruby to immediately go to "if signal is lost" mode (typically set to waypoint or return to home) and ignore further fly() commands instead of waiting 2 seconds for timeout
fly and fly_to_waypoint commands can be interspersed in a mission, bracketed by fly_engage, fly_disengage.
For a hands on demonstration: See "Fly command demo"
Implementing fly() command in your software:
Typically, if your application is streaming fly() commands, it will use data_request to monitor the metrics ap_target_from_packet_cage_triggered_last , and optionally also cage_triggered and ap_target_from_packet_enabled. fly_engage() sets ap_target_from_packet_enabled to 1 and clears ap_target_from_packet_cage_triggered_last to 0. If your plane goes out of cage parameters, does not send an updated fly() command within timeout ap_target_from_packet_timeout, or your application sends a fly() command with values outside of cage parameters, Ruby will set ap_target_from_packet_enabled to 0, causing further fly() commands to be ignored, and will set ap_target_from_packet_cage_triggered_last to indicate which parameter(s) were exceeded. Once Ruby autopilot has restored plane back to within cage parameters, cage_triggered will be set back to zero and your application can then issue a fly_engage() command and resume issuing fly() commands.
You'll probably also want to monitor control_operate_mode to see that Ruby is in Waypoint mode and ready to accept waypoint or fly commands.
cage_triggered |
The current status of the plane's state in relation to the "cage" . This is always updated regardless of whether fly() command is being executed.
A bitmap showing which parameters have been violated.
public enum CageTrigger
{
Altitude=0,
Climb,
Throttle,
RangeSoft,
RangeHard,
HandheldLostComm,
PacketTImeoutForSelectedMode,
PacketTimeoutLostComm,
Airspeed,
Roll,
Pitch,
Wingload,
BatteryWarn,
BatteryEmergency,
Unspecified,
Target,
GPSBad,
NavLost,
IMUdisabled=18
}
i.e.
"(cage_triggered & (1 << Roll))"
which is
"(cage_triggered & (1<<9)))"
tells you if the roll limit was exceeded. |
ap_target_from_packet_cage_triggered_last |
Value of cage_triggered which last caused ap_target_from_packet_enabled to be set to 0. Is cleared to zero when fly_engage() is called and first valid fly() command is received. |
ap_target_from_packet_enabled |
fly() commands will be ignored if ap_target_from_packet_enabled==0
use fly_engage() to set ap_target_from_packet_enabled to 1.
cage violation or timeout will set ap_target_from_packet_enabled = 0
|
control_operate_mode |
GC / Ruby will also only accept waypoint or fly() commands when in "Waypoint" mode = 3 or PacketTarget mode = 24.
Only the IFR operator can place Ruby in Waypoint mode, from which fly() commands can move it to PacketTarget mode. |
Note that GC now has a display screen: View: Cage which displays cage_triggered and ap_target_from_packet_cage_triggered_last.
Cage parameters
Cage parameters are set in Ground Control / Ruby configuration (currently requires editing of XML files and loading into Ruby ROM). It's not currently possible for your application to modify them.
Regardless of current operating mode, cage_triggered will always be updated to indicate whether plane's current state is within cage parameters. Exiting the cage will currently only trigger Ruby to go to "if signal is lost" mode when the fly() command is being used.
Ruby will also go to "signal is lost" mode if your application issues a fly() command specifying target parameters outside the cage.
These are listed with further description in GC under Display : variables : cage
cage_altitude_maximum
cage_altitude_minimum
cage_climb_maximum
cage_climb_minimum
cage_throttle_maximum
cage_range
cage_airspeed_max
cage_airspeed_min
cage_roll_max
cage_pitch_min
cage_pitch_max
cage_wingload_max
ap_target_from_packet_timeout (typically 1 to 10 seconds)
Other commands
request_client_ip_list - list of ip addresses served by this computer
(not sure why you'd need this)
|