Skip to content

Commit 9294141

Browse files
committed
added offbaord from stream
1 parent d49a4b1 commit 9294141

File tree

4 files changed

+571
-0
lines changed

4 files changed

+571
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""
2+
Drone Velocity and Yaw Control Sender
3+
=====================================
4+
5+
This script enables real-time control of a drone's velocity and yaw using keyboard inputs.
6+
It sends velocity setpoints in the body frame and commands for yaw adjustments, allowing
7+
for dynamic control through familiar keyboard keys.
8+
9+
Key Bindings:
10+
- 'W': Move forward
11+
- 'S': Move backward
12+
- 'A': Move left
13+
- 'D': Move right
14+
- Up Arrow: Increase altitude
15+
- Down Arrow: Decrease altitude
16+
- Left Arrow: Yaw left
17+
- Right Arrow: Yaw right
18+
- 'Q': Quit the application
19+
20+
The drone must be configured to receive and process these commands, typically in an offboard control mode.
21+
22+
Author:
23+
- Alireza Ghaderi
24+
- GitHub: alireza787b
25+
- Date: April 2024
26+
w
27+
Usage:
28+
Run the script in a compatible Python environment where the drone control system can
29+
receive UDP packets. Use the keys to control the drone's movement and orientation.
30+
"""
31+
32+
import socket
33+
import sys
34+
import select
35+
from control_packet import ControlPacket, SetpointMode
36+
37+
import socket
38+
import keyboard # Using the keyboard library for non-blocking key reads
39+
from control_packet import ControlPacket, SetpointMode
40+
41+
# Constants for communication and control
42+
UDP_IP = "127.0.0.1"
43+
UDP_PORT = 5005
44+
DEFAULT_SPEED = 1.0 # meters per second
45+
DEFAULT_YAW_RATE = 5.0 # degrees per second, incremental
46+
47+
# Setup UDP socket for sending commands
48+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
49+
50+
def send_velocity_body(velocity_x, velocity_y, velocity_z, yaw_rate=0):
51+
"""Send a velocity command with optional yaw rate to the drone."""
52+
packet = ControlPacket(
53+
mode=SetpointMode.VELOCITY_BODY,
54+
enable_flag=True,
55+
yaw_control_flag=True,
56+
position=(0, 0, 0),
57+
velocity=(velocity_x, velocity_y, velocity_z),
58+
acceleration=(0, 0, 0),
59+
attitude=(0, 0, 0, yaw_rate),
60+
attitude_rate=(0, 0, 0, 0)
61+
)
62+
packed_data = packet.pack()
63+
sock.sendto(packed_data, (UDP_IP, UDP_PORT))
64+
print(f"Sent: Velocity=({velocity_x}, {velocity_y}, {velocity_z}) Yaw={yaw_rate}")
65+
66+
def main():
67+
print("Drone Velocity and Yaw Control Sender Running...")
68+
print("Use W, A, S, D, Arrow keys, and H to control the drone. Press 'Q' to quit.")
69+
70+
vx, vy, vz, yaw_rate = 0, 0, 0, 0
71+
72+
while True:
73+
try:
74+
if keyboard.is_pressed('q'):
75+
print("Quitting...")
76+
break
77+
78+
if keyboard.is_pressed('w'):
79+
vx = DEFAULT_SPEED
80+
elif keyboard.is_pressed('s'):
81+
vx = -DEFAULT_SPEED
82+
elif keyboard.is_pressed('a'):
83+
vy = -DEFAULT_SPEED
84+
elif keyboard.is_pressed('d'):
85+
vy = DEFAULT_SPEED
86+
87+
if keyboard.is_pressed('up'):
88+
vz = DEFAULT_SPEED
89+
elif keyboard.is_pressed('down'):
90+
vz = -DEFAULT_SPEED
91+
92+
if keyboard.is_pressed('left'):
93+
yaw_rate -= DEFAULT_YAW_RATE
94+
elif keyboard.is_pressed('right'):
95+
yaw_rate += DEFAULT_YAW_RATE
96+
97+
if keyboard.is_pressed('h'):
98+
# Hold current velocities and yaw rate
99+
send_velocity_body(vx, vy, vz, yaw_rate)
100+
continue
101+
102+
send_velocity_body(vx, vy, vz, yaw_rate)
103+
104+
except Exception as e:
105+
print(f"Error: {str(e)}")
106+
107+
# Reset velocities and yaw rate after sending to simulate continuous control
108+
vx, vy, vz, yaw_rate = 0, 0, 0, 0
109+
110+
# Ensure the drone stops moving when the script exits
111+
send_velocity_body(0, 0, 0, 0)
112+
sock.close()
113+
114+
if __name__ == "__main__":
115+
main()
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
"""
2+
ControlPacket Module for Drone Communication
3+
============================================
4+
5+
Overview:
6+
---------
7+
This Python module provides the ControlPacket class, which is central to creating,
8+
packing, and unpacking control packets used for drone control operations via MAVSDK
9+
or other compatible UAV control systems. It supports a variety of control modalities
10+
including position, velocity, acceleration, and direct attitude control.
11+
12+
The control packets are designed to be transmitted over UDP, enabling real-time
13+
control of drones with high reliability and minimal latency. The packets include
14+
comprehensive setpoints for sophisticated flight dynamics and maneuvers.
15+
16+
Features:
17+
---------
18+
- Multiple Control Modes: Supports various modes such as POSITION_GLOBAL_LATLON,
19+
POSITION_LOCAL_NED, VELOCITY_NED, and ATTITUDE_CONTROL, among others.
20+
- Yaw Control: Optional direct yaw control alongside standard setpoints, allowing
21+
for dynamic adjustment of the drone's orientation.
22+
- Binary Packing: Uses Python's `struct` module for efficient binary packing and
23+
unpacking of control data, suitable for high-performance network transmission.
24+
- Error Handling: Robust error handling for data integrity checks using CRC and
25+
structured exception management.
26+
27+
Setpoint Modes Enum:
28+
--------------------
29+
- POSITION_GLOBAL_LATLON: Global coordinates (latitude, longitude, altitude)
30+
- POSITION_LOCAL_NED: Local coordinates (north, east, down)
31+
- VELOCITY_NED: Local frame velocity (north, east, down)
32+
- VELOCITY_BODY: Body frame velocity (forward, right, down)
33+
- POSITION_VELOCITY_NED: Combined local position and velocity
34+
- POSITION_VELOCITY_ACCELERATION_NED: Combined position, velocity, and acceleration
35+
- ACCELERATION_NED: Local frame acceleration
36+
- ATTITUDE_CONTROL: Direct control of roll, pitch, yaw, and thrust
37+
- YAW_CONTROL: Separate flag for explicit yaw control
38+
39+
Usage:
40+
------
41+
Instantiate a `ControlPacket` with desired setpoints and mode flags, then use
42+
`pack()` to serialize for transmission and `unpack()` to deserialize received packets.
43+
Example usage is provided in the sender and receiver scripts accompanying this module.
44+
45+
Author:
46+
-------
47+
Alireza Ghaderi
48+
GitHub: alireza787b
49+
Date: April 2024
50+
51+
Example:
52+
--------
53+
```python
54+
packet = ControlPacket(
55+
mode=SetpointMode.POSITION_VELOCITY_NED | SetpointMode.YAW_CONTROL,
56+
enable_flag=True,
57+
yaw_control_flag=True,
58+
position=(10.0, 20.0, -5.0),
59+
velocity=(0.5, 0.5, 0.0),
60+
acceleration=(0.0, 0.0, 0.0),
61+
attitude=(0.0, 0.0, 30.0, 0.6), # Yaw to 30 degrees, 60% thrust
62+
attitude_rate=(0, 0, 0, 0)
63+
)
64+
packed_data = packet.pack()
65+
unpacked_packet = ControlPacket.unpack(packed_data)
66+
unpacked_packet.debug_print()
67+
"""
68+
import struct
69+
import zlib
70+
import time
71+
from enum import Enum
72+
73+
class SetpointMode(Enum):
74+
POSITION_GLOBAL_LATLON = 0x40
75+
POSITION_LOCAL_NED = 0x20
76+
VELOCITY_NED = 0x80
77+
VELOCITY_BODY = 0x100
78+
POSITION_VELOCITY_NED = 0x01
79+
POSITION_VELOCITY_ACCELERATION_NED = 0x02
80+
ACCELERATION_NED = 0x04
81+
ATTITUDE_CONTROL = 0x08 # Direct attitude control including thrust
82+
YAW_CONTROL = 0x200 # Separate flag for yaw control
83+
84+
class ControlPacket:
85+
HEADER = 0xDEADBEEFDEADBEEF
86+
HEADER_FORMAT = ">Q" # 8 bytes for header
87+
DATA_FORMAT = ">QII3d3d3d4d4dI" # Updated format to include all required fields
88+
CRC_FORMAT = ">I" # 4 bytes for CRC
89+
90+
def __init__(self, mode, enable_flag, yaw_control_flag, position, velocity, acceleration, attitude, attitude_rate, timestamp=None):
91+
self.timestamp = timestamp if timestamp is not None else int(time.time() * 1e9)
92+
self.setpoint_flags = mode.value
93+
self.enable_flag = int(enable_flag) # Ensure enable_flag is integer
94+
self.yaw_control_flag = int(yaw_control_flag) # Ensure yaw_control_flag is integer
95+
self.position = position
96+
self.velocity = velocity
97+
self.acceleration = acceleration
98+
self.attitude = attitude
99+
self.attitude_rate = attitude_rate
100+
101+
def pack(self):
102+
# Ensure all values are properly converted and match the expected types
103+
enable_flag_int = 1 if self.enable_flag else 0 # Correct conversion of boolean to integer
104+
yaw_control_flag_int = 1 if self.yaw_control_flag else 0 # Correct conversion of boolean to integer
105+
106+
# Ensure the timestamp is an integer
107+
timestamp_int = int(self.timestamp)
108+
109+
# Pack all data components
110+
try:
111+
payload = struct.pack(
112+
self.DATA_FORMAT,
113+
timestamp_int,
114+
self.setpoint_flags,
115+
enable_flag_int,
116+
yaw_control_flag_int,
117+
*self.position,
118+
*self.velocity,
119+
*self.acceleration,
120+
*self.attitude,
121+
*self.attitude_rate
122+
)
123+
except struct.error as e:
124+
print(f"Struct error: {e}")
125+
print(f"Data being packed: {timestamp_int}, {self.setpoint_flags}, {enable_flag_int}, {yaw_control_flag_int}, {self.position}, {self.velocity}, {self.acceleration}, {self.attitude}, {self.attitude_rate}")
126+
raise
127+
128+
crc = zlib.crc32(payload) & 0xffffffff
129+
return struct.pack(self.HEADER_FORMAT, self.HEADER) + payload + struct.pack(self.CRC_FORMAT, crc)
130+
131+
132+
@staticmethod
133+
def unpack(packet):
134+
header = struct.unpack(ControlPacket.HEADER_FORMAT, packet[:8])[0]
135+
if header != ControlPacket.HEADER:
136+
raise ValueError("Invalid packet header")
137+
payload, crc = packet[8:-4], packet[-4:]
138+
data = struct.unpack(ControlPacket.DATA_FORMAT, payload)
139+
if crc != struct.pack(ControlPacket.CRC_FORMAT, zlib.crc32(payload) & 0xffffffff):
140+
raise ValueError("CRC check failed")
141+
142+
timestamp, setpoint_flags, enable_flag_int, yaw_control_flag_int = data[:4]
143+
position = data[4:7]
144+
velocity = data[7:10]
145+
acceleration = data[10:13]
146+
attitude = data[13:17]
147+
attitude_rate = data[17:21]
148+
149+
# Convert integers back to booleans
150+
enable_flag = bool(enable_flag_int)
151+
yaw_control_flag = bool(yaw_control_flag_int)
152+
153+
return ControlPacket(SetpointMode(setpoint_flags), enable_flag, yaw_control_flag,
154+
position, velocity, acceleration, attitude, attitude_rate, timestamp)
155+
156+
def debug_print(self):
157+
print("Control Packet:")
158+
print(f"Timestamp: {self.timestamp}")
159+
mode_name = self.get_mode_name()
160+
yaw_control = "enabled" if self.yaw_control_flag else "initial yaw maintained"
161+
enable_mode = "enabled" if self.enable_flag else "disabled"
162+
print(f"Setpoint Flags: {bin(self.setpoint_flags)} ({mode_name})")
163+
print(f"Enable Flag: {enable_mode}")
164+
print(f"Yaw Control: {yaw_control}")
165+
print("Position: ", self.position)
166+
print("Velocity: ", self.velocity)
167+
print("Acceleration: ", self.acceleration)
168+
print("Attitude: ", self.attitude)
169+
print("Attitude Rate: ", self.attitude_rate)
170+
171+
def get_mode_name(self):
172+
for mode in SetpointMode:
173+
if mode.value & self.setpoint_flags:
174+
return mode.name
175+
return "Unknown Mode"

0 commit comments

Comments
 (0)