def __init__(self, use_machine=True): if use_machine: self.machine = Machine(CONTROL_HOSTNAME) else: self.machine = None self.map = StoneMap('stonemap') # shortcuts for convenience if self.machine: self.m = self.machine self.c = self.machine.control self.c.reset() self.c.home()
class Brain(object): def __init__(self, use_machine=True): if use_machine: self.machine = Machine(CONTROL_HOSTNAME) else: self.machine = None self.map = StoneMap('stonemap') # shortcuts for convenience if self.machine: self.m = self.machine self.c = self.machine.control self.c.reset() self.c.home() # go home (also test if the machine is initialized and working) # self.c.home() def start(self): pass def run(self, prgname): f = getattr(self, prgname) f() def scan(self, startx=0, starty=0, analyze=True): log.debug('Begin scanning') self.c.pickup_top() self.z = self.c.get_pickup_z() self.m.go(e=90) self.c.block() stones = [] x, y = self.map.size stepx = int(self.machine.cam.viewx / 2.0) stepy = int(self.machine.cam.viewy / 2.0) for i in range(int(startx), x + 1, stepx): for j in range(int(starty), y + 1, stepy): self.m.go(x=i, y=j) self.c.block() if analyze: st = self.machine.cam.grab_extract(i, j, save=True) for s in st: s.center = self.machine.cam.pos_to_mm(s.center, offset=(i, j)) s.size = self.machine.cam.size_to_mm(s.size) s.rank = 0.0 stones.append(s) else: self.machine.cam.grab(save=True) log.debug('End scanning') if analyze: # select correct stones log.debug('Begin selecting/reducing stones') for i in range(len(stones)): for j in range(i + 1, len(stones)): s = stones[i].similarity(stones[j]) stones[i].rank += s stones[j].rank -= s log.debug('End selecting/reducing stones') # copy selected stones to storage self.map.stones = [s for s in stones if s.rank >= 1.5] self.map.save() def scan_from_files(self, analyze=True): import re import os import fnmatch import pickle as serialization log.debug('Begin scanning') cam = Camera(None) stones = [] p = "map_offline/" # looks here for pngs... pngfiles = [] bins = [] for file in os.listdir(p): if fnmatch.fnmatch(file, 'grab*.jpg'): pngfiles.append(file) for fn in pngfiles: m = re.search('\w+_(\d+)_(\d+)', fn) image = cv2.imread(os.path.join(p, fn), -1) (h, w) = image.shape[:2] xp, yp = float(m.group(1)), float(m.group(2)) log.info('Reading file at {} {}'.format(xp, yp)) localstones = [] st = cam.grab_extract(xp, yp, img=image, save=False) for s in st: s.center = cam.pos_to_mm(s.center, offset=(xp, yp)) s.size = cam.size_to_mm(s.size) s.rank = 0.0 stones.append(s) localstones.append(s) bin = {'x': xp, 'y': yp, 'stones': localstones} bins.append(bin) with open('map/intermediate.data', 'wb') as f: serialization.dump(bins, f) log.debug('Found {} stones in {} bins'.format(len(stones), len(bins))) log.debug('End scanning') chosen_stones = [] if analyze: # select correct stones log.debug('Begin selecting/reducing stones') for bi in range(len(bins)): bin_a = bins[bi] stones_a = bin_a['stones'] other_stones = [] for bj in range(bi + 1, len(bins)): bin_b = bins[bj] stones_b = bin_b['stones'] d_x = abs(bin_b['x'] - bin_a['x']) d_y = abs(bin_b['y'] - bin_a['y']) if d_x > cam.viewx * 2.0 or d_y > cam.viewy * 2.0: continue other_stones += stones_b for this_stone in stones_a: for other_stone in other_stones: if this_stone.coincides(other_stone): other_stone.bogus = True if not this_stone.bogus: chosen_stones.append(this_stone) log.debug('End selecting/reducing stones') # copy selected stones to storage self.map.stones = [s for s in chosen_stones] self.map.stage = (0, 2, None, None) log.debug('Reduced from {} to {} stones'.format( len(stones), len(self.map.stones))) self.map.save(meta=True) def demo1(self): # demo program which moves stone back and forth while True: self._move_stone_absolute((3500, 1000), 0, (3500, 1250), 90) self._move_stone_absolute((3500, 1250), 90, (3500, 1000), 0) def demo2(self): while True: self._move_stone((3500, 1000), 30, (3500, 1000), 120) self._move_stone((3500, 1000), 120, (3500, 1000), 30) def demo3(self): while True: self._move_stone((3700, 1000), 30, (3700, 1000), 120) self._move_stone((3700, 1000), 120, (3700, 1000), 30) def _move_stone_absolute(self, c1, a1, c2, a2): log.debug('Abs moving stone center %s angle %s to center %s angle %s', str(c1), str(a1), str(c2), str(a2)) if not self.m.check_movement(x=c1[0], y=c1[1], e=a1): log.warn('Invalid pickup position {},{}. Aborting move.'.format( c1[0], c1[1])) return False if not self.m.check_movement(x=c2[0], y=c2[1], e=a2): log.warn('Invalid placement position {},{}. Aborting move.'.format( c2[0], c2[1])) return False self.m.go(x=c1[0], y=c1[1], e=a1) ret = self.m.lift_up(x=c1[0], y=c1[1]) if ret: self.m.go(x=c2[0], y=c2[1], e=a2) self.m.lift_down() return True else: return False def _turn_stone_calc(self, c1, sa, c2, ea): h1 = self.machine.head_delta(angle=sa) c1 = c1[0] - h1[0], c1[1] - h1[1] h2 = self.machine.head_delta(angle=ea) c2 = c2[0] - h2[0], c2[1] - h2[1] off = (0.0, 0.0) # was 6.0, 0 return (c1[0] + off[0], c1[1] + off[1]), (c2[0] + off[0], c2[1] + off[1] ) # FIXME: Offseted def _move_stone(self, c1, a1, c2, a2): log.debug('Moving stone center %s angle %s to center %s angle %s', str(c1), str(a1), str(c2), str(a2)) da = a1 - a2 if da < 0.0: da = 360.0 + da da = da % 180 # Case 1 nc1, nc2 = self._turn_stone_calc(c1, 0.0, c2, da) max_y = self.map.size[1] if c1[1] >= 0 and c2[1] >= 0 and c1[1] <= max_y and c2[1] <= max_y: return self._move_stone_absolute(nc1, 0, nc2, da) else: # Case 2 nc1, nc2 = self._turn_stone_calc(c1, 180.0, c2, da) return self._move_stone_absolute(nc1, 180.0, nc2, da) # TODO: save map here ? def save_map(self): log.debug('Saving map...') self.map.save() log.debug('Saving map. Done.') def performance(self): saving_thread = threading.Thread(target=save_map, args=(self.map, )) while True: log.debug('Thinking...') i, nc, na, stage, force = art_step(self.map) if i is not None: s = self.map.stones[i] if nc is None: nc = s.center if na is None: na = s.angle log.debug('Placing stone {} from {} to {}'.format( i, s.center, nc)) if self._move_stone(s.center, s.angle, nc, na): # Pickup worked if saving_thread.is_alive(): saving_thread.join( ) # wait until save is completed if still being done s.center = nc s.angle = na self.map.stage = stage # Commit stage log.info('Placement worked') else: # Fail, flag if saving_thread.is_alive(): saving_thread.join( ) # wait until save is completed if still being done s.flag = True log.info('Placement failed') saving_thread = threading.Thread(target=save_map, args=(self.map, )) saving_thread.start() # async call of self.save_map elif force: # Art wants us to advance anyhow if saving_thread.is_alive(): saving_thread.join( ) # wait until save is completed if still being done self.map.stage = stage # Commit stage saving_thread = threading.Thread(target=save_map, args=(self.map, )) saving_thread.start() # async call of self.save_map else: if saving_thread.is_alive(): saving_thread.join( ) # wait until save is completed if still being done time.sleep(1) if saving_thread.is_alive(): saving_thread.join( ) # wait until save is completed if still being done
class Brain(object): def __init__(self, use_machine=True): if use_machine: self.machine = Machine(CONTROL_HOSTNAME) else: self.machine = None self.map = StoneMap('stonemap') # shortcuts for convenience if self.machine: self.m = self.machine self.c = self.machine.control self.c.reset() self.c.home() # go home (also test if the machine is initialized and working) # self.c.home() def start(self): pass def run(self, prgname): f = getattr(self, prgname) f() def scan(self, startx=0, starty=0, analyze=True): log.debug('Begin scanning') self.c.pickup_top() self.z = self.c.get_pickup_z() self.m.go(e=90) self.c.block() stones = [] x, y = self.map.size stepx = int(self.machine.cam.viewx / 2.0) stepy = int(self.machine.cam.viewy / 2.0) for i in range(int(startx), x + 1, stepx): for j in range(int(starty), y + 1, stepy): self.m.go(x=i, y=j) self.c.block() if analyze: st = self.machine.cam.grab_extract(i, j, save=True) for s in st: s.center = self.machine.cam.pos_to_mm(s.center, offset=(i, j)) s.size = self.machine.cam.size_to_mm(s.size) s.rank = 0.0 stones.append(s) else: self.machine.cam.grab(save=True) log.debug('End scanning') if analyze: # select correct stones log.debug('Begin selecting/reducing stones') for i in range(len(stones)): for j in range(i + 1, len(stones)): s = stones[i].similarity(stones[j]) stones[i].rank += s stones[j].rank -= s log.debug('End selecting/reducing stones') # copy selected stones to storage self.map.stones = [s for s in stones if s.rank >= 1.5] self.map.save() def scan_from_files(self, analyze=True): import re import os import fnmatch import pickle as serialization log.debug('Begin scanning') cam = Camera(None) stones = [] p = "map_offline/" # looks here for pngs... pngfiles = [] bins = [] for file in os.listdir(p): if fnmatch.fnmatch(file, 'grab*.jpg'): pngfiles.append(file) for fn in pngfiles: m = re.search('\w+_(\d+)_(\d+)', fn) image = cv2.imread(os.path.join(p, fn), -1) (h, w) = image.shape[:2] xp, yp = float(m.group(1)), float(m.group(2)) log.info('Reading file at {} {}'.format(xp, yp)) localstones = [] st = cam.grab_extract(xp, yp, img=image, save=False) for s in st: s.center = cam.pos_to_mm(s.center, offset=(xp, yp)) s.size = cam.size_to_mm(s.size) s.rank = 0.0 stones.append(s) localstones.append(s) bin = {'x': xp, 'y': yp, 'stones': localstones} bins.append(bin) with open('map/intermediate.data', 'wb') as f: serialization.dump(bins, f) log.debug('Found {} stones in {} bins'.format(len(stones), len(bins))) log.debug('End scanning') chosen_stones = [] if analyze: # select correct stones log.debug('Begin selecting/reducing stones') for bi in range(len(bins)): bin_a = bins[bi] stones_a = bin_a['stones'] other_stones = [] for bj in range(bi + 1, len(bins)): bin_b = bins[bj] stones_b = bin_b['stones'] d_x = abs(bin_b['x'] - bin_a['x']) d_y = abs(bin_b['y'] - bin_a['y']) if d_x > cam.viewx * 2.0 or d_y > cam.viewy * 2.0: continue other_stones += stones_b for this_stone in stones_a: for other_stone in other_stones: if this_stone.coincides(other_stone): other_stone.bogus = True if not this_stone.bogus: chosen_stones.append(this_stone) log.debug('End selecting/reducing stones') # copy selected stones to storage self.map.stones = [s for s in chosen_stones] self.map.stage = (0, 2, None, None) log.debug('Reduced from {} to {} stones'.format(len(stones), len(self.map.stones))) self.map.save(meta=True) def demo1(self): # demo program which moves stone back and forth while True: self._move_stone_absolute((3500, 1000), 0, (3500, 1250), 90) self._move_stone_absolute((3500, 1250), 90, (3500, 1000), 0) def demo2(self): while True: self._move_stone((3500, 1000), 30, (3500, 1000), 120) self._move_stone((3500, 1000), 120, (3500, 1000), 30) def demo3(self): while True: self._move_stone((3700, 1000), 30, (3700, 1000), 120) self._move_stone((3700, 1000), 120, (3700, 1000), 30) def _move_stone_absolute(self, c1, a1, c2, a2): log.debug('Abs moving stone center %s angle %s to center %s angle %s', str(c1), str(a1), str(c2), str(a2)) if not self.m.check_movement(x=c1[0], y=c1[1], e=a1): log.warn('Invalid pickup position {},{}. Aborting move.'.format(c1[0], c1[1])) return False if not self.m.check_movement(x=c2[0], y=c2[1], e=a2): log.warn('Invalid placement position {},{}. Aborting move.'.format(c2[0], c2[1])) return False self.m.go(x=c1[0], y=c1[1], e=a1) ret = self.m.lift_up(x=c1[0], y=c1[1]) if ret: self.m.go(x=c2[0], y=c2[1], e=a2) self.m.lift_down() return True else: return False def _turn_stone_calc(self, c1, sa, c2, ea): h1 = self.machine.head_delta(angle=sa) c1 = c1[0] - h1[0], c1[1] - h1[1] h2 = self.machine.head_delta(angle=ea) c2 = c2[0] - h2[0], c2[1] - h2[1] off = (0.0, 0.0) # was 6.0, 0 return (c1[0] + off[0], c1[1] + off[1]), (c2[0] + off[0], c2[1] + off[1]) # FIXME: Offseted def _move_stone(self, c1, a1, c2, a2): log.debug('Moving stone center %s angle %s to center %s angle %s', str(c1), str(a1), str(c2), str(a2)) da = a1 - a2 if da < 0.0: da = 360.0 + da da = da % 180 # Case 1 nc1, nc2 = self._turn_stone_calc(c1, 0.0, c2, da) max_y = self.map.size[1] if c1[1] >= 0 and c2[1] >= 0 and c1[1] <= max_y and c2[1] <= max_y: return self._move_stone_absolute(nc1, 0, nc2, da) else: # Case 2 nc1, nc2 = self._turn_stone_calc(c1, 180.0, c2, da) return self._move_stone_absolute(nc1, 180.0, nc2, da) # TODO: save map here ? def save_map(self): log.debug('Saving map...') self.map.save() log.debug('Saving map. Done.') def performance(self): saving_thread = threading.Thread(target=save_map, args=(self.map, )) while True: log.debug('Thinking...') i, nc, na, stage, force = art_step(self.map) if i is not None: s = self.map.stones[i] if nc is None: nc = s.center if na is None: na = s.angle log.debug('Placing stone {} from {} to {}'.format(i, s.center, nc)) if self._move_stone(s.center, s.angle, nc, na): # Pickup worked if saving_thread.is_alive(): saving_thread.join() # wait until save is completed if still being done s.center = nc s.angle = na self.map.stage = stage # Commit stage log.info('Placement worked') else: # Fail, flag if saving_thread.is_alive(): saving_thread.join() # wait until save is completed if still being done s.flag = True log.info('Placement failed') saving_thread = threading.Thread(target=save_map, args=(self.map, )) saving_thread.start() # async call of self.save_map elif force: # Art wants us to advance anyhow if saving_thread.is_alive(): saving_thread.join() # wait until save is completed if still being done self.map.stage = stage # Commit stage saving_thread = threading.Thread(target=save_map, args=(self.map, )) saving_thread.start() # async call of self.save_map else: if saving_thread.is_alive(): saving_thread.join() # wait until save is completed if still being done time.sleep(1) if saving_thread.is_alive(): saving_thread.join() # wait until save is completed if still being done