2016-07-31 07:22:06 -03:00
|
|
|
import math
|
2015-04-21 08:33:27 -03:00
|
|
|
import random
|
2016-07-31 07:22:06 -03:00
|
|
|
import time
|
|
|
|
import util
|
|
|
|
|
2021-04-02 22:00:23 -03:00
|
|
|
from pymavlink.rotmat import Vector3, Matrix3
|
2011-12-02 00:13:50 -04:00
|
|
|
|
2016-07-31 07:22:06 -03:00
|
|
|
|
2011-12-02 00:13:50 -04:00
|
|
|
class Aircraft(object):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""A basic aircraft class."""
|
2011-12-02 00:13:50 -04:00
|
|
|
def __init__(self):
|
|
|
|
self.home_latitude = 0
|
|
|
|
self.home_longitude = 0
|
|
|
|
self.home_altitude = 0
|
|
|
|
self.ground_level = 0
|
|
|
|
self.frame_height = 0.0
|
|
|
|
|
2016-07-31 07:22:06 -03:00
|
|
|
self.latitude = self.home_latitude
|
2011-12-02 00:13:50 -04:00
|
|
|
self.longitude = self.home_longitude
|
2016-07-31 07:22:06 -03:00
|
|
|
self.altitude = self.home_altitude
|
2011-12-02 00:13:50 -04:00
|
|
|
|
2012-03-22 08:50:47 -03:00
|
|
|
self.dcm = Matrix3()
|
2011-12-05 02:44:04 -04:00
|
|
|
|
2012-03-22 08:50:47 -03:00
|
|
|
# rotation rate in body frame
|
2016-07-31 07:22:06 -03:00
|
|
|
self.gyro = Vector3(0, 0, 0) # rad/s
|
2011-12-05 02:44:04 -04:00
|
|
|
|
2016-07-31 07:22:06 -03:00
|
|
|
self.velocity = Vector3(0, 0, 0) # m/s, North, East, Down
|
|
|
|
self.position = Vector3(0, 0, 0) # m North, East, Down
|
2011-12-02 00:13:50 -04:00
|
|
|
self.mass = 0.0
|
2016-07-31 07:22:06 -03:00
|
|
|
self.update_frequency = 50 # in Hz
|
|
|
|
self.gravity = 9.80665 # m/s/s
|
2012-03-23 02:24:52 -03:00
|
|
|
self.accelerometer = Vector3(0, 0, -self.gravity)
|
2011-12-02 00:13:50 -04:00
|
|
|
|
2011-12-12 19:11:10 -04:00
|
|
|
self.wind = util.Wind('0,0,0')
|
2015-03-21 11:29:28 -03:00
|
|
|
self.time_base = time.time()
|
|
|
|
self.time_now = self.time_base + 100*1.0e-6
|
2011-12-12 19:11:10 -04:00
|
|
|
|
2015-04-21 08:33:27 -03:00
|
|
|
self.gyro_noise = math.radians(0.1)
|
|
|
|
self.accel_noise = 0.3
|
|
|
|
|
2012-03-23 02:24:52 -03:00
|
|
|
def on_ground(self, position=None):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Return true if we are on the ground."""
|
2012-03-23 02:24:52 -03:00
|
|
|
if position is None:
|
|
|
|
position = self.position
|
|
|
|
return (-position.z) + self.home_altitude <= self.ground_level + self.frame_height
|
|
|
|
|
2015-04-01 13:11:25 -03:00
|
|
|
def update_position(self):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Update lat/lon/alt from position."""
|
2011-12-02 00:13:50 -04:00
|
|
|
|
2012-06-04 22:18:45 -03:00
|
|
|
bearing = math.degrees(math.atan2(self.position.y, self.position.x))
|
|
|
|
distance = math.sqrt(self.position.x**2 + self.position.y**2)
|
|
|
|
|
|
|
|
(self.latitude, self.longitude) = util.gps_newpos(self.home_latitude, self.home_longitude,
|
|
|
|
bearing, distance)
|
2011-12-02 00:13:50 -04:00
|
|
|
|
2016-07-31 07:22:06 -03:00
|
|
|
self.altitude = self.home_altitude - self.position.z
|
2012-03-22 08:50:47 -03:00
|
|
|
|
2012-03-23 02:24:52 -03:00
|
|
|
velocity_body = self.dcm.transposed() * self.velocity
|
|
|
|
|
2012-06-20 06:52:41 -03:00
|
|
|
self.accelerometer = self.accel_body.copy()
|
2013-05-16 21:37:11 -03:00
|
|
|
|
|
|
|
def set_yaw_degrees(self, yaw_degrees):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Rotate to the given yaw."""
|
2013-05-16 21:37:11 -03:00
|
|
|
(roll, pitch, yaw) = self.dcm.to_euler()
|
|
|
|
yaw = math.radians(yaw_degrees)
|
|
|
|
self.dcm.from_euler(roll, pitch, yaw)
|
2016-07-31 07:22:06 -03:00
|
|
|
|
2015-03-21 11:29:28 -03:00
|
|
|
def time_advance(self, deltat):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Advance time by deltat in seconds."""
|
2015-03-21 11:29:28 -03:00
|
|
|
self.time_now += deltat
|
2015-04-12 21:06:18 -03:00
|
|
|
|
|
|
|
def setup_frame_time(self, rate, speedup):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Setup frame_time calculation."""
|
2015-04-12 21:06:18 -03:00
|
|
|
self.rate = rate
|
|
|
|
self.speedup = speedup
|
|
|
|
self.frame_time = 1.0/rate
|
|
|
|
self.scaled_frame_time = self.frame_time/speedup
|
|
|
|
self.last_wall_time = time.time()
|
|
|
|
self.achieved_rate = rate
|
|
|
|
|
2015-04-19 19:20:08 -03:00
|
|
|
def adjust_frame_time(self, rate):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Adjust frame_time calculation."""
|
2015-04-19 19:20:08 -03:00
|
|
|
self.rate = rate
|
|
|
|
self.frame_time = 1.0/rate
|
|
|
|
self.scaled_frame_time = self.frame_time/self.speedup
|
|
|
|
|
2015-04-12 21:06:18 -03:00
|
|
|
def sync_frame_time(self):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Try to synchronise simulation time with wall clock time, taking
|
|
|
|
into account desired speedup."""
|
2015-04-12 21:06:18 -03:00
|
|
|
now = time.time()
|
|
|
|
if now < self.last_wall_time + self.scaled_frame_time:
|
|
|
|
time.sleep(self.last_wall_time+self.scaled_frame_time - now)
|
|
|
|
now = time.time()
|
|
|
|
|
|
|
|
if now > self.last_wall_time and now - self.last_wall_time < 0.1:
|
|
|
|
rate = 1.0/(now - self.last_wall_time)
|
|
|
|
self.achieved_rate = (0.98*self.achieved_rate) + (0.02*rate)
|
|
|
|
if self.achieved_rate < self.rate*self.speedup:
|
|
|
|
self.scaled_frame_time *= 0.999
|
|
|
|
else:
|
|
|
|
self.scaled_frame_time *= 1.001
|
|
|
|
|
|
|
|
self.last_wall_time = now
|
2015-04-21 08:33:27 -03:00
|
|
|
|
|
|
|
def add_noise(self, throttle):
|
2016-07-31 07:22:06 -03:00
|
|
|
"""Add noise based on throttle level (from 0..1)."""
|
2015-04-21 08:33:27 -03:00
|
|
|
self.gyro += Vector3(random.gauss(0, 1),
|
|
|
|
random.gauss(0, 1),
|
|
|
|
random.gauss(0, 1)) * throttle * self.gyro_noise
|
|
|
|
self.accel_body += Vector3(random.gauss(0, 1),
|
|
|
|
random.gauss(0, 1),
|
|
|
|
random.gauss(0, 1)) * throttle * self.accel_noise
|