swarms / dronemodel.py
YvesP's picture
initial load
a162e39
from dataclasses import dataclass
from scipy.integrate import odeint
import numpy as np
import param_
@dataclass
class DroneModel:
"""
Creates a drone_model of a drone
"""
def __init__(self, is_blue):
self.drone_model = param_.DRONE_MODELS[param_.DRONE_MODEL[is_blue]]
self.angle_to_neutralisation = self.drone_model['angle_to_neutralisation']
self.distance_to_neutralisation = self.drone_model['distance_to_neutralisation']
self.duration_to_neutralisation = self.drone_model['duration_to_neutralisation']
self.Cxy = self.drone_model['Cxy']
self.Cz = self.drone_model['Cz']
self.mass = self.drone_model['mass']
self.Fxy_ratio = self.drone_model['Fxy_ratio']
self.Fz_min_ratio = self.drone_model['Fz_min_ratio']
self.Fz_max_ratio = self.drone_model['Fz_max_ratio']
self.weight_eq = self.mass * param_.g * (1 - self.Fz_min_ratio)
self.Fz_plus = (self.Fz_max_ratio - 1) * self.mass * param_.g
self.Fz_minus = (1 - self.Fz_min_ratio) * self.mass * param_.g
self.Fxy = self.mass * param_.g * self.Fxy_ratio
self.max_speed = np.sqrt(self.Fxy / self.Cxy)
self.max_up_speed = np.sqrt(self.Fz_plus / self.Cz)
self.max_down_speed = np.sqrt(self.Fz_minus / self.Cz)
self.max_rot_speed = 2 * np.pi
def get_trajectory(self, pos_xyz, speed_xyz, action: np.ndarray(3,), time_: np.ndarray(1,)) -> np.ndarray(3,):
'''
returns next position given the current position, speed and applied forces
:param pos_xyz:
:param speed_xyz:
:param action:
:param time_:
:return:
'''
rho = action[0] # in 0, 1
theta = 2*np.pi * action[1] # in 0, 2pi
psy = np.pi * (action[2] - 0.5) # in -pi/2, pi/2
fx = rho * np.cos(theta) * np.cos(psy) * self.Fxy
fy = rho * np.sin(theta) * np.cos(psy) * self.Fxy
fz = rho * np.sin(psy) * (self.Fz_plus if 0 < psy else self.Fz_minus)
pos_speed = np.hstack((pos_xyz, speed_xyz))
result_ = odeint(
lambda u, v: self.drone_dynamics(u, v, fx, fy, fz, self.Cxy, self.Cz, self.mass),
pos_speed,
time_,
Dfun=lambda u, v: self.fulljac(u, v, self.Cxy, self.Cz, self.mass)
)
x, y, z, dx, dy, dz = result_.T
return np.array([x, y, z], dtype='float32'), np.array([dx, dy, dz], dtype='float32')
def drone_dynamics(self, pos_speed, time_, f_x, f_y, f_z, Cxy, Cz, m):
x, y, z, dx, dy, dz = pos_speed
return [dx,
dy,
dz,
1/m * (f_x - Cxy * dx * np.sqrt(dx**2 + dy**2 + dz**2)),
1/m * (f_y - Cxy * dy * np.sqrt(dx**2 + dy**2 + dz**2)),
1/m * (f_z - Cz * dz * np.sqrt(dx**2 + dy**2 + dz**2))]
def fulljac(self, pos_speed, time_, Cxy, Cz, m) -> np.ndarray((6, 6), ):
'''
returns the Jacobian of the differential equation of the trajectory
:param pos_speed:
:param time_:
:param Cxy:
:param Cz:
:param m:
:return:
'''
x, y, z, dx, dy, dz = pos_speed
J = np.zeros((6, 6))
J[0, 3] = 1
J[1, 4] = 1
J[2, 5] = 1
J[3, 3] = -Cxy/m * ((np.sqrt(dx**2 + dy**2 + dz**2)) + dx**2 / np.sqrt(dx**2 + dy**2 + dz**2))
J[3, 4] = -Cxy/m * (dx * dy / np.sqrt(dx**2 + dy**2 + dz**2))
J[3, 5] = -Cxy/m * (dx * dz / np.sqrt(dx**2 + dy**2 + dz**2))
J[4, 4] = -Cxy/m * ((np.sqrt(dx**2 + dy**2 + dz**2)) + dy**2 / np.sqrt(dx**2 + dy**2 + dz**2))
J[4, 3] = -Cxy/m * (dy * dx / np.sqrt(dx**2 + dy**2 + dz**2))
J[4, 5] = -Cxy/m * (dy * dz / np.sqrt(dx**2 + dy**2 + dz**2))
J[5, 5] = -Cz/m * ((np.sqrt(dx**2 + dy**2 + dz**2)) + dz**2 / np.sqrt(dx**2 + dy**2 + dz**2))
J[5, 3] = -Cz/m * (dz * dx / np.sqrt(dx**2 + dy**2 + dz**2))
J[5, 4] = -Cz/m * (dz * dy / np.sqrt(dx**2 + dy**2 + dz**2))
return J