Exemplo n.º 1
0
    def driveStraightForDistance(self,
                                 distance,
                                 speedLeft=None,
                                 speedRight=None,
                                 stopAtEnd=True):
        ''' Drive for given distance.

    Args:
      distance: distance to drive in mm
      speedLeft: speed in mm/s (left motor)
      speedRight: speed in mm/s (right motor)
      stopAtEnd (bool): brake at end of movement
    '''
        if speedLeft == None or speedLeft == 0:
            speedLeft = self.defaultSpeed

        if speedRight == None or speedRight == 0:
            speedRight = self.defaultSpeed

        degPerSecLeft = 360 * speedLeft / (pi * self.wheel_diameter)
        degPerSecRight = 360 * speedRight / (pi * self.wheel_diameter)

        driveTime = StopWatch()
        driveTime.start()

        self.leftDriveMotor.on(SpeedNativeUnits(degPerSecLeft), block=False)
        self.rightDriveMotor.on(SpeedNativeUnits(degPerSecRight), block=False)

        while driveTime.value_ms <= abs(distance / speedLeft) * 1000:
            sleep(0.02)

        if stopAtEnd:
            self.leftDriveMotor.stop()
            self.rightDriveMotor.stop()
            sleep(0.01)
Exemplo n.º 2
0
    def gotoXY(self, x, y, speed=30, block=True):
        ''' Move to absolute position (x,y).
      
      moves axes simultaneously.
      homeXY must be called first.

      Args:
        x: position of the x-axis (mm)
        y: position of the y-axis (mm)
        speed: the speed of the axes (mm/s)
        block (bool): block until move is complete
      '''
        # start move to x position
        self.xMotor.on_to_position(SpeedNativeUnits(speed * self.xRatio),
                                   x * self.xRatio,
                                   brake=False,
                                   block=False)

        # start move to y position
        self.yMotor.on_to_position(SpeedNativeUnits(speed * self.yRatio),
                                   y * self.yRatio,
                                   brake=False,
                                   block=False)

        if block:
            # sleep until either move is complete or motors stall
            self.xMotor.wait_until_not_moving(self.defaultTimeout)
            self.yMotor.wait_until_not_moving(self.defaultTimeout)
Exemplo n.º 3
0
    def line_follow(self, speed:int, distance_in, which_color_sensor='right', brake=True, block=True):
        cs = self.choose_color_sensor(which_color_sensor)
        integral = 0.0
        last_error = 0.0
        derivative = 0.0
        
        kp = .5
        ki = .1
        kd = .1
        
        target_light_intensity = self.line_square_intensity
        speed_native_units = self.left_motor._speed_native_units(speed)
        while self.follow_for_distance(distance_in, speed):
            reflected_light_intensity = cs.reflected_light_intensity
            error = target_light_intensity - reflected_light_intensity
            integral = integral + error
            derivative = error - last_error
            last_error = error
            turn_native_units = (kp * error) + (ki * integral) + (kd * derivative)
            left_speed = SpeedNativeUnits(speed_native_units - turn_native_units)
            right_speed = SpeedNativeUnits(speed_native_units + turn_native_units)

            self.debug("target_light_intensity: {}, error: {}, integral: {}, derivative: {}, last_error: {}, turn_native_units: {}, left_speed: {}, right_speed: {}".format(target_light_intensity, error, integral, derivative, last_error, turn_native_units, left_speed, right_speed))

            self.on(left_speed, right_speed)
Exemplo n.º 4
0
    def on_for_distance(self, speed:int, distance_in:int, brake=True, block=True, use_gyro=False, target=0, which_gyro_sensor="right"):
        """
        Drives for a certain distance
        and has a toglable gyro feature
        ``speed`` can be a percentage or a :class:`ev3dev2.motor.SpeedValue`
        object, enabling use of other units.
        """
        # self.reset()
        
        # values from ev3dev2 source
        #kp = 11.3
        #ki = 0.05
        #kd = 3.2

        kp = 11.3
        ki = 2
        kd = 3.2
        
        distance_mm = self.in_to_mm(distance_in)
        if use_gyro:
            self.set_led('AMBER')
            gyro = self.choose_gyro_sensor(which_gyro_sensor)
            gyro.mode = gyro.MODE_GYRO_ANG
            # there is currently a bug in gyro.reset() method so instead we just read the current
            # angle and then compare to that
            gyro.reset()
            # reset_angle = gyro.angle
            self.debug("GYRO ANGLE BEFORE LOOP: {}".format(gyro.angle))
            
            # convert speed to a SpeedValue if not already
            speed_native_units = self.left_motor._speed_native_units(speed)
            integral = 0.0 # integral is the sum of all errors
            last_error = 0.0 # last_error stores the last error through the while loop
            derivative = 0.0  # derivative is the rate at which the error is changing      
            while self.follow_for_distance(distance_in, speed):
                # error = gyro.angle - reset_angle # OLD CODE BEFORE GYRO.RESET FIXED
                error = gyro.angle - target
                integral = integral + error
                derivative = error - last_error
                last_error = error
                turn_native_units = (kp * error) + (ki * integral) + (kd * derivative)
                left_speed = SpeedNativeUnits(speed_native_units - turn_native_units)
                right_speed = SpeedNativeUnits(speed_native_units + turn_native_units)
                self.debug("error: {}, integral: {}, derivative: {}, last_error: {},\
                turn_native_units: {}, left_speed: {}, right_speed: {}".format\
                (error, integral, derivative, last_error, turn_native_units, left_speed, right_speed))
                self.on(left_speed, right_speed)
                self.sleep_in_loop(0.01)
        else:
            super().on_for_distance(speed, distance_mm, brake, block)

        self.set_led()
