Communication Systems
Reliable communication between the pilot (or ground station) and the drone is essential. This lesson covers the full communication stack from RC links to 5G cellular connections.
Communication Architecture Overview
Sponsored
Radio Control (RC) Protocols
python
class RCProtocol:
"""Model different RC protocols"""
PROTOCOLS = {
"PWM": {"channels": 8, "resolution": 1024, "latency_ms": 20, "digital": False},
"PPM": {"channels": 8, "resolution": 1024, "latency_ms": 20, "digital": False},
"SBUS": {"channels": 16, "resolution": 2048, "latency_ms": 4, "digital": True},
"IBUS": {"channels": 14, "resolution": 4096, "latency_ms": 5, "digital": True},
"CRSF": {"channels": 16, "resolution": 4096, "latency_ms": 1, "digital": True},
"ELRS": {"channels": 16, "resolution": 4096, "latency_ms": 1, "digital": True},
}
@classmethod
def compare(cls):
print("RC Protocol Comparison:\n")
print(f"{'Protocol':<10} {'Channels':<10} {'Resolution':<12} {'Latency':<10} {'Type':<10}")
print("-" * 55)
for name, specs in cls.PROTOCOLS.items():
ptype = "Digital" if specs["digital"] else "Analog"
print(f"{name:<10} {specs['channels']:<10} {specs['resolution']:<12} "
f"{specs['latency_ms']}ms{'':<5} {ptype:<10}")
@classmethod
def recommend(cls, use_case):
recommendations = {
"racing": ("ELRS/CRSF", "1ms latency, long range, fast response"),
"freestyle": ("ELRS", "Good range, excellent response"),
"long_range": ("ELRS (900MHz)", "Up to 40km range"),
"beginner": ("SBUS", "Widely supported, reliable"),
"cinema": ("SBUS/CRSF", "Smooth, reliable control"),
}
return recommendations.get(use_case, ("ELRS", "Best all-around choice"))
RCProtocol.compare()
for use in ["racing", "long_range", "beginner"]:
proto, reason = RCProtocol.recommend(use)
print(f"\n{use}: {proto} â {reason}")
MAVLink Protocol
MAVLink (Micro Air Vehicle Link) is the standard protocol for drone communication.
python
class MAVLinkMessage:
"""Simplified MAVLink message model"""
def __init__(self, msg_id, system_id, component_id, payload):
self.msg_id = msg_id
self.sys_id = system_id
self.comp_id = component_id
self.payload = payload
self.crc = self._compute_crc()
def _compute_crc(self):
"""Simplified CRC calculation"""
data = f"{self.msg_id}{self.sys_id}{self.comp_id}{self.payload}"
return sum(ord(c) for c in data) % 65536
def serialize(self):
"""Convert to bytes for transmission"""
return {
"stx": 0xFE,
"length": len(str(self.payload)),
"sysid": self.sys_id,
"compid": self.comp_id,
"msgid": self.msg_id,
"payload": self.payload,
"crc": self.crc
}
def __repr__(self):
return f"MAVLink[sys={self.sys_id} comp={self.comp_id} msg={self.msg_id}]"
class MAVLinkMessageTypes:
"""Common MAVLink message types"""
HEARTBEAT = 0
SYS_STATUS = 1
GPS_RAW_INT = 24
ATTITUDE = 30
COMMAND_LONG = 76
COMMAND_ACK = 77
SET_POSITION_TARGET = 86
MISSION_ITEM = 39
STATUSTEXT = 253
# Create sample messages
heartbeat = MAVLinkMessage(
msg_id=MAVLinkMessageTypes.HEARTBEAT,
system_id=1,
component_id=1,
payload={"type": 2, "autopilot": 3, "base_mode": 64, "custom_mode": 0}
)
gps = MAVLinkMessage(
msg_id=MAVLinkMessageTypes.GPS_RAW_INT,
system_id=1,
component_id=1,
payload={"lat": 377749000, "lon": -1224194000, "alt": 50000, "satellites": 12}
)
print(f"Heartbeat: {heartbeat}")
print(f" Serialized: {heartbeat.serialize()}")
print(f"\nGPS: {gps}")
print(f" Lat: {gps.payload['lat']/1e7:.6f}")
print(f" Lon: {gps.payload['lon']/1e7:.6f}")
Link Budget Analysis
Advertisement
python
def link_budget(frequency_mhz, tx_power_dbm, tx_gain_dbi, rx_gain_dbi,
distance_km, margin_db=10):
"""Calculate link budget for a wireless link"""
# Free space path loss (FSPL)
import math
fspl = 20 * math.log10(distance_km) + 20 * math.log10(frequency_mhz) + 32.45
# Received signal strength
rx_power = tx_power_dbm + tx_gain_dbi + rx_gain_dbi - fspl - margin_db
# Link margin
sensitivity_dbm = -100 # Typical receiver sensitivity
link_margin = rx_power - sensitivity_dbm
return {
"fspl_db": fspl,
"rx_power_dbm": rx_power,
"link_margin_db": link_margin,
"viable": link_margin > 0
}
# Compare different links
links = [
("RC 2.4GHz (ELRS)", 2400, 20, 2, 2, 1),
("Telemetry 915MHz", 915, 20, 2, 2, 5),
("4G LTE", 800, 23, 0, 0, 10),
]
for name, freq, tx_p, tx_g, rx_g, dist in links:
result = link_budget(freq, tx_p, tx_g, rx_g, dist)
print(f"{name} @ {dist}km:")
print(f" Path loss: {result['fspl_db']:.1f} dB")
print(f" RX power: {result['rx_power_dbm']:.1f} dBm")
print(f" Link margin: {result['link_margin_db']:.1f} dB")
print(f" Viable: {'Yes' if result['viable'] else 'No'}\n")
Bandwidth Requirements
python
bandwidth_needs = {
"RC Commands": {"rate_hz": 50, "size_bytes": 16, "total_kbps": 6.4},
"Telemetry": {"rate_hz": 4, "size_bytes": 100, "total_kbps": 3.2},
"GPS Waypoints": {"rate_hz": 1, "size_bytes": 50, "total_kbps": 0.4},
"Video Feed": {"rate_hz": 30, "size_bytes": 50000, "total_kbps": 12000},
"AI Inference": {"rate_hz": 10, "size_bytes": 10000, "total_kbps": 800},
}
print("Bandwidth Requirements:\n")
print(f"{'Stream':<20} {'Rate':<10} {'Size':<12} {'Bandwidth':<12}")
print("-" * 55)
for name, specs in bandwidth_needs.items():
print(f"{name:<20} {specs['rate_hz']}Hz{'':<6} "
f"{specs['size_bytes']}B{'':<8} {specs['total_kbps']}Kbps")
Hands-On Project: Telemetry Parser
python
class TelemetryParser:
def __init__(self):
self.messages = []
def parse_heartbeat(self, data):
return {
"type": "HEARTBEAT",
"flight_mode": data.get("custom_mode", 0),
"armed": bool(data.get("base_mode", 0) & 128),
"voltage": data.get("voltage_battery", 0) / 1000,
}
def parse_gps(self, data):
return {
"type": "GPS",
"latitude": data.get("lat", 0) / 1e7,
"longitude": data.get("lon", 0) / 1e7,
"altitude": data.get("alt", 0) / 1000,
"satellites": data.get("satellites_visible", 0),
"fix_type": data.get("fix_type", 0),
}
def parse_attitude(self, data):
import math
return {
"type": "ATTITUDE",
"roll": math.degrees(data.get("roll", 0)),
"pitch": math.degrees(data.get("pitch", 0)),
"yaw": math.degrees(data.get("yaw", 0)),
}
def display(self, parsed):
print(f"\n{'='*40}")
for key, value in parsed.items():
if isinstance(value, float):
print(f" {key}: {value:.4f}")
else:
print(f" {key}: {value}")
parser = TelemetryParser()
# Simulate incoming data
parser.display(parser.parse_heartbeat({
"custom_mode": 4, "base_mode": 128, "voltage_battery": 14800
}))
parser.display(parser.parse_gps({
"lat": 377749000, "lon": -1224194000, "alt": 50000,
"satellites_visible": 14, "fix_type": 3
}))
parser.display(parser.parse_attitude({
"roll": 0.05, "pitch": -0.02, "yaw": 1.57
}))
Summary
- RC links (2.4GHz): Low-latency control, safety-critical, always required
- Telemetry (433/915MHz): Bidirectional data, status updates, waypoint upload
- 4G/5G: High bandwidth for video and AI, unlimited range, but higher latency
- MAVLink is the universal protocol for drone-ground station communication
- Link budget analysis ensures reliable communication at target ranges
- Always maintain a redundant RC link â never rely solely on cellular!
Next, we'll cover GPS navigation basics.