def __init__(self, drone, *, loop=None, log=False): super().__init__(drone) self.kf = [] for i in range(3): self.kf.append(ThetaOmegaKalmanFilter(0.1, 0.1, 0.04)) self.action = np.array([0., 0., 0., 0.]) self.thrust = 0 self.accz_momentum = Momentum(tau=0.05) self.target_theta = np.array([0., 0., 0.]) self.target_omegaz = 0. self.target_zacc = 9.8 self.pid_thetaxy = np.array([48., 40., 15.]) self.pid_tweakper = np.array([1., 1., 1.]) self.pids = { 'theta_x': PID(*self.pid_thetaxy, imax=60.), 'theta_y': PID(*self.pid_thetaxy, imax=60.), 'theta_z': PID(60., 20., 30., imax=60.), 'acc_z': PID(20., 1., 0., imax=800), }
class SimpleController(BaseController): def __init__(self, drone, *, loop=None, log=False): super().__init__(drone) self.kf = [] for i in range(3): self.kf.append(ThetaOmegaKalmanFilter(0.1, 0.1, 0.04)) self.action = np.array([0., 0., 0., 0.]) self.thrust = 0 self.accz_momentum = Momentum(tau=0.05) self.target_theta = np.array([0., 0., 0.]) self.target_omegaz = 0. self.target_zacc = 9.8 self.pid_thetaxy = np.array([48., 40., 15.]) self.pid_tweakper = np.array([1., 1., 1.]) self.pids = { 'theta_x': PID(*self.pid_thetaxy, imax=60.), 'theta_y': PID(*self.pid_thetaxy, imax=60.), 'theta_z': PID(60., 20., 30., imax=60.), 'acc_z': PID(20., 1., 0., imax=800), } @asyncio.coroutine def update(self): '''updates the motors according to the sensors' data ''' now = self.loop.time() dt = now - self.last_time self.target_theta[2] += dt * self.target_omegaz acc, theta, omega, z = yield from self.drone.get_motion_sensors() theta_smooth = [] omega_smooth = [] for i in range(3): theome = np.array([theta[i], omega[i]]) self.kf[i].update(now, theome) the, ome = self.kf[i].predict(now) theta_smooth.append(the) omega_smooth.append(ome) theta_smooth = np.array(theta_smooth) omega_smooth = np.array(omega_smooth) zacc_smooth = self.accz_momentum.append_value(now, acc[2]) theta_error = self.target_theta - theta_smooth zacc_error = self.target_zacc - zacc_smooth theta_x_action = self.pids['theta_x'].get_control( now, theta_error[0], 0 - omega_smooth[0] ) theta_y_action = self.pids['theta_y'].get_control( now, theta_error[1], 0 - omega_smooth[1] ) theta_z_action = self.pids['theta_z'].get_control( now, theta_error[2], 0 - omega_smooth[2] ) thrust_action = self.pids['acc_z'].get_control( now, 0 - zacc_smooth ) action = np.array([-theta_y_action + theta_z_action, theta_x_action + -theta_z_action, theta_y_action + theta_z_action, -theta_x_action + -theta_z_action,]) action += thrust_action yield from self.send_control(action) self.last_time = now # logging if self.logger: self.logger.info(json.dumps({ 'action': self.action.tolist(), 'accel': acc.tolist(), 'theta': theta.tolist(), 'omega': omega.tolist(), 'theta_smooth': theta_smooth.tolist(), 'omega_smooth': omega_smooth.tolist(), 'time': now, })) @asyncio.coroutine def send_control(self, action=None, thrust=None): if action is not None: self.action = action if thrust is not None: self.thrust = thrust final_action = self.action + self.thrust final_action = np.maximum.reduce([final_action, np.full((4,), -100)]) final_action = np.minimum.reduce( [final_action, np.full((4,), CONST['thrust_restriction'])] ) yield from self.drone.set_motors(final_action) @asyncio.coroutine def preform_action(self, action, args): if action == 'stop': yield from self.stop() elif action == 'arm': print('Get Arm') yield from self.arm() elif action == 'disarm': yield from self.disarm() elif action == 'control': self.preform_control(*args) elif action == 'tweak': self.tweak_pid(*args) def preform_control(self, thrust, theta_x, theta_y, omega_z): self.target_zacc = 9.8 + thrust self.target_theta[0] = theta_x self.target_theta[1] = theta_y self.target_omegaz = omega_z def tweak_pid(self, type_, per): if type_ == 'P': self.pid_tweakper[0] = per elif type_ == 'I': self.pid_tweakper[1] = per elif type_ == 'D': self.pid_tweakper[2] = per gain = self.pid_thetaxy * self.pid_tweakper for x in self.pids.values(): x.set_gain(*gain)