Exemplo n.º 5
0
    def pivot_gyro(self, speed, target_angle=0, sleep_time=0.01):
        """
        Pivot Turn
        ``speed`` is the desired speed of the midpoint of the robot
        ``target_angle`` is the angle we want drive
        ``sleep_time`` is how many seconds we sleep on each pass through
            the loop.  This is to give the robot a chance to react
            to the new motor settings. This should be something small such
            as 0.01 (10ms).
        Example:
        .. code:: python
            from ev3dev2.motor import OUTPUT_A, OUTPUT_B, MoveTank, SpeedPercent
            from ev3dev2.sensor.lego import GyroSensor
            tank = MoveTank(OUTPUT_A, OUTPUT_B)
            tank.gyro = GyroSensor()
            try:
                # Reset gyro sensor to zero
                tank.calibrate_gyro()

                # Pivot 30 degrees
                tank.pivot_gyro(
                    speed=SpeedPercent(5),
                    target_angle(30)
                )
            except Exception:
                tank.stop()
                raise
        """
        assert self.gyro, "GyroSensor must be defined"

        speed_native_units = speed.to_native_units(self.left_motor)
        target_reached = False

        while not target_reached:
            current_angle = self.gyro.angle
            if (current_angle >= target_angle - 2
                    and current_angle <= target_angle + 2):
                target_reached = True
                self.stop()
            elif (current_angle > target_angle):
                left_speed = SpeedNativeUnits(-1 * speed_native_units)
                right_speed = SpeedNativeUnits(speed_native_units)
            else:
                left_speed = SpeedNativeUnits(speed_native_units)
                right_speed = SpeedNativeUnits(-1 * speed_native_units)

            if sleep_time:
                sleep(sleep_time)

            self.on(left_speed, right_speed)
Exemplo n.º 6
0
def follow_line_dual(self, kp, ki, kd, speed, sleep_time, follow_for,
                     **kwargs):

    # PID line follower using both color sensors
    # requires defintion of color sensors cs_l and cs_r

    # dt = sleep_time
    # RC = 1 / (2 * pi * LP_CUTOFF_FREQ)

    e = e_prev = i = d_prev = 0.0

    speed = speed_to_speedvalue(speed)
    speed_native_units = speed.to_native_units(self.left_motor)

    # t0 = time.clock()
    # t = 0
    max_speed = SPEED_MAX_NATIVE

    while follow_for(self, **kwargs):

        e = self.cs_l.reflected_light_intensity - self.cs_r.reflected_light_intensity
        i += e

        d = (e - e_prev)
        # d = (e - e_prev) / dt
        # d = d_prev + ((dt / (RC + dt)) * (d - d_prev))
        # d_prev = d

        u = (kp * e) + (ki * i) + (kd * d)
        e_prev = e

        # slewrate
        # if (SLEW_RATE and t < 1):
        # 	t = time.clock() - t0
        # 	max_speed = SPEED_MAX_NATIVE * min(t * SLEW_RATE, 1.0)

        # convert to native speed units (saturated)
        speed_left = SpeedNativeUnits(
            saturate(speed_native_units - u, max_speed))
        speed_right = SpeedNativeUnits(
            saturate(speed_native_units + u, max_speed))

        # if sleep_time:
        # 	time.sleep(sleep_time)

        self.on(speed_left, speed_right)

    self.stop()
