def test_container_input_output(self): from pyctrl.block.container import Container, Input, Output from pyctrl.block.system import Gain container = Container() container.add_signal('s1') container.add_source('input1', Input(), ['s1']) container.add_sink('ouput1', Output(), ['s1']) container.set_enabled(True) container.write(1) values = container.read() container.set_enabled(False) self.assertTrue(values == (1, )) container.add_sink('ouput2', Output(), ['s1']) container.set_enabled(True) container.write(1) values = container.read() container.set_enabled(False) self.assertTrue(values == (1, 1)) container.add_source('input2', Input(), ['s2']) container.add_sink('ouput2', Output(), ['s2']) container.set_enabled(True) container.write(1, 2) values = container.read() container.set_enabled(False) self.assertTrue(values == (1, 2)) container.add_filter('gain1', Gain(gain=3), ['s1'], ['s1']) container.set_enabled(True) container.write(1, 2) values = container.read() container.set_enabled(False) self.assertTrue(values == (3, 2)) container.add_sink('ouput1', Output(), ['s3']) container.add_filter('gain1', Gain(gain=3), ['s1'], ['s3']) container.set_enabled(True) container.write(1, 2) values = container.read() container.set_enabled(False) self.assertTrue(values == (2, 3))
def test_timer_sub_container(): import pyctrl import pyctrl.block as block from pyctrl.block.container import Container, Input, Output, ContainerException from pyctrl.block.system import Gain from pyctrl.block import Constant # create container first container = Container() container.add_signals('s1', 's2', 's3') # add subcontainer container.add_timer('container1', Container(), ['s1'], ['s2', 's3'], period=1, repeat=False) container.add_signals('timer/container1/s1', 'timer/container1/s2', 'timer/container1/s3') container.add_source('timer/container1/input1', Input(), ['s1']) container.add_filter('timer/container1/gain1', Gain(gain=3), ['s1'], ['s2']) container.add_filter('timer/container1/gain2', Gain(gain=5), ['s1'], ['s3']) container.add_sink('timer/container1/output1', Output(), ['s2']) container.add_sink('timer/container1/output2', Output(), ['s3']) print(container.info('all')) container.set_enabled(True) container.set_signal('s1', 1) container.run() container.set_enabled(False) assert container.get_signal('s2') == 0 assert container.get_signal('s3') == 0 container.set_enabled(True) container.set_signal('s1', 1) container.run() time.sleep(1.1) container.run() container.set_enabled(False) assert container.get_signal('s2') == 3 assert container.get_signal('s3') == 5
def test_sub_container(): import pyctrl import pyctrl.block as block from pyctrl.block.container import Container, Input, Output, ContainerException from pyctrl.block.system import Gain, DTTF container = Container() container.add_signals('s1', 's2', 's3') # add subcontainer container1 = Container() container.add_filter('container1', container1, ['s1'], ['s2', 's3']) container.add_signals('container1/s1', 'container1/s2') container.add_source('container1/input1', Input(), ['s1']) container.add_filter('container1/gain1', Gain(gain=3), ['s1'], ['s2']) container.add_sink('container1/output1', Output(), ['s2']) # add subsubcontainer container.add_sink('container1/output2', Output(), ['s3']) container2 = Container() container.add_filter('container1/container2', container2, ['s1'], ['s3']) container.add_signals('container1/container2/s1', 'container1/container2/s2') container.add_source('container1/container2/input1', Input(), ['s1']) container.add_filter('container1/container2/gain1', Gain(gain=5), ['s1'], ['s2']) container.add_sink('container1/container2/output1', Output(), ['s2']) print(container.info('all')) from pyctrl.flask import JSONEncoder, JSONDecoder json1 = JSONEncoder(sort_keys=True, indent=4).encode(container) obj = JSONDecoder().decode(json1) json2 = JSONEncoder(sort_keys=True, indent=4).encode(obj) assert json1 == json2 print('json = \n{}'.format(json1))
def test_sub_container_timer(self): from pyctrl.block.container import Container, Input, Output from pyctrl.block.system import Gain from pyctrl.block import Constant # create container first container = Container() container.add_signals('s1', 's2', 's3') # add subcontainer container.add_filter('container1', Container(), ['s1'], ['s2', 's3']) container.add_signals('container1/s1', 'container1/s2', 'container1/s3') container.add_source('container1/input1', Input(), ['s1']) container.add_filter('container1/gain1', Gain(gain=3), ['s1'], ['s2']) container.add_timer('container1/constant1', Constant(value=5), None, ['s3'], period=1, repeat=False) container.add_sink('container1/output1', Output(), ['s2']) container.add_sink('container1/output2', Output(), ['s3']) print(container.info('all')) container.set_enabled(True) container.set_signal('s1', 1) container.run() container.set_enabled(False) self.assertTrue(container.get_signal('s2') == 3) self.assertTrue(container.get_signal('s3') == 0) container.set_enabled(True) container.set_signal('s1', 1) container.run() time.sleep(1.1) container.run() container.set_enabled(False) self.assertTrue(container.get_signal('s2') == 3) self.assertTrue(container.get_signal('s3') == 5)
def main(): # import blocks and controller from pyctrl.rc.mip 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 from rcpy.gpio import GRN_LED, PAUSE_BTN from rcpy.led import red # export json? export_json = True # create mip mip = Controller() # 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') 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 green led mip.add_sink('timer/supervisor/green_led', ('pyctrl.rc.led', 'LED'), ['small_angle'], kwargs={'pin': GRN_LED}, enable=True) # add pause button on a timer mip.add_source('timer/supervisor/pause_button', ('pyctrl.rc.button', 'Button'), ['is_running'], kwargs={ 'pin': PAUSE_BTN, 'invert': True }, enable=True) # print controller print(mip.info('all')) # export json? if export_json: from pyctrl.flask import JSONEncoder # export controller as json json = JSONEncoder(sort_keys=True, indent=4).encode(mip) with open('rc_mip_balance.json', 'w') as f: f.write(json) fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: print(""" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * M I P B A L A N C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * """) print(""" Hold your MIP upright to start balancing Use your keyboard to control the mip: * UP and DOWN arrows move forward and back * LEFT and RIGHT arrows steer * / stops forward motion * . stops steering * SPACE resets forward motion and steering """) # reset everything mip.set_source('clock', reset=True) mip.set_source('encoder1', reset=True) mip.set_source('encoder2', reset=True) mip.set_filter('controller', reset=True) mip.set_source('inclinometer', reset=True) # turn on red led red.on() # start the controller mip.start() print("Press Ctrl-C or press the <PAUSE> button to exit") # fire thread to update velocities thread = threading.Thread(target=get_arrows, args=(mip, fd)) thread.daemon = False thread.start() # and wait until controller dies mip.join() # print message print("\nDone with balancing") except KeyboardInterrupt: print("\nBalancing aborted") finally: # turn off red led red.off() # make sure it exits mip.set_state(pyctrl.EXITING) print("Press any key to exit") thread.join() termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
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))
def test_sub_sub_container(self): import pyctrl from pyctrl.block.container import Container, Input, Output, ContainerException from pyctrl.block.system import Gain # create container first container = Container() container.add_signals('s1', 's2', 's3') # add subcontainer container1 = Container() container.add_filter('container1', container1, ['s1'], ['s2', 's3']) self.assertTrue( container.resolve_label('container1') == (container, 'container1')) self.assertTrue( container.resolve_label('./container1') == (container, 'container1')) self.assertTrue( container.resolve_label('/container1') == (container, 'container1')) with self.assertRaises(pyctrl.block.container.ContainerException): container.resolve_label('/container2/something') with self.assertRaises(pyctrl.block.container.ContainerException): container.resolve_label('../something') container.add_signals('container1/s1', 'container1/s2') self.assertTrue( container.resolve_label('container1/s1') == (container1, 's1')) self.assertTrue( container.resolve_label('./container1/s1') == (container1, 's1')) self.assertTrue( container.resolve_label('/container1/s1') == (container1, 's1')) self.assertTrue(container1.resolve_label('../s1') == (container, 's1')) self.assertTrue(container1.resolve_label('s1') == (container1, 's1')) self.assertTrue(container1.resolve_label('./s1') == (container1, 's1')) self.assertTrue( container1.resolve_label('/container1/s1') == (container1, 's1')) container.add_source('container1/input1', Input(), ['s1']) container.add_filter('container1/gain1', Gain(gain=3), ['s1'], ['s2']) container.add_sink('container1/output1', Output(), ['s2']) container.set_enabled(True) container.set_signal('s1', 1) container.run() container.set_enabled(False) self.assertTrue(container.get_signal('s2') == 3) # add subsubcontainer container.add_sink('container1/output2', Output(), ['s3']) container2 = Container() container.add_filter('container1/container2', container2, ['s1'], ['s3']) container.add_signals('container1/container2/s1', 'container1/container2/s2') self.assertTrue( container.resolve_label('container1/container2/s1') == (container2, 's1')) self.assertTrue( container.resolve_label('./container1/container2/s1') == ( container2, 's1')) self.assertTrue( container.resolve_label('/container1/container2/s1') == ( container2, 's1')) self.assertTrue( container.resolve_label('container1/container2/s1') == (container2, 's1')) self.assertTrue( container.resolve_label('./container1/container2/s1') == ( container2, 's1')) self.assertTrue( container.resolve_label('/container1/container2/s1') == ( container2, 's1')) self.assertTrue( container1.resolve_label('container2/s1') == (container2, 's1')) self.assertTrue( container1.resolve_label('./container2/s1') == (container2, 's1')) self.assertTrue( container1.resolve_label('/container1/container2/s1') == ( container2, 's1')) self.assertTrue(container2.resolve_label('s1') == (container2, 's1')) self.assertTrue(container2.resolve_label('./s1') == (container2, 's1')) self.assertTrue( container2.resolve_label('/container1/container2/s1') == ( container2, 's1')) self.assertTrue( container2.resolve_label('../s1') == (container1, 's1')) self.assertTrue( container2.resolve_label('../../s1') == (container, 's1')) self.assertTrue( container2.resolve_label('../container2/s1') == (container2, 's1')) container.add_source('container1/container2/input1', Input(), ['s1']) container.add_filter('container1/container2/gain1', Gain(gain=5), ['s1'], ['s2']) container.add_sink('container1/container2/output1', Output(), ['s2']) print(container.info('all')) container.set_enabled(True) container.set_signal('s1', 1) container.run() container.set_enabled(False) self.assertTrue(container.get_signal('s2') == 3) self.assertTrue(container.get_signal('s3') == 5)
def test_sub_container(self): from pyctrl.block.container import Container, Input, Output, ContainerException from pyctrl.block.system import Gain # create subcontainer first subcontainer = Container() subcontainer.add_signals('s1', 's2') subcontainer.add_source('input1', Input(), ['s1']) subcontainer.add_filter('gain1', Gain(gain=3), ['s1'], ['s2']) subcontainer.add_sink('output1', Output(), ['s2']) subcontainer.set_enabled(True) subcontainer.write(1) values = subcontainer.read() subcontainer.set_enabled(False) self.assertTrue(values == (3, )) # add to container container = Container() container.add_signals('s1', 's2') container.add_filter('container', subcontainer, ['s1'], ['s2']) container.set_enabled(True) container.set_signal('s1', 1) container.run() container.set_enabled(False) self.assertTrue(container.get_signal('s2') == 3) # signals in subcontainer container.set_signal('container/s1', 2) container.add_signal('container/s3') container.set_signal('container/s3', 4) self.assertTrue(container.get_signal('s1') == 1) self.assertTrue(container.get_signal('container/s1') == 2) self.assertTrue(container.get_signal('container/s3') == 4) container.remove_signal('container/s3') with self.assertRaises(KeyError): container.get_signal('container/s3') # sources in subcontainer self.assertTrue(container.get_source('container/input1', 'enabled')) container.set_source('container/input1', enabled=False) self.assertTrue( not container.get_source('container/input1', 'enabled')) container.add_source('container/source1', Input(), ['s1']) self.assertTrue(container.get_source('container/source1', 'enabled')) container.remove_source('container/source1') with self.assertRaises(ContainerException): container.get_source('container/source1') # sinks in subcontainer self.assertTrue(container.get_sink('container/output1', 'enabled')) container.set_sink('container/output1', enabled=False) self.assertTrue(not container.get_sink('container/output1', 'enabled')) container.add_sink('container/sink1', Output(), ['s1']) self.assertTrue(container.get_sink('container/sink1', 'enabled')) container.remove_sink('container/sink1') with self.assertRaises(ContainerException): container.get_sink('container/sink1') # filters in subcontainer self.assertTrue(container.get_filter('container/gain1', 'enabled')) container.set_filter('container/gain1', enabled=False) self.assertTrue(not container.get_filter('container/gain1', 'enabled')) container.add_filter('container/filter1', Gain(), ['s1'], ['s1']) self.assertTrue(container.get_filter('container/filter1', 'enabled')) container.remove_filter('container/filter1') with self.assertRaises(ContainerException): container.get_filter('container/filter1')
def test_enable(self): from pyctrl.block.container import Container, Input, Output from pyctrl.block.system import Gain # create subcontainer first subcontainer = Container() subcontainer.add_signals('s1', 's2') subcontainer.add_source('input1', Input(), ['s1'], enable=True) subcontainer.add_filter('gain1', Gain(gain=3), ['s1'], ['s2']) subcontainer.add_sink('output1', Output(), ['s2']) print(subcontainer.info('all')) subcontainer.set_enabled(True) subcontainer.write(1) values = subcontainer.read() subcontainer.set_enabled(False) self.assertTrue(values == (3, )) print(subcontainer.info('all')) subcontainer.set_source('input1', enable=False) subcontainer.set_signal('s1', 0) print(subcontainer.info('all')) subcontainer.set_enabled(True) subcontainer.write(1) values = subcontainer.read() subcontainer.set_enabled(False) self.assertTrue(values == (0, )) subcontainer.set_source('input1', enable=True) subcontainer.set_filter('gain1', enable=True) subcontainer.set_enabled(True) subcontainer.write(1) values = subcontainer.read() subcontainer.set_enabled(False) self.assertTrue(values == (3, )) subcontainer.set_filter('gain1', enable=False) subcontainer.set_signal('s2', 0) subcontainer.set_enabled(True) subcontainer.write(1) values = subcontainer.read() subcontainer.set_enabled(False) self.assertTrue(values == (0, )) subcontainer.set_filter('gain1', enable=True) subcontainer.set_sink('output1', enable=True) subcontainer.set_signal('s2', 0) subcontainer.set_enabled(True) subcontainer.write(1) values = subcontainer.read() subcontainer.set_enabled(False) self.assertTrue(values == (3, )) subcontainer.set_sink('output1', enable=False) subcontainer.set_signal('s2', 0) subcontainer.set_enabled(True) subcontainer.write(1) values = subcontainer.read() subcontainer.set_enabled(False) self.assertTrue(values == (None, ))