forked from simondlevy/PyQuadSim
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfmu.py
More file actions
141 lines (105 loc) · 5.25 KB
/
fmu.py
File metadata and controls
141 lines (105 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
'''
fmu.py - Flight Management Unit class
Copyright (C) 2014 Bipeen Acharya, Fred Gisa, and Simon D. Levy
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
'''
# PID parameters ==================================================================
IMU_PITCH_ROLL_Kp = .1
IMU_PITCH_ROLL_Kd = .025
IMU_PITCH_ROLL_Ki = 0
IMU_YAW_Kp = 0.2
IMU_YAW_Kd = 0.1
IMU_YAW_Ki = 0.01
ALTITUDE_Kp = 0.25
ALTITUDE_Kd = 0.1
# Flight Forces
ROLL_DEMAND_FACTOR = 0.1
PITCH_DEMAND_FACTOR = 0.1
YAW_DEMAND_FACTOR = 0.5
# Essential imports ================================================================
from pidcontrol import Stability_PID_Controller, Yaw_PID_Controller, Hover_PID_Controller
import math
# FMU class ========================================================================
class FMU(object):
def __init__(self, logfile=None):
'''
Creates a new Quadrotor object with optional logfile.
'''
# Store logfile handle
self.logfile = logfile
# Create PD controllers for pitch, roll based on angles from Inertial Measurement Unit (IMU)
self.pitch_Stability_PID = Stability_PID_Controller(IMU_PITCH_ROLL_Kp, IMU_PITCH_ROLL_Kd, IMU_PITCH_ROLL_Ki)
self.roll_Stability_PID = Stability_PID_Controller(IMU_PITCH_ROLL_Kp, IMU_PITCH_ROLL_Kd, IMU_PITCH_ROLL_Ki)
# Special handling for yaw from IMU
self.yaw_IMU_PID = Yaw_PID_Controller(IMU_YAW_Kp, IMU_YAW_Kd, IMU_YAW_Ki)
# Create PD controller for altitude-hold
self.altitude_PID = Hover_PID_Controller(ALTITUDE_Kp, ALTITUDE_Kd)
# For altitude hold
self.switch_prev = 0
self.target_altitude = 0
def getMotors(self, imuAngles, controllerInput, timestep, extraData):
'''
Gets motor thrusts based on current telemetry:
imuAngles IMU pitch, roll, yaw angles in radians (positive = nose up, right down, nose right)
controllerInput (pitchDemand, rollDemand, yawDemand, throttleDemand, switch)
timestep timestep in seconds
extraData extra sensor data for mission
'''
# Convert flight-stick controller input to demands
pitchDemand = controllerInput[0]
rollDemand = controllerInput[1]
yawDemand = -controllerInput[2]
throttleDemand = controllerInput[3]
# Grab value of three-position switch
switch = controllerInput[4]
# Grab altitude from sonar
altitude = extraData[0]
# Lock onto altitude when switch goes on
if switch == 1:
if self.switch_prev == 0:
self.target_altitude = altitude
else:
self.target_altitude = 0
self.switch_prev = switch
# Get PID altitude correction if indicated
altitudeCorrection = self.altitude_PID.getCorrection(altitude, self.target_altitude, timestep) \
if self.target_altitude > 0 \
else 0
# PID control for pitch, roll based on angles from Inertial Measurement Unit (IMU)
imuPitchCorrection = self.pitch_Stability_PID.getCorrection(imuAngles[0], timestep)
imuRollCorrection = self.roll_Stability_PID.getCorrection(-imuAngles[1], timestep)
# Pitch, roll, yaw correction
pitchCorrection = imuPitchCorrection
rollCorrection = imuRollCorrection
yawCorrection = self.yaw_IMU_PID.getCorrection(imuAngles[2], yawDemand, timestep)
# Climb demand defaults to throttle demand
climbDemand = throttleDemand
# Adjust climb demand for altitude correction
if altitudeCorrection != 0:
# In deadband, maintain altitude
if throttleDemand > 0.4 and throttleDemand < 0.6:
climbDemand = 0.5 + altitudeCorrection
# Baseline thrust is a nonlinear function of climb demand
thrust = 4*math.sqrt(math.sqrt(climbDemand)) + 2
# Overall thrust is baseline plus throttle demand plus correction from PD controller
# received from the joystick and the # quadrotor model corrections. A positive
# pitch value means, thrust increases for two back propellers and a negative
# is opposite; similarly for roll and yaw. A positive throttle value means thrust
# increases for all 4 propellers.
psign = [+1, -1, -1, +1]
rsign = [-1, -1, +1, +1]
ysign = [+1, -1, +1, -1]
thrusts = [0]*4
for i in range(4):
thrusts[i] = (thrust + rsign[i]*rollDemand*ROLL_DEMAND_FACTOR + \
psign[i]*PITCH_DEMAND_FACTOR*pitchDemand + \
ysign[i]*yawDemand*YAW_DEMAND_FACTOR) * \
(1 + rsign[i]*rollCorrection + psign[i]*pitchCorrection + ysign[i]*yawCorrection)
return thrusts