Exemplo n.º 7
0
    def test_units(self):
        clean_arena()
        populate_arena([('large_motor', 0, 'outA'),
                        ('large_motor', 1, 'outB')])

        m = Motor()

        self.assertEqual(
            SpeedPercent(35).to_native_units(m), 35 / 100 * m.max_speed)
        self.assertEqual(SpeedDPS(300).to_native_units(m), 300)
        self.assertEqual(SpeedNativeUnits(300).to_native_units(m), 300)
        self.assertEqual(SpeedDPM(30000).to_native_units(m), (30000 / 60))
        self.assertEqual(SpeedRPS(2).to_native_units(m), 360 * 2)
        self.assertEqual(SpeedRPM(100).to_native_units(m), (360 * 100 / 60))

        self.assertEqual(DistanceMillimeters(42).mm, 42)
        self.assertEqual(DistanceCentimeters(42).mm, 420)
        self.assertEqual(DistanceDecimeters(42).mm, 4200)
        self.assertEqual(DistanceMeters(42).mm, 42000)

        self.assertAlmostEqual(DistanceInches(42).mm, 1066.8)
        self.assertAlmostEqual(DistanceFeet(42).mm, 12801.6)
        self.assertAlmostEqual(DistanceYards(42).mm, 38404.8)

        self.assertEqual(DistanceStuds(42).mm, 336)
Exemplo n.º 8
0
    def run(self):
        print("Engine running!")
        if self.handmax != 0:
            self.calibrate()
        # Change this function to suit your robot.
        # The code below is for driving a simple tank.
        while running:
            # We have run out of records
            if replay and record.empty():
                continue
            # Do normal replay
            elif replay:
                cur_record = record.get()
                left_dc = cur_record[0][0]
                left_speed = SpeedNativeUnits(cur_record[0][1])
                right_dc = cur_record[1][0]
                right_speed = SpeedNativeUnits(cur_record[1][1])
                print(left_speed, left_dc, right_speed, right_dc)
                self.tank.right_motor.on_to_position(right_speed, right_dc)
                self.tank.left_motor.on_to_position(left_speed,
                                                    left_dc,
                                                    block=True)

            # Run by controller
            else:
                right_dc = clamp(-speed - turn)
                left_dc = clamp(-speed + turn)
                self.tank.on(left_dc, right_dc)
                if do_record:
                    record.put(([
                        self.tank.left_motor.position,
                        self.tank.left_motor.speed
                    ], [
                        self.tank.right_motor.position,
                        self.tank.left_motor.speed
                    ]))

            #self.right_motor.on_fo(duty_cycle_sp=right_dc)
            #self.left_motor.run_direct(duty_cycle_sp=left_dc)
            if hand:
                self.movehand()
                hand = 0
            self.movedrop(drop)

        #self.right_motor.stop()
        #self.left_motor.stop()
        self.tank.stop()
Exemplo n.º 9
0
    def test_units(self):
        clean_arena()
        populate_arena([('large_motor', 0, 'outA'), ('large_motor', 1, 'outB')])

        m = Motor()

        self.assertEqual(SpeedPercent(35).get_speed_pct(m), 35)
        self.assertEqual(SpeedDPS(300).get_speed_pct(m), 300 / 1050 * 100)
        self.assertEqual(SpeedNativeUnits(300).get_speed_pct(m), 300 / 1050 * 100)
        self.assertEqual(SpeedDPM(30000).get_speed_pct(m), (30000 / 60) / 1050 * 100)
        self.assertEqual(SpeedRPS(2).get_speed_pct(m), 360 * 2 / 1050 * 100)
        self.assertEqual(SpeedRPM(100).get_speed_pct(m), (360 * 100 / 60) / 1050 * 100)
Exemplo n.º 10
0
    def test_units(self):
        clean_arena()
        populate_arena([('large_motor', 0, 'outA'),
                        ('large_motor', 1, 'outB')])

        m = Motor()

        self.assertEqual(
            SpeedPercent(35).to_native_units(m), 35 / 100 * m.max_speed)
        self.assertEqual(SpeedDPS(300).to_native_units(m), 300)
        self.assertEqual(SpeedNativeUnits(300).to_native_units(m), 300)
        self.assertEqual(SpeedDPM(30000).to_native_units(m), (30000 / 60))
        self.assertEqual(SpeedRPS(2).to_native_units(m), 360 * 2)
        self.assertEqual(SpeedRPM(100).to_native_units(m), (360 * 100 / 60))
