def main(): # import python's standard time module import time # import Controller and other blocks from modules from pyctrl import Controller from pyctrl.block import Printer from pyctrl.block.clock import TimerClock # initialize controller hello = Controller() # add the signal myclock hello.add_signal('myclock') # add a TimerClock as a source hello.add_source('myclock', TimerClock(period=1), ['myclock'], enable=True) # add a Printer as a sink hello.add_sink('message', Printer(message='Hello World!'), ['myclock'], enable=True) try: # run the controller with hello: # do nothing for 5 seconds time.sleep(5) except KeyboardInterrupt: pass finally: print('Done')
def main(): # import python's standard time module import time # import Controller and other blocks from modules from pyctrl import Controller from pyctrl.block import Printer, Constant # initialize controller hello = Controller() # add a Printer as a timer hello.add_timer('message', Printer(message='Hello World @ {:3.1f} s '), ['clock'], None, period=1, repeat=True) # Add a timer to stop the controller hello.add_timer('stop', Constant(value=0), None, ['is_running'], period=5, repeat=False) # add a Printer as a sink hello.add_sink('message', Printer(message='Current time {:5.3f} s', endln='\r'), ['clock']) # print controller info print(hello.info('all')) try: # run the controller print('> Run the controller.') with hello: # wait for the controller to finish on its own hello.join() print('> Done with the controller.') except KeyboardInterrupt: pass
def _test_mip_balance(): import numpy as np from pyctrl import Controller from pyctrl.block.container import Container, Input, Output from pyctrl.block.system import System, Subtract, Differentiator, Sum, Gain from pyctrl.block.nl import ControlledCombination, Product from pyctrl.block import Fade, Printer from pyctrl.system.ss import DTSS from pyctrl.block.logic import CompareAbsWithHysterisis, SetFilter, State GRN_LED = 61 PAUSE_BTN = 62 # create mip mip = Controller() # add signals mip.add_signals('theta', 'theta_dot', 'encoder1', 'encoder2', 'pwm1', 'pwm2') # phi is the average of the encoders mip.add_signal('phi') mip.add_filter('phi', Sum(gain=0.5), ['encoder1', 'encoder2'], ['phi']) # phi dot mip.add_signal('phi_dot') mip.add_filter('phi_dot', Differentiator(), ['clock', 'phi'], ['phi_dot']) # phi dot and steer reference mip.add_signals('phi_dot_reference', 'phi_dot_reference_fade') mip.add_signals('steer_reference', 'steer_reference_fade') # add fade in filter mip.add_filter('fade', Fade(target=[0, 0.5], period=5), ['clock', 'phi_dot_reference', 'steer_reference'], ['phi_dot_reference_fade', 'steer_reference_fade']) # state-space matrices A = np.array([[0.913134, 0.0363383], [-0.0692862, 0.994003]]) B = np.array([[0.00284353, -0.000539063], [0.00162443, -0.00128745]]) C = np.array([[-383.009, 303.07]]) D = np.array([[-1.22015, 0]]) B = 2 * np.pi * (100 / 7.4) * np.hstack((-B, B[:, 1:])) D = 2 * np.pi * (100 / 7.4) * np.hstack((-D, D[:, 1:])) ssctrl = DTSS(A, B, C, D) # state-space controller mip.add_signals('pwm') mip.add_filter('controller', System(model=ssctrl), ['theta_dot', 'phi_dot', 'phi_dot_reference_fade'], ['pwm']) # enable pwm only if about small_angle mip.add_signals('small_angle', 'small_angle_pwm') mip.add_filter('small_angle_pwm', Product(), ['small_angle', 'pwm'], ['small_angle_pwm']) # steering biasing mip.add_filter( 'steer', ControlledCombination(), ['steer_reference_fade', 'small_angle_pwm', 'small_angle_pwm'], ['pwm1', 'pwm2']) # set references mip.set_signal('phi_dot_reference', 0) mip.set_signal('steer_reference', 0.5) # add supervisor actions on a timer # actions are inside a container so that they are executed all at once mip.add_timer('supervisor', Container(), ['theta'], ['small_angle', 'is_running'], period=0.5, repeat=True) mip.add_signals('timer/supervisor/theta', 'timer/supervisor/small_angle', 'timer/supervisor/is_running') mip.add_source('timer/supervisor/theta', Input(), ['theta']) mip.add_sink('timer/supervisor/small_angle', Output(), ['small_angle']) mip.add_sink('timer/supervisor/is_running', Output(), ['is_running']) # add small angle sensor mip.add_filter( 'timer/supervisor/is_angle_small', CompareAbsWithHysterisis(threshold=0.11, hysterisis=0.09, offset=-0.07, state=(State.LOW, )), ['theta'], ['small_angle']) # reset controller and fade mip.add_sink( 'timer/supervisor/reset_controller', SetFilter(label=['/controller', '/fade'], on_rise={'reset': True}), ['small_angle']) # add pause button on a timer mip.add_source('timer/supervisor/pause_button', ('pyctrl.block', 'Constant'), ['is_running'], kwargs={'value': 0}, enable=True) from pyctrl.flask import JSONEncoder, JSONDecoder json1 = JSONEncoder(sort_keys=True, indent=4).encode(mip) obj = JSONDecoder().decode(json1) json2 = JSONEncoder(sort_keys=True, indent=4).encode(obj) assert json1 == json2 print('json = \n{}'.format(json1))
pilot.add_signal('northspeed') pilot.add_signal('eastspeed') pilot.add_signal('aileron') pilot.add_signal('elevator') pilot.add_signal('rudder') pilot.add_signal('throttle') pilot.add_source('fg_source', FgSource(), ['speed', 'heading', 'altitude', 'climb', 'pitch', 'bank', 'engine', 'latitude', 'longitude', 'northspeed', 'eastspeed'], enable = True) pilot.add_sink('debug_print', Printer(message = 'speed: {}, heading: {}'), ['speed', 'heading'], enable = True) pilot.add_sink('fg_sender', FgSink(), ['aileron', 'elevator', 'rudder', 'throttle'], enable = True) try: # run the controller with pilot: # do nothing for 5 seconds while True: time.sleep(1) except KeyboardInterrupt:
def test1(): if not test_ode: return from pyctrl import Controller controller = Controller() Ts = 0.01 clock = TimerClock(period=Ts) controller.add_source('clock', clock, ['clock']) a = -1 b = 1 def f(t, x, u, a, b): return a * x + b * u t0 = 0 uk = 1 x0 = np.array([0]) sys = ODE((1, 1, 1), f, x0=x0, t0=t0, pars=(a, b)) controller.add_signals('input', 'output') controller.add_filter('condition', Map(function=lambda x: x < 1), ['clock'], ['is_running']) controller.add_filter('ode', TimeVaryingSystem(model=sys), ['clock', 'input'], ['output']) controller.add_sink('logger', Logger(), ['clock', 'output']) print(controller.info('all')) controller.set_filter('ode', reset=True) controller.set_source('clock', reset=True) controller.set_sink('logger', reset=True) controller.set_signal('input', uk) controller.run() xk = sys.state log = controller.get_sink('logger', 'log') t0 = log['clock'][0, 0] tk = log['clock'][-1, 0] yk = log['output'][-1, 0] print('t0 = {}'.format(t0)) print('tk = {}'.format(tk)) print('yk = {}'.format(yk)) yyk = uk * (1 - math.exp(a * (tk - t0))) + x0[0] * math.exp(a * (tk - t0)) print(log) print(t0, x0, tk, xk, yk, yyk) assert np.abs(yk - yyk) < 1e-2 uk = 0 x0 = sys.state controller.add_filter('condition', Map(function=lambda x: x < 2), ['clock'], ['is_running']) print(controller.info('all')) print('clock = {}'.format(controller.get_signal('clock'))) #controller.set_source('clock', reset = True) controller.set_sink('logger', reset=True) controller.set_signal('input', uk) controller.run() xk = sys.state print('clock = {}'.format(controller.get_signal('clock'))) log = controller.get_sink('logger', 'log') print('log = {}'.format(log)) t0 = log['clock'][0, 0] tk = log['clock'][-1, 0] yk = log['output'][-1, 0] print('t0 = {}, x0 = {}, tk = {}, xk = {}, yk = {}'.format( t0, x0, tk, xk, yk)) yyk = uk * (1 - math.exp(a * (tk - t0))) + x0 * math.exp(a * (tk - t0)) print(log) print(t0, x0, tk, xk, yk, yyk) assert np.abs(yk - np.array([yyk])) < 1e-2 uk = -1 x0 = sys.state controller.add_filter('condition', Map(function=lambda x: x < 3), ['clock'], ['is_running']) #controller.set_source('clock', reset = True) controller.set_sink('logger', reset=True) controller.set_signal('input', uk) controller.run() xk = sys.state log = controller.get_sink('logger', 'log') t0 = log['clock'][0, 0] tk = log['clock'][-1, 0] yk = log['output'][-1, 0] yyk = uk * (1 - math.exp(a * (tk - t0))) + x0 * math.exp(a * (tk - t0)) print(t0, x0, tk, xk, yk, yyk) assert np.abs(yk - np.array([yyk])) < 1e-2 clock.set_enabled(False)
def test2(): if not test_ode: return m1 = 30 / 1000 l1 = 7.6 / 100 r1 = (5 - (10 - 7.6) / 2) / 100 w1 = 10 / 100 d1 = 2.4 / 100 J1 = m1 * (w1**2 + d1**2) / 12 m2 = 44 / 1000 w2 = 25.4 / 100 d2 = 2.4 / 100 J2 = m2 * (w2**2 + d2**2) / 12 r2 = (25.4 / 2 - 1.25) / 100 Jm = 0.004106 km = 0.006039 bm = 0.091503 g = 9.8 bPhi = 0 bTheta = 0 def MK(x, u): theta, phi, thetaDot, phiDot = x return ( np.array([[J2 + m2 * r2**2, m2 * r2 * l1 * math.cos(theta - phi)], [ m2 * r2 * l1 * math.cos(theta - phi), J1 + Jm + m1 * r1**2 + m2 * l1**2 ]]), np.array([ bTheta * thetaDot + m2 * r2 * (g * math.sin(theta) + l1 * math.sin(theta - phi) * phiDot**2), g * (m1 * r1 + m2 * l1) * math.sin(phi) - m2 * r2 * l1 * math.sin(theta - phi) * thetaDot**2 + (bm + bPhi) * phiDot - km * u[0] ])) def ff(t, x, u): M, K = MK(x, u) return np.hstack((x[2:4], -la.solve(M, K))) theta0, phi0 = 0 + math.pi / 6, 0 t0, x0, u0 = 0, np.array([theta0, phi0, 0, 0]), [0] M, K = MK(x0, u0) print(M) print(K) print(ff(t0, x0, u0)) sys = ODE(shape=(1, 4, 4), t0=t0, x0=x0, f=ff) tk = 5 uk = [0] yk = sys.update(tk, uk) print('1. [{:3.2f}, {:3.2f}] = {}'.format(t0, tk, yk)) from pyctrl import Controller controller = Controller() Ts = 0.01 controller.add_source('clock', Clock(), ['clock']) condition = Map(function=lambda t: t < T) controller.add_filter('condition', condition, ['clock'], ['is_running']) controller.add_signals('tau', 'x') controller.add_filter( 'ode', TimeVaryingSystem(model=ODE(shape=(1, 4, 4), t0=t0, x0=x0, f=ff)), ['clock', 'tau'], ['x']) controller.add_sink('logger', Logger(), ['clock', 'x']) controller.set_source('clock', reset=True) T = 5 + Ts controller.run() log = controller.get_sink('logger', 'log') t0 = log['clock'][0, 0] tk = log['clock'][0, -1] yk = log['x'][0, -1] # yk = log[-1,1:] print('2. [{:3.2f}, {:3.2f}] = {}'.format(t0, tk, yk)) import control fc = 7 wc = 2 * math.pi * fc lpf = control.tf(wc, [1, wc]) ctr = -2 * 100 def gg(t, x, u): return [x[0]] Ts = 0.01 Ac, Bc, Cc, Dc = map(np.array, control.ssdata(control.ss(lpf * ctr))) nc = Ac.shape[0] def F(t, x, ref): x, xc = x[0:4], x[4:4 + nc] y = ref - gg(t, x, [0]) u = max(-100, min(100, Cc.dot(xc) + Dc.dot(y))) #print(ff(t,x,u)) return np.hstack((ff(t, x, u), Ac.dot(xc) + Bc.dot(y))) eta = 0 kappa = 0 ref = np.array([eta * math.pi]) theta0 = -20 * math.pi / 180 xx0 = [kappa * math.pi - theta0, eta * math.pi, 0, 0] xc0 = np.zeros((nc, )) x0 = np.hstack((xx0, xc0)) t0 = 0 print('F = {}'.format(F(t0, x0, ref))) sys = ODE(shape=(1, 4, 4), t0=t0, x0=x0, f=F) tk = 1 uk = np.array([0]) yk = sys.update(tk, uk) print('1. [{:3.2f}, {:3.2f}] = {}'.format(t0, tk, yk)) controller.reset() Ts = 0.01 controller.add_source('clock', Clock(), ['clock']) condition = Map(function=lambda t: t < T) controller.add_filter('condition', condition, ['clock'], ['is_running']) controller.add_signals('ref', 'x') controller.add_filter( 'ode', TimeVaryingSystem(model=ODE(shape=(1, 4, 4), t0=t0, x0=x0, f=F)), ['clock', 'ref'], ['x']) controller.add_sink('logger', Logger(), ['clock', 'x']) #print(controller.info('all')) controller.set_source('clock', reset=True) controller.set_signal('ref', ref) T = 1 + Ts controller.run() log = controller.get_sink('logger', 'log') t0 = log['clock'][0, 0] tk = log['clock'][0, -1] yk = log['x'][0, -1] #yk = log[-1,1:] print('2. [{:3.2f}, {:3.2f}] = {}'.format(t0, tk, yk))