def test_prob_experiment(self): hat = Hat(blue=3, red=2, green=6) probability = experiment(hat=hat, expected_balls={ "blue": 2, "green": 1 }, num_balls_drawn=4, num_experiments=1000) actual = probability expected = 0.272 self.assertAlmostEqual( actual, expected, delta=0.01, msg='Expected experiemnt method to return a different probability.' ) hat = Hat(yellow=5, red=1, green=3, blue=9, test=1) probability = experiment(hat=hat, expected_balls={ "yellow": 2, "blue": 3, "test": 1 }, num_balls_drawn=20, num_experiments=100) actual = probability expected = 1.0 self.assertAlmostEqual( actual, expected, delta=0.01, msg='Expected experiment method to return a different probability.' )
def test_hat_draw(self): hat = Hat(red=5, blue=2) actual = hat.draw(2) expected = ['blue', 'red'] self.assertEqual( actual, expected, 'Expected hat draw to return two random items from hat contents.') actual = len(hat.contents) expected = 5 self.assertEqual( actual, expected, 'Expected hat draw to reduce number of items in contents.')
def test_hat_class_contents(self): hat = Hat(red=3, blue=2) actual = hat.contents expected = ["red", "red", "red", "blue", "blue"] self.assertEqual( actual, expected, 'Expected creation of hat object to add correct contents.')
def run(self): """ Make random draw honoring exclusions Using the people in the exchange self.args.exchange, make a random drawing where no person draws someone prohibited to them in the database exclude table Print the results in a file with eacj "from to" pair on a separate line. """ self.db = sqlite3.connect(self.args.database) people = self.get_people() # If no people are listed, no exchange, so show valid exchanges if not people: self.list_valid_exchanges() quit() excludes = self.set_exclusions(people) try: exchange = Hat(people, excludes).draw() except NoValidDraw: print("Could not make a draw for", file=sys.stderr) print("people: %s" % (people), file=sys.stderr) print("excludes:", file=sys.stderr) for person, exclude in excludes.items(): print(" %s: %s" % (person, exclude), file=sys.stderr) else: self.output(exchange)
def __init__( self, frequency=30, debug=False, verbose=0, calibration_file="bot.json", ): self.debug = debug self.verbose = verbose self.frequency = frequency self.hat = Hat(debug=debug, verbose=verbose) self.hat.open() self.camera = OpenCVCameraSensor(frequency=frequency) self.detector = hsv_detector(debug=debug) # Set the calibration self.calibration_file = calibration_file self.reset_calibration()
def __init__( self, frequency=30, debug=False, verbose=0, derivative_fn=derivative, calibration_file="bot.json", ): self.debug = debug self.verbose = verbose self.frequency = frequency self.derivative_fn = derivative self.vel_x = self.derivative_fn(frequency) self.vel_y = self.derivative_fn(frequency) self.sum_x, self.sum_y = 0, 0 self.hat = Hat(debug=debug, verbose=verbose) self.hat.open() self.camera = OpenCVCameraSensor(frequency=frequency) self.detector = hsv_detector(debug=debug) self.calibration_file = calibration_file self.reset_calibration()
class MoabEnv: def __init__( self, frequency=30, debug=False, verbose=0, derivative_fn=derivative, calibration_file="bot.json", ): self.debug = debug self.verbose = verbose self.frequency = frequency self.derivative_fn = derivative self.vel_x = self.derivative_fn(frequency) self.vel_y = self.derivative_fn(frequency) self.sum_x, self.sum_y = 0, 0 self.hat = Hat(debug=debug, verbose=verbose) self.hat.open() self.camera = OpenCVCameraSensor(frequency=frequency) self.detector = hsv_detector(debug=debug) self.calibration_file = calibration_file self.reset_calibration() def __enter__(self): self.camera.start() return self def __exit__(self, type, value, traceback): self.hat.go_down() self.hat.disable_servos() self.hat.display_power_symbol("TO WAKE", PowerIcon.POWER) self.hat.close() self.camera.stop() def __repr__(self): return self.__str__() def __str__(self): return f"hue: {self.hue}, offsets: {self.servo_offsets}" def reset_calibration(self, calibration_file=None): # Use default if not defined calibration_file = calibration_file or self.calibration_file # Get calibration settings if os.path.isfile(calibration_file): with open(calibration_file, "r") as f: calib = json.load(f) else: # Use defaults calib = { "ball_hue": 44, "plate_offsets": (0.0, 0.0), "servo_offsets": (0.0, 0.0, 0.0), } plate_offsets = calib["plate_offsets"] self.plate_offsets_pixels = meters_to_pixels(plate_offsets) self.servo_offsets = calib["servo_offsets"] self.hue = calib["ball_hue"] # Set the servo offsets (self.hue & self.plate_offsets_pixels are used in step) self.hat.set_servo_offsets(*self.servo_offsets) self.camera.x_offset_pixels = self.plate_offsets_pixels[0] self.camera.y_offset_pixels = self.plate_offsets_pixels[1] def reset(self, text=None, icon=None): # Optionally display the controller active text if icon and text: self.hat.display_string_icon(text, icon) elif text: self.hat.display_string(text) # Reset the derivative of the position # Use a high pass filter instead of a numerical derivative for stability. # A high pass filtered signal can be thought of as a derivative of a low # pass filtered signal: fc*s / (s + fc) = fc*s * 1 / (s + fc) # For more info: https://en.wikipedia.org/wiki/Differentiator # Or: https://www.youtube.com/user/ControlLectures/ self.vel_x = self.derivative_fn(self.frequency) self.vel_y = self.derivative_fn(self.frequency) # Reset the integral of the position self.sum_x, self.sum_y = 0, 0 # Return the state after a step with no motor actions return self.step((0, 0)) def step(self, action) -> Tuple[EnvState, bool, Buttons]: plate_x, plate_y = action self.hat.set_angles(plate_x, plate_y) frame, elapsed_time = self.camera() ball_detected, cicle_feature = self.detector(frame, hue=self.hue) ball_center, ball_radius = cicle_feature x, y = ball_center # Update derivate calulation vel_x, vel_y = self.vel_x(x), self.vel_y(y) # Update the summation (integral calculation) self.sum_x += x self.sum_y += y buttons = self.hat.get_buttons() state = EnvState(x, y, vel_x, vel_y, self.sum_x, self.sum_y) return state, ball_detected, buttons
from hat import Hat, Icon, PowerIcon with Hat() as hat: hat.display_string_icon("DOT", Icon.DOT) input("Confirm: • DOT") hat.display_string_icon("X Mark", Icon.X) input("Confirm: × Mark") hat.display_power_symbol("POWER", PowerIcon.POWER) input("Confirm: ⏻ POWER") hat.display_power_symbol("TOGGLE", PowerIcon.TOGGLE_POWER) input("Confirm: ⏼ TOGGLE") hat.display_power_symbol("ON", PowerIcon.POWER_ON) input("Confirm: ⏽ ON") hat.display_power_symbol("OFF", PowerIcon.POWER_OFF) input("Confirm: ⭘ OFF") hat.display_power_symbol("SLEEP", PowerIcon.SLEEP_MODE) input("Confirm: ⏾ SLEEP") menus = { 0: "§ Berkeley\nCalifornia", 1: "Albany\nKansas City\nBerkeley", 2: "Vancouver, Canada...Albany, NY\nKansas City, MO...Berkeley, CA", } hat.display_long_string(menus[0])
class MoabHardware: def __init__( self, frequency=30, debug=False, verbose=0, calibration_file="bot.json", ): self.debug = debug self.verbose = verbose self.frequency = frequency self.hat = Hat(debug=debug, verbose=verbose) self.hat.open() self.camera = OpenCVCameraSensor(frequency=frequency) self.detector = hsv_detector(debug=debug) # Set the calibration self.calibration_file = calibration_file self.reset_calibration() def __enter__(self): self.camera.start() return self def __exit__(self, type, value, traceback): self.go_down() self.hat.disable_servos() self.hat.display_power_symbol("TO WAKE", PowerIcon.POWER) self.hat.close() self.camera.stop() def __repr__(self): return self.__str__() def __str__(self): return f"hue: {self.hue}, servo offsets: {self.servo_offsets}, plate offsets: {self.plate_offsets}" def reset_calibration(self, calibration_file=None): # Use default if not defined calibration_file = calibration_file or self.calibration_file # Get calibration settings if os.path.isfile(calibration_file): with open(calibration_file, "r") as f: calib = json.load(f) else: # Use defaults calib = { "ball_hue": 44, "plate_offsets": (0.0, 0.0), "servo_offsets": (0.0, 0.0, 0.0), } self.plate_offsets = calib["plate_offsets"] self.servo_offsets = calib["servo_offsets"] self.hue = calib["ball_hue"] def go_up(self): # Set the plate to its hover position, experimentally found to be 150 self.set_servos(150, 150, 150) time.sleep( 0.200) # Give enough time for the action before turning off servos def go_down(self): # Set the plate to its lowest position, experimentally found to be 155 self.set_servos(155, 155, 155) time.sleep( 0.200) # Give enough time for the action before turning off servos def get_buttons(self): # Get the buttons after doing a noop (ensure the buttons are up to date) self.hat.noop() return self.hat.get_buttons() def enable_servos(self): self.hat.enable_servos() def disable_servos(self): self.hat.disable_servos() def set_servos(self, s1, s2, s3): # Note the indexing offset s1 += self.servo_offsets[0] s2 += self.servo_offsets[1] s3 += self.servo_offsets[2] self.hat.set_servos((s1, s2, s3)) def display( self, text: Optional[str] = None, icon: Optional[str] = None, scrolling: bool = False, ): # Optionally display the controller active text if icon and text: if scrolling: raise ValueError( "Cannot display scrolling screen with an icon") self.hat.display_string_icon(text, icon) elif text: if scrolling: self.hat.display_long_string(text) else: self.hat.display_string(text) def set_angles(self, pitch, roll): s1, s2, s3 = plate_angles_to_servo_positions(pitch, roll) self.set_servos(s1, s2, s3) def step(self, pitch, roll) -> Buttons: self.set_angles(pitch, roll) frame, elapsed_time = self.camera() buttons = self.hat.get_buttons() ball_detected, (ball_center, ball_radius) = self.detector(frame, hue=self.hue) return ball_center, ball_detected, buttons
from game import Game from player import Player from repositories.game import GameRepository import callbacks.register_flow from telegram.ext import Updater, CommandHandler, MessageHandler, Filters from utils.read_token import read_token import logging TOKEN = read_token() game_repo = GameRepository() hat = Hat() game = game_repo.create(hat) logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) def main(): updater = Updater(TOKEN, use_context=True) dispatcher = updater.dispatcher dispatcher.add_handler( CommandHandler("start", callbacks.register_flow.start))