Exemplo n.º 11
0
    def follow_line(self,
                    kp,
                    ki,
                    kd,
                    speed,
                    target_light_intensity=None,
                    follow_left_edge=True,
                    white=60,
                    off_line_count_max=20,
                    sleep_time=0.01,
                    follow_for=follow_for_forever,
                    prox_treshold=50,
                    **kwargs):
        """
        PID line follower
        ``kp``, ``ki``, and ``kd`` are the PID constants.
        ``speed`` is the desired speed of the midpoint of the robot
        ``target_light_intensity`` is the reflected light intensity when the color sensor
            is on the edge of the line.  If this is None we assume that the color sensor
            is on the edge of the line and will take a reading to set this variable.
        ``follow_left_edge`` determines if we follow the left or right edge of the line
        ``white`` is the reflected_light_intensity that is used to determine if we have
            lost the line
        ``off_line_count_max`` is how many consecutive times through the loop the
            reflected_light_intensity must be greater than ``white`` before we
            declare the line lost and raise an exception
        ``sleep_time`` is how many seconds we sleep on each pass through
            the loop.  This is to give the robot a chance to react
            to the new motor settings. This should be something small such
            as 0.01 (10ms).
        ``follow_for`` is called to determine if we should keep following the
            line or stop.  This function will be passed ``self`` (the current
            ``MoveTank`` object). Current supported options are:
            - ``follow_for_forever``
            - ``follow_for_ms``
        ``**kwargs`` will be passed to the ``follow_for`` function
        Example:
        .. code:: python
            from ev3dev2.motor import OUTPUT_A, OUTPUT_B, MoveTank, SpeedPercent, follow_for_ms
            from ev3dev2.sensor.lego import ColorSensor
            tank = MoveTank(OUTPUT_A, OUTPUT_B)
            tank.cs = ColorSensor()
            try:
                # Follow the line for 4500ms
                tank.follow_line(
                    kp=11.3, ki=0.05, kd=3.2,
                    speed=SpeedPercent(30),
                    follow_for=follow_for_ms,
                    ms=4500
                )
            except Exception:
                tank.stop()
                raise
        """
        assert self.cs, "ColorSensor must be defined"

        if target_light_intensity is None:
            target_light_intensity = self.cs.reflected_light_intensity

        integral = 0.0
        last_error = 0.0
        derivative = 0.0
        off_line_count = 0

        speed_native_units = speed.to_native_units(self.left_motor)
        print(speed_native_units)
        MAX_SPEED = SpeedNativeUnits(self.max_speed)
        button = Button()

        while follow_for(self, **kwargs):
            if "down" in button.buttons_pressed:
                self.stop()
                return

            reflected_light_intensity = self.cs.reflected_light_intensity
            error = reflected_light_intensity - target_light_intensity
            integral = integral + error
            derivative = error - last_error

            print("target: {:^20} light: {:^20}, deri: {:^5}, integral: {:^5}".
                  format(target_light_intensity, reflected_light_intensity,
                         derivative, integral))

            if derivative > 6:  #or abs(integral) > 100:
                self.stop()
                print("Wrong way")
                return
            #    self.on_for_degrees(SpeedPercent(-10), SpeedPercent(10), 100)
            #    integral = 0
            #    last_error = 0
            #    derivative = 0
            #    off_line_count = 0
            #    time.sleep(1)
            #    continue

            if integral > 150:
                self.stop()
                print("Too high integral")
                integral = -100.0
                # We are correcting heading too much to the left, make correction to right
                self.on_for_degrees(SpeedPercent(30), SpeedPercent(-30), 150)
                self.on_until_target(target_light_intensity)
                continue

            last_error = error
            turn_native_units = (kp * error) + (ki * integral) + (kd *
                                                                  derivative)

            if not follow_left_edge:
                turn_native_units *= -1

            left_speed = SpeedNativeUnits(speed_native_units -
                                          turn_native_units)
            right_speed = SpeedNativeUnits(speed_native_units +
                                           turn_native_units)

            # Is distance to wall too close?
            #if self.us.proximity < prox_treshold:
            #    print("Too close")
            #    self.stop()
            #    in_line = reflected_light_intensity >= white

            #    turn_help = self.get_next_turn()
            #    # If we are still in line, safe to turn straight away
            #    if in_line:
            #        self.on_for_degrees(turn_help[0], turn_help[1], turn_help[2])

            #    else:
            #        self.on_for_seconds(SpeedPercent(-10), SpeedPercent(-10), 1)
            #        self.on_for_degrees(turn_help[0], turn_help[1], turn_help[2])

            #    # Reset values for new straigth line
            #    integral = 0
            #    last_error = 0
            #    derivative = 0
            #    off_line_count = 0
            #    time.sleep(2)
            #    continue

            # Have we lost the line?
            if reflected_light_intensity >= white:
                off_line_count += 1

                if off_line_count >= off_line_count_max:
                    self.stop()
                    print("Lost line")
                    raise LineFollowErrorLostLine("we lost the line")
            else:
                off_line_count = 0

            if sleep_time:
                time.sleep(sleep_time)

            self.on(left_speed, right_speed)

        self.stop()
