示例#1
0
screen = Screen()
screen.hide_cursor()

w, h = screen.shape

for image_file in ('tux.png', 'pobot.png', 'smiley.png'):
    decal = Image.open(os.path.join(os.path.dirname(__file__), 'img', image_file))
    iw, ih = decal.size

    screen.draw.rectangle(
        ((0, 0), (w-1, h-1)),
        outline='black'
    )

    for i, dim in enumerate(zip('wh', (w, h))):
        label, value = dim
        s = "%s=%d" % (label, value)
        tw, th = screen.draw.textsize(s)
        screen.draw.text((w - tw - 1, 2 + i * th), s)

    screen.draw.arc((5, 5, 25, 25), 0, 360)
    screen.draw.arc((w - 25, h - 25, w - 5, h - 5), 0, 360)

    screen.img.paste(decal, ((w - iw)/2, (h - ih)/2, (w + iw)/2, (h + ih)/2), decal)

    screen.update()

    time.sleep(5)

    screen.clear()
class Grabber(object):
    WHEELS_DIST = 140           # mm
    WHEEL_DIAMETER = 43.2       # mm

    EXPLORATION_RANGE = 300     # mm
    DEPOSIT_DIST = 250          # mm

    def __init__(self):
        self._motor_left = ev3.LargeMotor(port='outB')
        self._motor_right = ev3.LargeMotor(port='outC')
        self._motors = (self._motor_left, self._motor_right)

        self._gripper = Gripper(ev3.MediumMotor(port='outA'))

        self._color_sensor = ev3.ColorSensor(port='in1')
        self._start_btn = ev3.TouchSensor(port='in2')

        self._buttons = ev3.Buttons()
        self._buttons.on_back = self._back_button_pressed

        self._screen = Screen()
        self._screen.hide_cursor()

        self._done = False

        self._dist_per_pulse = self.WHEEL_DIAMETER * math.pi / self._motors[0].count_per_rot
        self._spin_per_pulse = math.degrees(self._dist_per_pulse / self.WHEELS_DIST * 2)

        self._images = dict()

    def _back_button_pressed(self, state):
        self._done = True

    def reset(self):
        for m in self._motors:
            m.reset()
            m.duty_cycle_sp = 100
            m.stop_command = ev3.LargeMotor.STOP_COMMAND_HOLD
            m.ramp_up_sp = 500
            m.ramp_down_sp = 500

        self._color_sensor.mode = ev3.ColorSensor.MODE_COL_COLOR
        ev3.Leds.all_off()

        self._done = False

    def display_image(self, name, centered=True):
        # cache images to avoid re-reading them for each request
        # (we use a lazy loading method to avoid too long program
        # start time if loading all of them on init)
        try:
            img = self._images[name]
        except KeyError:
            self._images[name] = img = Image.open(os.path.join(os.path.dirname(__file__), 'img', name + '.png'))

        self._screen.clear()
        if centered:
            xy = tuple((d1 - d0) / 2 for d1, d0 in zip(self._screen.shape, img.size))
        else:
            xy = (0, 0)
        self._screen.img.paste(img, xy)
        self._screen.update()

    def run(self):
        self.reset()

        ev3.Leds.heartbeat(red=1, green=1)
        self.display_image("smiley-o")
        ev3.Sound.speak("I am calibrating my gripper")

        self.display_image("smiley-busy")
        self._gripper.calibrate()
        self._gripper.open()

        ev3.Sound.speak('I am ready').wait()
        self._buttons.start_scanner()

        self._done = False
        try:
            while not self._done:
                self.display_image("smiley-o")
                LedFeedback.k2000(red=1, green=1)
                ev3.Sound.speak('Press touch sensor to start').wait()

                self.display_image("smiley-asleep")
                while not (self._start_btn.is_pressed or self._done):
                    time.sleep(0.1)
                while self._start_btn.is_pressed and not self._done:
                    time.sleep(0.1)

                if not self._done:
                    self.display_image("smiley-waiting")
                    LedFeedback.searching()
                    self.grab_a_brick()

        finally:
            self._buttons.stop_scanner()

        ev3.Leds.red_on()

        self.display_image('terminator', centered=False)

        ev3.Sound.speak("I'll be back").wait()

    def grab_a_brick(self):
        # reset encoders
        for m in self._motors:
            m.position = 0

        brick_found = self.drive_until_brick_found(max_dist=self.EXPLORATION_RANGE)
        good_one = None         # we don't need to set it here, but it's cleaner

        if brick_found:
            brick_color = self.analyze_brick()
            try:
                self.display_image("smiley-happy")
                msg = "this is a %s brick" % {
                    ev3.ColorSensor.COLOR_GREEN: 'green',
                    ev3.ColorSensor.COLOR_RED: 'red',
                }[brick_color]
                good_one = True

            except KeyError:
                self.display_image("smiley-wtf")
                msg = "I do not know this color"
                good_one = False

            ev3.Sound.speak(msg).wait()
            LedFeedback.brick_color(brick_color)

        else:
            self.display_image("smiley-sad")
            ev3.Sound.speak("There is no brick").wait()
            brick_color = None  # we don't need to set it, but it's cleaner
            ev3.Leds.all_off()

        # go back home first in any case
        dist = self._motor_left.position * self._dist_per_pulse
        backing_sound = ev3.Sound.play(os.path.join(_HERE, 'snd', 'backing_alert.rsf'))
        self.drive(-dist)

        if brick_found:
            if good_one:
                turn_direction = {
                        ev3.ColorSensor.COLOR_GREEN: -1,
                        ev3.ColorSensor.COLOR_RED: 1,
                    }[brick_color]

                self.spin(turn_direction * 90)
                self.drive(self.DEPOSIT_DIST)
                self._gripper.open()
                self.drive(-self.DEPOSIT_DIST)
                self.spin(-turn_direction * 90)

            else:
                backing_sound.wait()
                self._gripper.open()
                self.display_image("smiley-o")
                ev3.Sound.speak("Please take the brick").wait()

        else:
            # nothing special to do here
            pass

        backing_sound.wait()
        ev3.Leds.all_off()

    def drive_for_ever(self, power_pct=100):
        for m in self._motors:
            m.run_forever(
                duty_cycle_sp=power_pct
            )

    def drive(self, dist_mm, power_pct=100):
        """ Travels straight by a given distance.

        :param dist_mm: the distance of the travel
        :param power_pct: percent of power
        """
        pulses = dist_mm / self._dist_per_pulse
        for m in self._motors:
            m.position_sp = pulses
            m.duty_cycle_sp = power_pct

        self.run_and_wait_for_completion(absolute=False)

    def run_and_wait_for_completion(self, absolute=True):
        for m in self._motors:
            m.command = m.COMMAND_RUN_TO_ABS_POS if absolute else m.COMMAND_RUN_TO_REL_POS
        while any((m.state and 'holding' not in m.state for m in self._motors)):
            time.sleep(0.1)

    def stop(self, brake=True):
        for m in self._motors:
            m.stop(stop_command='brake' if brake else 'coast')

    def drive_until_brick_found(self, max_dist=300, power_pct=100):
        m = self._motors[0]
        limit = m.position + max_dist / self._dist_per_pulse
        self.drive_for_ever(power_pct=power_pct)
        while m.position <= limit and not self._color_sensor.value():
            time.sleep(0.1)
        self.stop()
        return self._color_sensor.value()

    def spin(self, degrees, power_pct=100):
        """ Spins by a given amount of degrees.

        :param degrees: spin degrees (>0 = CCW)
        :param power_pct: percent of power
        """
        pulses = degrees / self._spin_per_pulse
        for i, m in enumerate(self._motors):
            m.duty_cycle_sp = power_pct
            m.position_sp = pulses * (1 if i else -1)

        self.run_and_wait_for_completion(absolute=False)

    def analyze_brick(self):
        # move forward a bit gently to place the brick well inside the gripper
        self.drive(dist_mm=50, power_pct=30)
        self._gripper.close()

        # leave some time to the sensor for updating its reading accurately
        time.sleep(0.2)

        return self._color_sensor.value()