Exemplo n.º 12
0
tank_pair = MoveTank(OUTPUT_B, OUTPUT_C)
leftMotor = ev3dev2.motor.Motor(OUTPUT_B)
rightMotor = ev3dev2.motor.Motor(OUTPUT_C)
# Connect an EV3 color sensor to any sensor port.
cl = ColorSensor()

while not btn.any():
    leftSpeeds=[]
    rightSpeeds=[]
    for x in range(600):
           # exit loop when any button pressed
        # if we are over the black line (weak reflection)
        rintensity=cl.reflected_light_intensity
        lmotorpower=-((100/70)*(rintensity-70)+100)
        rmotorpower=-(100-((100/70)*(rintensity-70)+100))
        leftMotor.on(SpeedNativeUnits(lmotorpower))
        rightMotor.on(SpeedNativeUnits(rmotorpower))
        sleep(0.05)
        leftSpeeds.append(leftMotor.speed)
        rightSpeeds.append(rightMotor.speed)
        """if cl.reflected_light_intensity<30:
            # medium turn right

            leftMotor.on(SpeedNativeUnits(-100))
            #leftMotor.speedNativeUnits(-500)
            rightMotor.on(SpeedNativeUnits(0))

            #leftMotor.speedNativeUnits(-500)
            #rightMotor.speedNativeUnits(0)
            leftSpeeds.append(leftMotor.speed)
            rightSpeeds.append(rightMotor.speed)
Exemplo n.º 13
0
    def followLineDist(self,
                       distance,
                       sensor,
                       sideToFollow,
                       stopAtEnd,
                       speed,
                       gain_multiplier=1):
        ''' Drive forward following line.  

    Uses direct control of drive motors and PD control. 

    Args:
      distance: distance to follow line in mm
      sensor: colorsensor to use for line following
      sideToFollow: which side of line to follow:  LineEdge.LEFT or LineEdge.RIGHT
      stopAtEnd (bool): Stop motors at end of line following
      speed: speed in mm/s
      gain_multiplier: multiplier for P and D gains
      
    '''
        degPerSec = 360 * speed / (pi * self.wheel_diameter)
        propGain = 6.0 * gain_multiplier
        derivGain = 6 * gain_multiplier

        target = (self.blackThreshold + self.whiteThreshold) / 2

        print("******* starting line following ********")
        # print("error,Pterm,Dterm")

        # initialize term for derivative calc
        previousError = target - avgReflection(sensor, 2)

        i = 0
        driveTime = StopWatch()
        driveTime.start()

        while driveTime.value_ms <= abs(distance / speed) * 1000:
            # calc error and proportional term
            error = target - avgReflection(sensor, 2)
            Pterm = propGain * error

            # calc d(error)/d(t) and derivative term
            d_error_dt = error - previousError
            Dterm = derivGain * d_error_dt
            previousError = error

            if sideToFollow == LineEdge.RIGHT:
                self.leftDriveMotor.on(SpeedNativeUnits(degPerSec + Pterm +
                                                        Dterm),
                                       block=False)
                self.rightDriveMotor.on(SpeedNativeUnits(degPerSec - Pterm -
                                                         Dterm),
                                        block=False)
                # eprint("{:7.2f},{:7.2f},{:7.2f}".format(error, Pterm, Dterm)) # for debugging

            if sideToFollow == LineEdge.LEFT:
                self.leftDriveMotor.on(SpeedNativeUnits(degPerSec - Pterm -
                                                        Dterm),
                                       block=False)
                self.rightDriveMotor.on(SpeedNativeUnits(degPerSec + Pterm +
                                                         Dterm),
                                        block=False)
                # eprint("{:7.2f},{:7.2f},{:7.2f}".format(error, Pterm, Dterm)) # for debugging

        # eprint("line following complete")

        if stopAtEnd:
            self.leftDriveMotor.stop()
            self.rightDriveMotor.stop()
            sleep(0.01)

        # Play sound when we stop line following
        sound.beep()
Exemplo n.º 14
0
    def follow_line(self,
                    kp,
                    ki,
                    kd,
                    side,
                    speed=SpeedPercent(50),
                    target_light_intensity=None,
                    follow_left_edge=True,
                    white=60,
                    off_line_count_max=20,
                    sleep_time=0.01,
                    follow_for=follow_for_forever,
                    **kwargs):

        self.cs = self.sLS_left

        if target_light_intensity is None:
            target_light_intensity = self.get_light_intensitiy(side)

        integral = 0.0
        last_error = 0.0
        derivative = 0.0
        off_line_count = 0
        speed_native_units = -speed.to_native_units(self.motor_left)
        MAX_SPEED = SpeedNativeUnits(self.max_speed / 2)

        while follow_for(self, **kwargs):
            if args.light_mode == 'ambient':
                reflected_light_intensity = self.cs.ambient_light_intensity
            else:
                reflected_light_intensity = self.cs.reflected_light_intensity
            error = target_light_intensity - reflected_light_intensity
            integral = integral + error
            derivative = error - last_error
            last_error = error
            turn_native_units = -((kp * error) + (ki * integral) +
                                  (kd * derivative))

            if not follow_left_edge:
                turn_native_units *= -1

            #if error < last_error:
            #    speed_native_units -= 2
            #elif error > last_error:
            #    speed_native_units += 5

            right_speed = SpeedNativeUnits(speed_native_units -
                                           turn_native_units)
            left_speed = SpeedNativeUnits(speed_native_units +
                                          turn_native_units)
            print(turn_native_units, speed_native_units)

            # DEBUG
            #print('Error: %s' % error)
            #print('reflected_light_intesity: : %s' % reflected_light_intensity)
            #print('integral: %s' % integral)
            #print('derivative: %s' % derivative)
            #print('last_error: %s' % last_error)
            #print('turn_native_units: %s' % turn_native_units)
            #print('left_speed: %s' % left_speed)
            #print('right_speed: %s' % right_speed)

            if left_speed > MAX_SPEED:
                print("%s: left_speed %s is greater than MAX_SPEED %s" %
                      (self, left_speed, MAX_SPEED))
                self.mMT.stop()
                raise LineFollowErrorTooFast(
                    "The robot is moving too fast to follow the line")

            if right_speed > MAX_SPEED:
                print("%s: right_speed %s is greater than MAX_SPEED %s" %
                      (self, right_speed, MAX_SPEED))
                self.mMT.stop()
                raise LineFollowErrorTooFast(
                    "The robot is moving too fast to follow the line")

            # Have we lost the line?
            if reflected_light_intensity >= white:
                off_line_count += 1

                if off_line_count >= off_line_count_max:
                    self.mMT.stop()
                    raise LineFollowErrorLostLine("we lost the line")
            else:
                off_line_count = 0

            if sleep_time:
                time.sleep(sleep_time)

            self.mMT.on(left_speed, right_speed)

        self.mMT.stop()
Exemplo n.º 15
0
    def follow_gyro(self,
                    kp,
                    ki,
                    kd,
                    speed,
                    target_angle=0,
                    sleep_time=0.01,
                    follow_for=follow_for_forever,
                    **kwargs):
        """
        PID line follower
        ``kp``, ``ki``, and ``kd`` are the PID constants.
        ``speed`` is the desired speed of the midpoint of the robot
        ``target_angle`` is the angle we want drive
        ``sleep_time`` is how many seconds we sleep on each pass through
            the loop.  This is to give the robot a chance to react
            to the new motor settings. This should be something small such
            as 0.01 (10ms).
        ``follow_for`` is called to determine if we should keep following the
            line or stop.  This function will be passed ``self`` (the current
            ``MoveWithGyroTank`` object). Current supported options are:
            - ``follow_for_forever``
            - ``follow_for_ms``
        ``**kwargs`` will be passed to the ``follow_for`` function
        Example:
        .. code:: python
            from ev3dev2.motor import OUTPUT_A, OUTPUT_B, MoveTank, SpeedPercent, follow_for_ms
            from ev3dev2.sensor.lego import GyroSensor
            tank = MoveTank(OUTPUT_A, OUTPUT_B)
            tank.gyro = GyroSensor()
            try:
                # Follow the line for 4500ms
                tank.calibrate_gyro()
                tank.follow_gyro(
                    kp=11.3, ki=0.05, kd=3.2,
                    speed=SpeedPercent(30),
                    follow_for=follow_for_ms,
                    ms=4500
                )
            except Exception:
                tank.stop()
                raise
        """
        assert self.gyro, "GyroSensor must be defined"

        integral = 0.0
        last_error = 0.0
        derivative = 0.0
        speed_native_units = speed.to_native_units(self.left_motor)
        MAX_SPEED = SpeedNativeUnits(self.max_speed)

        while follow_for(self, **kwargs):
            current_angle = self.gyro.angle
            error = current_angle - target_angle
            integral = integral + error
            derivative = error - last_error
            last_error = error
            turn_native_units = (kp * error) + (ki * integral) + (kd *
                                                                  derivative)

            left_speed = SpeedNativeUnits(speed_native_units -
                                          turn_native_units)
            right_speed = SpeedNativeUnits(speed_native_units +
                                           turn_native_units)

            if left_speed > MAX_SPEED:
                log.info("%s: left_speed %s is greater than MAX_SPEED %s" %
                         (self, left_speed, MAX_SPEED))
                self.stop()
                raise GyroFollowErrorTooFast(
                    "The robot is moving too fast to follow the angle")

            if right_speed > MAX_SPEED:
                log.info("%s: right_speed %s is greater than MAX_SPEED %s" %
                         (self, right_speed, MAX_SPEED))
                self.stop()
                raise GyroFollowErrorTooFast(
                    "The robot is moving too fast to follow the angle")

            if sleep_time:
                sleep(sleep_time)

            self.on(left_speed, right_speed)

        self.stop()
Exemplo n.º 16
0
    def follow_line(self,
                    kp,
                    ki,
                    kd,
                    side,
                    speed=SpeedPercent(50),
                    target_light_intensity=None,
                    follow_left_edge=True,
                    white=60,
                    off_line_count_max=20,
                    sleep_time=0.01,
                    follow_for=follow_for_forever,
                    **kwargs):

        target_light = self.sLS_left
        other_light = self.sLS_right

        if target_light_intensity is None:
            time.sleep(1)
            target_light_intensity = self.get_light_intensitiy(side)
            buffed = target_light_intensity + 2.5
            target_light_intensity_ls = other_light.reflected_light_intensity - 3

        integral = 0.0
        last_error = 0.0
        derivative = 0.0
        off_line_count = 0
        speed_native_units = -speed.to_native_units(self.motor_left)
        MAX_SPEED = SpeedNativeUnits(self.max_speed / 2)
        switch_locked = False

        while follow_for(self, **kwargs):
            if args.light_mode == 'ambient':
                target = target_light.ambient_light_intensity
                other = other_light.ambient_light_intensity
            else:
                target = target_light.reflected_light_intensity
                other = other_light.reflected_light_intensity

            print("{:.3f}->{:.3f} | {:.3f}->{:.3f} | {:.3f} <-> {:.3f} | {}".
                  format(target, target_light_intensity, other,
                         target_light_intensity_ls, target_light_intensity,
                         target_light_intensity_ls, follow_left_edge))
            if other < buffed and not switch_locked:
                follow_left_edge = False
                target_light = self.sLS_right
                other_light = self.sLS_left
                _tmp = target_light_intensity
                target_light_intensity = target_light_intensity_ls
                target_light_intensity_ls = _tmp
            else:
                follow_left_edge = True
                target_light = self.sLS_left
                other_light = self.sLS_right
            #if reflected_light_intensity > buffed*2 and follow_left_edge is False and reflected_light_intensity_ls > target_light_intensity_ls*2:
            #    follow_left_edge = True
            #    switch_locked = False

            error = target_light_intensity - target
            integral = integral + error
            derivative = error - last_error
            last_error = error
            turn_native_units = -((kp * error) + (ki * integral) +
                                  (kd * derivative))

            if not follow_left_edge:
                turn_native_units *= -1

            #if error < last_error:
            #    speed_native_units -= 2
            #elif error > last_error:
            #    speed_native_units += 5

            right_speed = SpeedNativeUnits(speed_native_units -
                                           turn_native_units)
            left_speed = SpeedNativeUnits(speed_native_units +
                                          turn_native_units)
            #print(turn_native_units, speed_native_units)

            # DEBUG
            #print('Error: %s' % error)
            #print('reflected_light_intesity: : %s' % reflected_light_intensity)
            #print('integral: %s' % integral)
            #print('derivative: %s' % derivative)
            #print('last_error: %s' % last_error)
            #print('turn_native_units: %s' % turn_native_units)
            #print('left_speed: %s' % left_speed)
            #print('right_speed: %s' % right_speed)

            if left_speed > MAX_SPEED:
                print("%s: left_speed %s is greater than MAX_SPEED %s" %
                      (self, left_speed, MAX_SPEED))
                self.mMT.stop()
                raise LineFollowErrorTooFast(
                    "The robot is moving too fast to follow the line")

            if right_speed > MAX_SPEED:
                print("%s: right_speed %s is greater than MAX_SPEED %s" %
                      (self, right_speed, MAX_SPEED))
                self.mMT.stop()
                raise LineFollowErrorTooFast(
                    "The robot is moving too fast to follow the line")

            # Have we lost the line?
            if target >= white:
                off_line_count += 1

                if off_line_count >= off_line_count_max:
                    #self.mMT.stop()
                    #raise LineFollowErrorLostLine("we lost the line")
                    pass
            else:
                off_line_count = 0

            if sleep_time:
                time.sleep(sleep_time)

            #self.mMT.on(left_speed, right_speed)

        self.mMT.stop()
Exemplo n.º 17
0
    def follow_line(self,
                    kp,
                    ki,
                    kd,
                    side,
                    speed,
                    target_light_intensity=None,
                    follow_left_edge=True,
                    white=60,
                    off_line_count_max=20,
                    sleep_time=0.01,
                    follow_for=follow_for_forever,
                    **kwargs):
        """
        PID line follower

        ``kp``, ``ki``, and ``kd`` are the PID constants.

        ``speed`` is the desired speed of the midpoint of the robot

        ``target_light_intensity`` is the reflected light intensity when the color sensor
            is on the edge of the line.  If this is None we assume that the color sensor
            is on the edge of the line and will take a reading to set this variable.

        ``follow_left_edge`` determines if we follow the left or right edge of the line

        ``white`` is the reflected_light_intensity that is used to determine if we have
            lost the line

        ``off_line_count_max`` is how many consecutive times through the loop the
            reflected_light_intensity must be greater than ``white`` before we
            declare the line lost and raise an exception

        ``sleep_time`` is how many seconds we sleep on each pass through
            the loop.  This is to give the robot a chance to react
            to the new motor settings. This should be something small such
            as 0.01 (10ms).

        ``follow_for`` is called to determine if we should keep following the
            line or stop.  This function will be passed ``self`` (the current
            ``MoveTank`` object). Current supported options are:
            - ``follow_for_forever``
            - ``follow_for_ms``

        ``**kwargs`` will be passed to the ``follow_for`` function

        Example:

        .. code:: python

            from ev3dev2.motor import OUTPUT_A, OUTPUT_B, MoveTank, SpeedPercent, follow_for_ms
            from ev3dev2.sensor.lego import ColorSensor

            tank = MoveTank(OUTPUT_A, OUTPUT_B)
            tank.cs = ColorSensor()

            try:
                # Follow the line for 4500ms
                tank.follow_line(
                    kp=11.3, ki=0.05, kd=3.2,
                    speed=SpeedPercent(30),
                    follow_for=follow_for_ms,
                    ms=4500
                )
            except Exception:
                tank.stop()
                raise
        """
        #assert self.cs, "ColorSensor must be defined"

        if target_light_intensity is None:
            target_light_intensity = self.get_light_intensitiy(side)

        integral = 0.0
        last_error = 0.0
        derivative = 0.0
        off_line_count = 0
        speed_native_units = speed.to_native_units(self.left_motor)
        MAX_SPEED = SpeedNativeUnits(self.max_speed)

        while follow_for(self, **kwargs):
            reflected_light_intensity = self.cs.reflected_light_intensity
            error = target_light_intensity - reflected_light_intensity
            integral = integral + error
            derivative = error - last_error
            last_error = error
            turn_native_units = (kp * error) + (ki * integral) + (kd *
                                                                  derivative)

            if not follow_left_edge:
                turn_native_units *= -1

            left_speed = SpeedNativeUnits(speed_native_units -
                                          turn_native_units)
            right_speed = SpeedNativeUnits(speed_native_units +
                                           turn_native_units)

            if left_speed > MAX_SPEED:
                print("%s: left_speed %s is greater than MAX_SPEED %s" %
                      (self, left_speed, MAX_SPEED))
                self.stop()
                raise LineFollowErrorTooFast(
                    "The robot is moving too fast to follow the line")

            if right_speed > MAX_SPEED:
                print("%s: right_speed %s is greater than MAX_SPEED %s" %
                      (self, right_speed, MAX_SPEED))
                self.stop()
                raise LineFollowErrorTooFast(
                    "The robot is moving too fast to follow the line")

            # Have we lost the line?
            if reflected_light_intensity >= white:
                off_line_count += 1

                if off_line_count >= off_line_count_max:
                    self.stop()
                    raise LineFollowErrorLostLine("we lost the line")
            else:
                off_line_count = 0

            if sleep_time:
                time.sleep(sleep_time)

            self.on(left_speed, right_speed)

        self.stop()