예제 #1
0
    hasFoundSpot = False
    straightLine = 0
    goRight=True
    bookTurns=5
    while not hasFoundSpot:
        currentColor = cl.value()

        if currentColor != C_BLACK and currentColor != C_NO_COLOR and currentColor != C_WHITE and currentColor == SPOT:
            hasFoundSpot = checkForSpot(SPOT)
            straightLine = 0

        elif hasBumpedBook() or isBookNearBy() or straightLine > 3000 or ts.value():
            if bookTurns <= 5:
                bookTurns = bookTurns + 1
                turnRight()
                RMC.on(-100)
                LMC.on(-100)
                sleep(1)
                turnLeft()
            else:
                if backUpThenTurn(SPOT):
                    hasFoundSpot = True

                straightLine = 0

        elif isOnBlackLineOrTable(currentColor):
            # Turn & go
            if backUpThenTurn(SPOT):
                hasFoundSpot = True

            straightLine = 0
예제 #2
0
            print("usDistCmVal = ", usDistCmVal, "  irDistVal = ", irDistVal,
                  "  irHeadVal = ", irHeadVal, "  compassVal = ", compassVal
                  )  # print all sensor vals, regardless of which changed
            prev_compassVal = compassVal
            # if beaconLock is False and we're outside the compass North range, reset cmpGenHeading to False
            if compassVal < (compassGoal - 40) or compassVal > (compassGoal +
                                                                40):
                cmpGenHeading = False

        if usDistCmVal < 50:
            print("Obstacle Detected! Forward motion stopped.")
            if spd > 0:
                spd = 0
            if pilot_mode < 0:
                # stop motors
                mL.on(0, brake=False)
                mR.on(0, brake=False)
                print("Auto-pilot collision avoidance - backing up")
                # backup at speed 5 with equal speed applied to left and right motors
                spd = -5
                # do so for 3 seconds
                mL.on(speed=spd, brake=False)
                mR.on_for_seconds(speed=spd,
                                  seconds=3,
                                  brake=False,
                                  block=True)
                # stop motors
                mL.on(0, brake=False)
                mR.on(0, brake=False)
                print("Auto-pilot collision avoidance - turning")
                spd = 5
예제 #3
0
m.reset()
time.sleep(0.1)
start_time = time.time()
m.stop_action = 'brake'
# m.ramp_up_sp(5000)     #### unsupported (on PiStorms only?)
# m._ramp_down_sp(5000)  #### unsupported (on PiStorms only?)

print("position_p =   ", m.position_p)  # powerup default is 7000
print("position_i =   ", m.position_i)  # powerup default is 0
print("position_d =   ", m.position_d)  # powerup default is 37500

print("speed_p =   ", m.speed_p)  # powerup default is 15000
print("speed_i =   ", m.speed_i)  # powerup default is 300
print("speed_d =   ", m.speed_d)  # powerup default is 7500

m.on(SpeedDPS(0))
t1 = time.time()

for i in range(0, 910, 10):
    # print("START --------> m.on...", round((time.time() - t1), 4))
    print(i, "   Increment SpeedDPS --------> m.on(SpeedDPS(i))  ",
          round((time.time() - t1), 4))
    m.on(SpeedDPS(i))
    #m.on_to_position(SpeedDPS(100), (i * 360), brake=False, block=True)  ### this method FAILS TO BLOCK
    #m.run_to_rel_pos(position_sp=(i * 360), speed_sp=600, stop_action="hold") ### no claim of blocking
    #m.on_for_degrees(SpeedDPS(900), (i * 360), brake=True, block=True)  ### this method FAILS TO BLOCK
    # m.on_for_seconds(speed=i, seconds=8, brake=False)
    # print("END --------> m.on...")
    # #time.sleep(2)
    # print("stop_action is  ", m.stop_action, round((time.time() - t1), 4))
    # print("state is  ", m.state, round((time.time() - t1), 4))
    print("Finding Next Spot...")
    SPOT = HOME
    if i == 2:
        SPOT = GOAL

    i = i - 1
    hasFoundSpot = False
    while not hasFoundSpot:
        currentColor = cl.value()

        if currentColor != C_BLACK and currentColor != C_NO_COLOR and currentColor != C_WHITE and currentColor == SPOT:
            # Found the spot!
            RMC.off()
            LMC.off()

            RMC.on(25 * POLARITY)
            LMC.on(25 * POLARITY)
            sleep(0.1)
            stopMotors()

            # Double Check Sensor
            idx = 10
            while idx > 0:
                currentColor = cl.value()
                sleep(0.1)
                if currentColor != SPOT:
                    idx = -2
                idx = idx - 1

            if idx != -3:
                nagHumans()
예제 #5
0
start_pos = 0
end_pos = 0
start_time = 0.0
end_time = 0.0

initial_power = b1.measured_voltage

mA = LargeMotor(OUTPUT_A)
mB = LargeMotor(OUTPUT_B)
time.sleep(0.1)
mA.reset()
time.sleep(0.1)
start_time = time.time()

print("starting motors")

while (True):
    print("ramping motors up")
    for i in range(0, 1001, 5):
        mA.on(SpeedDPS(i))
        mB.on(SpeedDPS(i))
        time.sleep(0.05)
    print("ramping motors down")
    for i in range(1000, 0, -5):
        mA.on(SpeedDPS(i))
        mB.on(SpeedDPS(i))
        time.sleep(0.05)
    print("finished full cycle:     ", time.time() - start_time)
    print("current votage:      ", (b1.measured_voltage / 1000000))
    print("votage drop since start:     ",
          ((initial_power - b1.measured_voltage) / 1000000))
class R3ptar:
    def __init__(self,
                 turn_motor_port: str = OUTPUT_A,
                 move_motor_port: str = OUTPUT_B,
                 scare_motor_port: str = OUTPUT_D,
                 touch_sensor_port: str = INPUT_1,
                 color_sensor_port: str = INPUT_3,
                 ir_sensor_port: str = INPUT_4,
                 ir_beacon_channel: int = 1):
        self.turn_motor = MediumMotor(address=turn_motor_port)
        self.move_motor = LargeMotor(address=move_motor_port)
        self.scare_motor = LargeMotor(address=scare_motor_port)

        self.touch_sensor = TouchSensor(address=touch_sensor_port)
        self.color_sensor = ColorSensor(address=color_sensor_port)

        self.ir_sensor = InfraredSensor(address=ir_sensor_port)
        self.ir_beacon_channel = ir_beacon_channel

        self.noise = Sound()

    def keep_driving_by_ir_beacon(self, speed: float = 100):
        while True:
            if self.ir_sensor.top_left(channel=self.ir_beacon_channel) and \
                    self.ir_sensor.top_right(channel=self.ir_beacon_channel):
                self.move_motor.on(speed=speed, brake=False, block=False)

            elif self.ir_sensor.bottom_left(channel=self.ir_beacon_channel) and \
                    self.ir_sensor.bottom_right(channel=self.ir_beacon_channel):
                self.move_motor.on(speed=-speed, brake=False, block=False)

            elif self.ir_sensor.top_left(channel=self.ir_beacon_channel):
                self.turn_motor.on(speed=-50, brake=False, block=False)

                self.move_motor.on(speed=speed, brake=False, block=False)

            elif self.ir_sensor.top_right(channel=self.ir_beacon_channel):
                self.turn_motor.on(speed=50, brake=False, block=False)

                self.move_motor.on(speed=speed, brake=False, block=False)

            elif self.ir_sensor.bottom_left(channel=self.ir_beacon_channel):
                self.turn_motor.on(speed=-50, brake=False, block=False)

                self.move_motor.on(speed=-speed, brake=False, block=False)

            elif self.ir_sensor.bottom_right(channel=self.ir_beacon_channel):
                self.turn_motor.on(speed=50, brake=False, block=False)

                self.move_motor.on(speed=-speed, brake=False, block=False)

            else:
                self.turn_motor.off(brake=True)

                self.move_motor.off(brake=False)

    def bite_by_ir_beacon(self, speed: float = 100):
        while True:
            if self.ir_sensor.beacon(channel=self.ir_beacon_channel):
                self.scare_motor.on_for_seconds(speed=speed,
                                                seconds=1,
                                                brake=True,
                                                block=False)

                self.noise.play_file(
                    wav_file='/home/robot/sound/Snake hiss.wav',
                    volume=100,
                    play_type=Sound.PLAY_NO_WAIT_FOR_COMPLETE)

                self.scare_motor.on_for_seconds(speed=-speed,
                                                seconds=1,
                                                brake=True,
                                                block=True)

                while self.ir_sensor.beacon(channel=self.ir_beacon_channel):
                    pass

    def run_away_if_chased(self):
        while True:
            if self.color_sensor.reflected_light_intensity > 30:
                self.move_motor.on_for_seconds(speed=50,
                                               seconds=4,
                                               brake=True,
                                               block=False)

                for i in range(2):
                    self.turn_motor.on_for_seconds(speed=50,
                                                   seconds=1,
                                                   brake=False,
                                                   block=True)

                    self.turn_motor.on_for_seconds(speed=-50,
                                                   seconds=1,
                                                   brake=False,
                                                   block=True)

    def bite_if_touched(self):
        while True:
            if self.touch_sensor.is_pressed:
                self.scare_motor.on_for_seconds(speed=100,
                                                seconds=1,
                                                brake=True,
                                                block=False)

                self.noise.play_file(
                    wav_file='/home/robot/sound/Snake hiss.wav',
                    volume=100,
                    play_type=Sound.PLAY_NO_WAIT_FOR_COMPLETE)

                self.scare_motor.on_for_seconds(speed=-10,
                                                seconds=10,
                                                brake=True,
                                                block=True)

    def main(self, speed: float = 100):
        Process(target=self.bite_by_ir_beacon, daemon=True).start()

        Process(target=self.bite_if_touched, daemon=True).start()

        Process(target=self.run_away_if_chased, daemon=True).start()

        self.keep_driving_by_ir_beacon(speed=speed)
예제 #7
0
sleep(1)
lm.on_for_rotations(50, 3)  # 매개 변수 이름을 명시하지 않아도 된다. 
sleep(1)
#endregion

#region 2.시간당 지정된 스피드로 rotations 바퀴만큼 회전 
lm.on_for_rotations(speed=SpeedDPS(500), rotations=3)   # DPS(degrees per second) 초당 500도를 도는 속도로 3바퀴 회전
sleep(1) 
lm.on_for_rotations(speed=SpeedRPS(1), rotations=3)     # RPS(rotations per second) 초당 1 바퀴를 도는 속도로 3바퀴 회전
sleep(1)
#endregion
#endregion

#region break, block
# break : True 인 경우 모터가 동작을 완료하면 모터를 고정위치에 붙잡는다.
# block : 현재 명령이 완료 될 때까지 프로그램 실행을 일시 중지
#endregion

#region 계속 회전하기 => on(speed, brake=True, block=False)
lm.on(speed=80, brake=False) # 정격 최고 속도의 45 %의 속도로 계속 회전
sleep(2)
lm.off()        # 정지
#endregion

#region Run a single motor until it stops moving
# # 그리퍼의 팔이 바닥까지 내려갈 때 어떤 각도 또는 시간동안 내려가야하는지 정확히 알 수 없다.
# # 이 명령은 일반적으로이 on() 명령 다음에 실행된다.
# # 움직이는 휠을 잡고 멈 추면 스크립트가 종료된다.
lm.on(speed=20)
lm.wait_until_not_moving()
#endregion
예제 #8
0
#!/usr/bin/env python3
from ev3dev2.motor import LargeMotor, OUTPUT_B

large_motor = LargeMotor(OUTPUT_B)

large_motor.on(speed=50)
large_motor.wait_until_not_moving()
예제 #9
0
#!/usr/bin/env python3

from time import sleep
from ev3dev2 import list_devices
from ev3dev2.port import LegoPort
from ev3dev2.motor import OUTPUT_A, LargeMotor, SpeedPercent
from ev3dev2.sensor import INPUT_1
from ev3dev2.sensor.lego import UltrasonicSensor

p1 = LegoPort(INPUT_1)
p1.mode = 'ev3-uart'
p1.set_device = 'lego-ev3-us'

sleep(0.5)

s = UltrasonicSensor(INPUT_1)
m = LargeMotor(OUTPUT_A)

print("Running motor...")

while True:
    dist = s.distance_centimeters
    if dist < 50:
        m.on(SpeedPercent(30))
    else:
        m.on(SpeedPercent(-30))

    sleep(0.05)
예제 #10
0
        LMC.on(leftSpeed)
        i = 0
        while light_intensity > 20 and i < ticks:
            i = i + 1
            sleep(0.005)
            light_intensity = cl.reflected_light_intensity
            if light_intensity < 20:
                LMC.off()
                RMC.off()
                leds.all_off()

while True:
    if (int(round(time.time() * 1000)) - start_time) > 20000:
        LMC.off()
        RMC.off()
        RMC.on(-50)
        LMC.on(-50)
        sleep(5)
        RMC.on(50)
        LMC.on(50)
        sleep(5)
        start_time = int(round(time.time() * 1000))

    light_intensity = cl.reflected_light_intensity
    if light_intensity > 20:
        # White Part of the Board 
        LMC.off()
        RMC.off()

        # This code attempts micro adjustments
        doTurn(25,-25,25,'LEFT')
예제 #11
0
        leds.set_color('LEFT', 'AMBER')
        leds.set_color('RIGHT', 'AMBER')

        client, clientInfo = s.accept()
        print ('Connected')
        leds.set_color('LEFT', 'GREEN')
        leds.set_color('RIGHT', 'GREEN')

        while True:
            data = client.recv(size)
            if data:
                #print(data, file=sys.stderr)
                cmd = Command.unpickled(data)

                if cmd:
                    leftMotor.on(speed=cmd.left_drive)
                    rightMotor.on(speed=cmd.right_drive)
                    do_kick = cmd.do_kick > 0
                    if do_kick != kicking:
                        kicking = do_kick
                        if do_kick:
                            kickMotor.run_to_abs_pos(position_sp=-100, speed_sp=kick_power*max_kick//screenh, stop_action="hold")
                            kick_power = kick_power - (25 if kick_power > 25 else kick_power)
                        else:
                            kickMotor.run_to_abs_pos(position_sp=-10, speed_sp=200, stop_action="coast")

                    kick_power = kick_power + (1 if kick_power < screenh else 0)
                    display.rectangle(x1=0, y1=0, x2=screenw, y2=kick_power)
                    display.update()

    except:
예제 #12
0
class AthenaRobot(object):
    # constructors for the robot with default parameters of wheel radius and ports
    def __init__(self,
                 wheelRadiusCm=2.75,
                 leftMotorPort=OUTPUT_C,
                 rightMotorPort=OUTPUT_B,
                 leftSensorPort=INPUT_4,
                 rightSensorPort=INPUT_1):
        #self is the current object, everything below for self are member variables
        self.wheelRadiusCm = wheelRadiusCm
        self.wheelCircumferenceCm = 2 * math.pi * wheelRadiusCm
        self.leftMotor = LargeMotor(leftMotorPort)
        self.rightMotor = LargeMotor(rightMotorPort)
        self.leftSensor = ColorSensor(leftSensorPort)
        self.rightSensor = ColorSensor(rightSensorPort)

    # run a distance in centimeters at speed of centimeters per second
    def run(self, distanceCm, speedCmPerSecond, brake=True, block=True):
        # Calculate degrees of distances and SpeedDegreePerSecond
        degreesToRun = distanceCm / self.wheelCircumferenceCm * 360
        speedDegreePerSecond = speedCmPerSecond / self.wheelCircumferenceCm * 360
        print("Degree: {0:.3f} Speed:{1:.3f} MaxSpeed {2}".format(
            degreesToRun, speedDegreePerSecond, self.leftMotor.max_speed),
              file=sys.stderr)
        # run motors based on the calculated results
        self.leftMotor.on_for_degrees(SpeedDPS(speedDegreePerSecond),
                                      degreesToRun, brake, False)
        self.rightMotor.on_for_degrees(SpeedDPS(speedDegreePerSecond),
                                       degreesToRun, brake, block)

    # turn a angle in degrees, positive means turn right and negative means turn left.
    def turn(self, degree, brake=True, block=True):
        # 1.9 is a scale factor from experiments
        degreesToRun = degree * 1.9
        # Turn at the speed of 20
        self.leftMotor.on_for_degrees(20, degreesToRun, brake, False)
        self.rightMotor.on_for_degrees(-20, degreesToRun, brake, block)

    # run until find a game line
    def onUntilGameLine(self,
                        consecutiveHit=5,
                        speed=10,
                        sleepTime=0.01,
                        white_threshold=85,
                        black_threshold=30,
                        brake=True):
        # Start motor at passed speed.
        self.leftMotor.on(speed)
        self.rightMotor.on(speed)

        # flags for whether both left and right wheel are in position
        leftLineSquaredWhite = False
        rightLineSquaredWhite = False
        leftConsecutiveWhite = 0
        rightConsecutiveWhite = 0

        # first aligned on white
        while (not leftLineSquaredWhite or not rightLineSquaredWhite):
            left_reflected = self.leftSensor.reflected_light_intensity
            right_reflected = self.rightSensor.reflected_light_intensity

            # left to detect white
            if (left_reflected > white_threshold):
                leftConsecutiveWhite += 1
            else:
                leftConsecutiveWhite = 0
                # reset to zero
            if (leftConsecutiveWhite >= consecutiveHit):
                self.leftMotor.off()
                leftLineSquaredWhite = True

            # right to detect white
            if (right_reflected > white_threshold):
                rightConsecutiveWhite += 1
            else:
                rightConsecutiveWhite = 0
                # reset to zero
            if (rightConsecutiveWhite >= consecutiveHit):
                self.rightMotor.off()
                rightLineSquaredWhite = True
            print(
                "left_reflected: {0:3d}, right_reflected: {1:3d}, leftConsecutiveWhite: {2:3d}, rightConsecutiveWhite: {3:3d}"
                .format(left_reflected, right_reflected, leftConsecutiveWhite,
                        rightConsecutiveWhite),
                file=sys.stderr)
            sleep(sleepTime)

        print("*********** White Line Reached *********", file=sys.stderr)

        leftLineSquaredBlack = False
        rightLineSquaredBlack = False
        leftConsecutiveBlack = 0
        rightConsecutiveBlack = 0

        # now try black
        self.leftMotor.on(speed)
        self.rightMotor.on(speed)
        while (not leftLineSquaredBlack or not rightLineSquaredBlack):
            left_reflected = self.leftSensor.reflected_light_intensity
            right_reflected = self.rightSensor.reflected_light_intensity

            # left to detect black
            if (left_reflected < black_threshold):
                leftConsecutiveBlack += 1
            else:
                leftConsecutiveBlack = 0
                # reset to zero
            if (leftConsecutiveBlack >= consecutiveHit):
                self.leftMotor.off()
                leftLineSquaredBlack = True

            # right to detect black
            if (right_reflected < black_threshold):
                rightConsecutiveBlack += 1
            else:
                rightConsecutiveBlack = 0
                # reset to zero
            if (rightConsecutiveBlack >= consecutiveHit):
                self.rightMotor.off()
                rightLineSquaredBlack = True
            print(
                "left_reflected: {0:3d}, right_reflected: {1:3d}, leftConsecutiveBlack: {2:3d}, rightConsecutiveBlack: {3:3d}"
                .format(left_reflected, right_reflected, leftConsecutiveBlack,
                        rightConsecutiveBlack),
                file=sys.stderr)
            sleep(sleepTime)

        self.leftMotor.off()
        self.rightMotor.off()

    #Go to the Bridge
    def goToBridge(self):
        # start from base, run 12.5 cm at 20cm/s
        self.run(12.5, 20)
        sleep(.2)
        # turn right 70 degree
        self.turn(70)
        sleep(.1)
        print("test", file=sys.stderr)
        # run 90 cm at speed of 30 cm/s
        self.run(90, 30, False)
        sleep(.1)
        # run until hit game line
        self.onUntilGameLine()
        sleep(.1)
        # move forward 2cm at 15cm/s
        self.run(2, 15)
        # turn left 90 degree
        self.turn(-90)
        # move forward 13 cm at 20cm/s
        self.run(13, 20)
        sleep(.1)
        # run until hit game line
        self.onUntilGameLine()
예제 #13
0
class Printer:
    colors = ('unknown', 'black', 'blue', 'green', 'yellow', 'red', 'white',
              'brown')

    def __init__(self, pixel_size):
        self._touch = TouchSensor(INPUT_1)
        self._color = ColorSensor(INPUT_4)
        self._color.mode = 'COL-COLOR'
        self._fb_motor = LargeMotor(OUTPUT_C)
        self._lr_motor = LargeMotor(OUTPUT_B)
        self._ud_motor = Motor(OUTPUT_A)

        self._x_res = utilities.MAX_X_RES / int(pixel_size)
        self._y_res = utilities.MAX_Y_RES / int(pixel_size)
        self._padding_left = utilities.MAX_PADDING_LEFT / int(pixel_size)
        self._padding_right = utilities.MAX_PADDING_RIGHT / int(pixel_size)
        self._is_pen_up = True
        self._pen_calibrated = False

        self._ud_ratio = 5
        self._fb_ratio = 4
        self._lr_ratio = 1
        self._pen_up_val = -3 * self._ud_ratio
        self._pen_down_val = -self._pen_up_val
        self._pen_up_down_speed = 10
        self._pen_left_speed = 20
        self._pen_right_speed = 20
        self._paper_scroll_speed = 20

        self._pixel_size = pixel_size
        self._p_codes = []
        self._current_line = 0

    def _pen_up(self, val):
        print("{} {}".format('PEN_UP', val))
        if val > 0:
            self._ud_motor.on_for_degrees(self._pen_up_down_speed,
                                          val * self._pen_up_val)
            self._is_pen_up = True

    def _pen_down(self, val):
        print("{} {}".format('PEN_DOWN', val))
        if val > 0:
            self._ud_motor.on_for_degrees(self._pen_up_down_speed,
                                          val * self._pen_down_val)
            self._is_pen_up = False

    def _pen_left(self, val):
        print("{} {}".format('PEN_LEFT', val))
        if val > 0:
            self._lr_motor.on_for_degrees(
                self._pen_left_speed,
                int(self._pixel_size) * val * self._lr_ratio)

    def _pen_right(self, val):
        print("{} {}".format('PEN_RIGHT', val))
        if val > 0:
            self._lr_motor.on_for_degrees(
                self._pen_right_speed,
                -int(self._pixel_size) * val * self._lr_ratio)

    def _paper_scroll(self, val):
        print("{} {}".format('SCROLL', val))
        if val > 0:
            if val == 1:
                self._current_line += val
                print("-------------- Line {} --------------".format(
                    self._current_line))
            self._fb_motor.on_for_degrees(
                self._paper_scroll_speed,
                int(self._pixel_size) * val * self._fb_ratio)

    def _finish_calibration(self):
        self._pen_calibrated = True

    def calibrate(self, quick_calibration):
        speaker = Sound()

        if quick_calibration:
            speaker.speak("Quick calibration")
            print("Quick calibration...")
        else:
            speaker.speak("Calibrating")
            print("Calibrating...")
            btn = Button()

            self._lr_motor.reset()
            self._ud_motor.reset()
            self._fb_motor.reset()

            self._lr_motor.on_for_degrees(
                self._pen_left_speed,
                self._x_res * self._pixel_size * self._lr_ratio)
            self._lr_motor.reset()

            self._ud_motor.on(-15)
            self._touch.wait_for_pressed()
            self._ud_motor.stop()
            time.sleep(1)
            self._ud_motor.on(15)
            self._touch.wait_for_released()
            self._ud_motor.on_for_degrees(10, 40)
            self._ud_motor.stop()
            time.sleep(1)

            speaker.speak(
                "Insert calibration paper and press the touch sensor")
            self._touch.wait_for_pressed()
            speaker.speak("Adjust pen height")
            print("Adjust pen height...")

            while not self._pen_calibrated:
                self._lr_motor.on_for_degrees(
                    self._pen_right_speed,
                    -100 * self._pixel_size * self._lr_ratio)
                self._lr_motor.on_for_degrees(
                    self._pen_left_speed,
                    100 * self._pixel_size * self._lr_ratio)
                time.sleep(1)
                if btn.up:
                    self._pen_up(1)
                elif btn.down:
                    self._pen_down(1)
                elif btn.right:
                    self._finish_calibration()
                elif btn.left:
                    self._pen_down(4)

            self._lr_motor.reset()

        if not self._is_pen_up:
            self._pen_up(1)
        self._pen_left(self._x_res)

        for _ in range(2):
            self._pen_right(self._x_res)
            self._pen_left(self._x_res)
        for _ in range(8):
            self._pen_right(self._padding_left)
            for _ in range(int(self._x_res)):
                self._pen_right(1)
            self._pen_left(self._x_res + self._padding_left)
        self._lr_motor.reset()

        speaker.speak(
            "Insert a blank piece of paper and press the touch sensor")
        self._touch.wait_for_pressed()
        self._fb_motor.on(5)
        val = 0
        print("Scrolling the piece of paper to its starting position...")
        while self.colors[val] == 'unknown':
            val = self._color.value()

        self._fb_motor.reset()
        print("Calibration done")

    def _interpret_p_codes(self, p_codes):
        btn = Button()
        speaker = Sound()
        self._current_line = 0
        abort = False

        print("---------- p_codes:----------")
        print("-------------- Line {} --------------".format(
            self._current_line))
        for x in p_codes:
            if btn.down:
                speaker.speak("Aborting")
                print("\nAborting...")
                abort = True
                break

            if x[0] == utilities.Command.PEN_UP:
                if not self._is_pen_up:
                    self._pen_up(x[1])

            elif x[0] == utilities.Command.PEN_DOWN:
                if self._is_pen_up:
                    self._pen_down(x[1])

            elif x[0] == utilities.Command.PEN_RIGHT:
                self._pen_right(x[1])

            elif x[0] == utilities.Command.PEN_LEFT:
                self._pen_left(x[1])

            elif x[0] == utilities.Command.SCROLL:
                self._paper_scroll(x[1])

        if not self._is_pen_up:
            self._pen_up(1)
        self._ud_motor.stop()

        return abort

    def draw(self, path=None, multicolor=False):
        speaker = Sound()

        if path is not None:
            if multicolor:
                speaker.speak("Printing multi color image")
                print("\nPrinting multi color image...")
            else:
                speaker.speak("Printing single color image")
                print("\nPrinting single color image...")

            binarized, img_x, img_y = utilities.binarize_image(
                path, self._x_res, self._y_res, multicolor)
        else:
            binarized, img_x, img_y = utilities.generate_and_binarize_test_image(
                self._pixel_size)
            speaker.speak("Printing test page")
            print("\nPrinting test page...")

        quick_calibration = False
        for layer, i in zip(binarized, range(1, utilities.NUM_OF_COLORS)):
            speaker.speak("Insert a {} pen and press the touch sensor".format(
                utilities.palette_names[i]))
            self._touch.wait_for_pressed()
            self.calibrate(quick_calibration)

            p_codes = utilities.binarized_image_to_p_codes(
                layer, img_x, img_y, self._padding_left)
            if self._interpret_p_codes(p_codes):
                break

            self._paper_scroll(self._y_res)
            self._fb_motor.reset()
            self._ud_motor.reset()
            self._lr_motor.reset()
            quick_calibration = True

        speaker = Sound()
        speaker.speak("Printing finished")
        print("Printing finished")
예제 #14
0
print("speed_d =   ", m.speed_d)  # powerup default is 7500

start_time = time.time()
""" ### quick test
m.position = 0
print(m.position) """

for j in range(50, 551, 10):
    m.speed_p = 15000
    m.speed_i = j
    m.speed_d = 7500
    tachospeed_min = 999999.99
    tachospeed_max = 0.0
    start_pos = 0
    start_time = time.time()
    m.on(SpeedDPS(goal_DPS))
    for i in range(100):
        t1 = time.time()
        old_pos = encoder_pos
        time.sleep(0.05)
        encoder_pos = m.position
        dt = time.time() - t1
        d_deg = encoder_pos - old_pos
        tachospeed = d_deg / dt
        d_deg_avg = ((d_deg_avg + d_deg) / (2))
        tachospeed_avg = ((tachospeed_avg + tachospeed) / (2))
        if tachospeed < tachospeed_min:
            tachospeed_min = tachospeed
        if tachospeed > tachospeed_max:
            tachospeed_max = tachospeed
        # if abs(d_deg) > 100:
예제 #15
0
#!/usr/bin/env python3

from time import sleep

from ev3dev2.motor import MediumMotor, LargeMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, SpeedPercent
from ev3dev2.sensor.lego import TouchSensor

touch_start_button = TouchSensor()
motor_conveyor = LargeMotor(OUTPUT_A)
motor_fan = LargeMotor(OUTPUT_B)
motor_water = MediumMotor(OUTPUT_C)

while True:
    touch_start_button.wait_for_pressed()
    motor_conveyor.on(SpeedPercent(8))
    sleep(1)
    motor_water.on_for_rotations(SpeedPercent(10), 0.5)
    sleep(1.5)
    motor_water.on_for_rotations(SpeedPercent(10), -0.5)
    sleep(1.5)
    motor_fan.on(SpeedPercent(100))
    motor_conveyor.on(SpeedPercent(3))
    sleep(4)
    motor_fan.off()
    motor_conveyor.off()
        # Make the robot turn so the compass reads the correct angle
        # Start turning clockwise very slowly.
        while True:
            compass_angle = compass.value()
            if degrees - 1 <= compass_angle <= degrees + 1:
                break
            # We also need to be careful when degrees is 0. A compass angle of 359 is super close,
            # and so we need to check this case separately
            elif degrees == 0 and compass_angle >= 359:
                break
            difference = compass_angle - degrees
            if difference > 180:
                difference = difference - 360
            elif difference < -180:
                difference = difference + 360
            # Now difference is in between -180 and 180.
            # If it's negative, we need to turn clockwise
            if difference < 0:
                # Motors are more powerful when difference is large
                m_l.on((difference - 20) / 5)
                m_r.on(-(difference - 20) / 5)
            else:
                # Motors are more powerful when difference is large
                m_l.on((difference + 20) / 5)
                m_r.on(-(difference + 20) / 5)
            wait_for_tick()
        # Go forwards
        m_l.on_for_seconds(50, distance / robot_speed, block=False)
        m_r.on_for_seconds(50, distance / robot_speed)
    x = x + 1
예제 #17
0
	# lift the rear part of the car
	lm_lifter.on_for_degrees(-100, lm_lifter.degrees)

	# stop drive motor
	lm_move.stop()
	mm_move.stop()
	# reset gyro sensor
	gy.mode = 'GYRO-RATE'
	gy.mode = 'GYRO-ANG'



log.info('prepare for the initial position')
# prepare for the initial position
# detect the upper position of the lifter
lm_lifter.on( -100, brake=True)
while( not ts.is_pressed ):
	sleep(0.05)
# approaching the initial position with high speed
lm_lifter.on_for_rotations(90, 7)
# nearly approached the initial position, approaching with lower speed
lm_lifter.on_for_degrees(20, 240)

# clear the lcd display
lcd.clear()

# show the steps
lcd.text_pixels( str(steps), True, 80, 50, font='courB18')
lcd.update()

log.info('wait user to supply the steps')
예제 #18
0
    if x == 32 or x == 120:  # space or x key pushed
        spd = 0
        turnRatio = 0
    if x == 119:  # w key pushed
        if spd < 90:  # limit max frwd speed to 90
            spd = spd + 5
    if x == 115:  # s key pushed
        if spd > -30:  # limit max rvrs speed to -30
            spd = spd - 5
    if x == 100:  # d key pushed (turn more to the Right)
        if turnRatio > -0.5:
            turnRatio = turnRatio - 0.1
    if x == 97:  # a key pushed (turn more to the Left)
        if turnRatio < 0.5:
            turnRatio = turnRatio + 0.1

    if turnRatio <= 0:
        mLspd = spd
        mRspd = spd * (1 + turnRatio)
    if turnRatio > 0:
        mRspd = spd
        mLspd = spd * (1 - turnRatio)

    mL.on(mLspd, brake=False)
    mR.on(mRspd, brake=False)
    if x == 120:  # x key means exit
        break

    print("x, spd, turnRatio, mLspd, mRspd  ", x, spd, turnRatio, mLspd, mRspd)
    time.sleep(.05)
예제 #19
0
class Balance:
    def __init__(self, motor, sensor, midPoint):
        self.motor = LargeMotor(motor)
        self.sensor = UltrasonicSensor(sensor)
        self.midPoint = midPoint
        self.motorPositionUp = self.motor.position - 20
        self.motorPositionDown = self.motor.position + 20
        self.integral = 0
        self.integralCount = 0

    def getSensorState(self):
        """
        Returns sensor measure based on an axis positioned on 
        the mid point
        """
        return -1 * (self.sensor.distance_centimeters - self.midPoint)

    def rotateAxis(self, speed):
        """
        Rotates axis on the tacho motor by speed value
        """
        # Limits rotation to limit object speed
        if self.motor.position >= self.motorPositionDown and speed > 0:
            self.motor.stop(stop_action="brake")
        elif self.motor.position <= self.motorPositionUp and speed < 0:
            self.motor.stop(stop_action="brake")
        else:
            #print(speed)
            self.motor.on(speed, block=False)

    def calculateSpeed(self, Kp=1, Kd=0, Ki=0, verbose=False):
        """
        Calculates speed in next cicle based on
        a PID control
        """
        initialMeasure = self.getSensorState()
        sleep(0.015)
        finalMeasure = self.getSensorState()

        # Fix closeness to the sensor
        if finalMeasure < -30:
            finalMeasure = 8.4

        speed = finalMeasure - initialMeasure

        if -3 < finalMeasure < 3 and (self.integral <= 10
                                      and self.integral >= -10
                                      and self.integralCount < 10):
            self.integral = self.integral + (finalMeasure)
            self.integralCount = self.integralCount + 1
        else:
            self.integral = 0
            self.integralCount = 0

        value = (Kp * finalMeasure) + (Kd * speed) + self.integral * Ki

        # Fix unbalanced values
        if value > 100:
            value = 100.0
        if value < -100:
            value = -100.0

        #print("\n-Distancia: %f, Velocidad %f, Integracion %f" % (finalMeasure, speed, self.integral))
        return value / 3.2
            print("toggled sample_mode (i); now set to...  ", sample_mode)

        if sample_mode > 0:
            try:
                # cycle through positions and take data samples
                for i in range(
                        30, 151,
                        15):  ### cycle through increasing distances from door
                    ## move BPDDbot to potision i
                    ### rotate to face SE wall
                    print("moving to position ", i,
                          "  ...rotating to face SE wall")
                    while compassVal < SEwalldeg - 1 or compassVal > SEwalldeg + 1:
                        compassVal = cmp.value(0)
                        #print("compasVal = ", compassVal)
                        mL.on(3, brake=False)
                    mL.on(0, brake=True)
                    time.sleep(.25)
                    print("compassVal =  ", compassVal)
                    usDistCmVal = us.distance_centimeters
                    print("usDistCmVal =  ", usDistCmVal)

                    ## drive to distance SEWALLDIST (40cm)
                    print("moving to position ", i,
                          "  ...driving to correct distance from SE wall")
                    while usDistCmVal < SEWALLDIST - 1 or usDistCmVal > SEWALLDIST + 1:
                        usDistCmVal = us.distance_centimeters
                        if usDistCmVal < SEWALLDIST - 1:
                            mL.on(-5, brake=False)
                            mR.on(-5, brake=False)
                        if usDistCmVal > SEWALLDIST + 1:
예제 #21
0
파일: art.py 프로젝트: artgl/zvezd
from ev3dev2.sensor.lego import GyroSensor

import time
from ev3dev2.sound import Sound
m1 = LargeMotor(OUTPUT_C)
m2 = LargeMotor(OUTPUT_D)
m3 = LargeMotor(OUTPUT_B)

us = UltrasonicSensor()
sound = Sound()

print(us.distance_centimeters, file=sys.stderr)


a_min = m3.position + 10
m3.on(-10, block=False)
while m3.position < a_min:
    a_min = m3.position
    time.sleep(0.1)
m3.off()
print("a_min", a_min, file=sys.stderr)

a_max = m3.position - 10
m3.on(10, block=False)
while m3.position > a_max:
    a_max = m3.position
    time.sleep(0.1)
m3.off()
print("a_max", a_max, file=sys.stderr)

예제 #22
0
from ev3dev2.motor import LargeMotor, SpeedPercent, OUTPUT_B, OUTPUT_C
# Importing the sleep() class from the time module
from time import sleep

# Moving the right large motor
# Set a variable for your left large motor, connected to port B
l_motor = LargeMotor(OUTPUT_B)

# Set a variable for your right large motor, connected to port C
r_motor = LargeMotor(OUTPUT_C)

# 1. Move the motor with on() and sleep() methods
#    a. turning it on at speed 70
#    b. telling the robot to wait 1 second
#    c. turning the robot off
l_motor.on(70)
sleep(1)
l_motor.off()

r_motor.on(70)
sleep(1)
r_motor.off()

# 2. Move the motors with the on_for_seconds() method
#    - Speed 70% for 1 second
r_motor.on_for_seconds(SpeedPercent(70), 1)
l_motor.on_for_seconds(SpeedPercent(70), 1)

# 3. Move the motors with the on_for_rotations() method
#    - Speed 70% for 2 wheel rotations
l_motor.on_for_rotations(SpeedPercent(70), 2)
예제 #23
0
class MindCuber(object):
    scan_order = [
        5, 9, 6, 3, 2, 1, 4, 7, 8, 23, 27, 24, 21, 20, 19, 22, 25, 26, 50, 54,
        51, 48, 47, 46, 49, 52, 53, 14, 10, 13, 16, 17, 18, 15, 12, 11, 41, 43,
        44, 45, 42, 39, 38, 37, 40, 32, 34, 35, 36, 33, 30, 29, 28, 31
    ]

    hold_cube_pos = 85
    rotate_speed = 400
    flip_speed = 300
    flip_speed_push = 400

    def __init__(self):
        self.shutdown = False
        self.flipper = LargeMotor(address=OUTPUT_A)
        self.turntable = LargeMotor(address=OUTPUT_B)
        self.colorarm = MediumMotor(address=OUTPUT_C)
        self.color_sensor = ColorSensor()
        self.color_sensor.mode = self.color_sensor.MODE_RGB_RAW
        self.infrared_sensor = InfraredSensor()
        self.init_motors()
        self.state = ['U', 'D', 'F', 'L', 'B', 'R']
        self.rgb_solver = None
        signal.signal(signal.SIGTERM, self.signal_term_handler)
        signal.signal(signal.SIGINT, self.signal_int_handler)

        filename_max_rgb = 'max_rgb.txt'

        if os.path.exists(filename_max_rgb):
            with open(filename_max_rgb, 'r') as fh:
                for line in fh:
                    (color, value) = line.strip().split()

                    if color == 'red':
                        self.color_sensor.red_max = int(value)
                        log.info("red max is %d" % self.color_sensor.red_max)
                    elif color == 'green':
                        self.color_sensor.green_max = int(value)
                        log.info("green max is %d" %
                                 self.color_sensor.green_max)
                    elif color == 'blue':
                        self.color_sensor.blue_max = int(value)
                        log.info("blue max is %d" % self.color_sensor.blue_max)

    def init_motors(self):

        for x in (self.flipper, self.turntable, self.colorarm):
            x.reset()

        log.info("Initialize flipper %s" % self.flipper)
        self.flipper.on(SpeedDPS(-50), block=True)
        self.flipper.off()
        self.flipper.reset()

        log.info("Initialize colorarm %s" % self.colorarm)
        self.colorarm.on(SpeedDPS(500), block=True)
        self.colorarm.off()
        self.colorarm.reset()

        log.info("Initialize turntable %s" % self.turntable)
        self.turntable.off()
        self.turntable.reset()

    def shutdown_robot(self):
        log.info('Shutting down')
        self.shutdown = True

        if self.rgb_solver:
            self.rgb_solver.shutdown = True

        for x in (self.flipper, self.turntable, self.colorarm):
            # We are shutting down so do not 'hold' the motors
            x.stop_action = 'brake'
            x.off(False)

    def signal_term_handler(self, signal, frame):
        log.error('Caught SIGTERM')
        self.shutdown_robot()

    def signal_int_handler(self, signal, frame):
        log.error('Caught SIGINT')
        self.shutdown_robot()

    def apply_transformation(self, transformation):
        self.state = [self.state[t] for t in transformation]

    def rotate_cube(self, direction, nb):
        current_pos = self.turntable.position
        final_pos = 135 * round(
            (self.turntable.position + (270 * direction * nb)) / 135.0)
        log.info(
            "rotate_cube() direction %s, nb %s, current_pos %d, final_pos %d" %
            (direction, nb, current_pos, final_pos))

        if self.flipper.position > 35:
            self.flipper_away()

        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed),
                                      final_pos)

        if nb >= 1:
            for i in range(nb):
                if direction > 0:
                    transformation = [0, 1, 5, 2, 3, 4]
                else:
                    transformation = [0, 1, 3, 4, 5, 2]
                self.apply_transformation(transformation)

    def rotate_cube_1(self):
        self.rotate_cube(1, 1)

    def rotate_cube_2(self):
        self.rotate_cube(1, 2)

    def rotate_cube_3(self):
        self.rotate_cube(-1, 1)

    def rotate_cube_blocked(self, direction, nb):

        # Move the arm down to hold the cube in place
        self.flipper_hold_cube()

        # OVERROTATE depends on lot on MindCuber.rotate_speed
        current_pos = self.turntable.position
        OVERROTATE = 18
        final_pos = int(135 * round(
            (current_pos + (270 * direction * nb)) / 135.0))
        temp_pos = int(final_pos + (OVERROTATE * direction))

        log.info(
            "rotate_cube_blocked() direction %s nb %s, current pos %s, temp pos %s, final pos %s"
            % (direction, nb, current_pos, temp_pos, final_pos))

        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed),
                                      temp_pos)
        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed / 4),
                                      final_pos)

    def rotate_cube_blocked_1(self):
        self.rotate_cube_blocked(1, 1)

    def rotate_cube_blocked_2(self):
        self.rotate_cube_blocked(1, 2)

    def rotate_cube_blocked_3(self):
        self.rotate_cube_blocked(-1, 1)

    def flipper_hold_cube(self, speed=300):
        current_position = self.flipper.position

        # Push it forward so the cube is always in the same position
        # when we start the flip
        if (current_position <= MindCuber.hold_cube_pos - 10
                or current_position >= MindCuber.hold_cube_pos + 10):

            self.flipper.ramp_down_sp = 400
            self.flipper.on_to_position(SpeedDPS(speed),
                                        MindCuber.hold_cube_pos)
            sleep(0.05)

    def flipper_away(self, speed=300):
        """
        Move the flipper arm out of the way
        """
        log.info("flipper_away()")
        self.flipper.ramp_down_sp = 400
        self.flipper.on_to_position(SpeedDPS(speed), 0)

    def flip(self):
        """
        Motors will sometimes stall if you call on_to_position() multiple
        times back to back on the same motor. To avoid this we call a 50ms
        sleep in flipper_hold_cube() and after each on_to_position() below.
        We have to sleep after the 2nd on_to_position() because sometimes
        flip() is called back to back.
        """
        log.info("flip()")

        if self.shutdown:
            return

        # Move the arm down to hold the cube in place
        self.flipper_hold_cube()

        # Grab the cube and pull back
        self.flipper.ramp_up_sp = 200
        self.flipper.ramp_down_sp = 0
        self.flipper.on_to_position(SpeedDPS(self.flip_speed), 190)
        sleep(0.05)

        # At this point the cube is at an angle, push it forward to
        # drop it back down in the turntable
        self.flipper.ramp_up_sp = 200
        self.flipper.ramp_down_sp = 400
        self.flipper.on_to_position(SpeedDPS(self.flip_speed_push),
                                    MindCuber.hold_cube_pos)
        sleep(0.05)

        transformation = [2, 4, 1, 3, 0, 5]
        self.apply_transformation(transformation)

    def colorarm_middle(self):
        log.info("colorarm_middle()")
        self.colorarm.on_to_position(SpeedDPS(600), -750)

    def colorarm_corner(self, square_index):
        """
        The lower the number the closer to the center
        """
        log.info("colorarm_corner(%d)" % square_index)
        position_target = -580

        if square_index == 1:
            position_target -= 10

        elif square_index == 3:
            position_target -= 30

        elif square_index == 5:
            position_target -= 20

        elif square_index == 7:
            pass

        else:
            raise ScanError(
                "colorarm_corner was given unsupported square_index %d" %
                square_index)

        self.colorarm.on_to_position(SpeedDPS(600), position_target)

    def colorarm_edge(self, square_index):
        """
        The lower the number the closer to the center
        """
        log.info("colorarm_edge(%d)" % square_index)
        position_target = -640

        if square_index == 2:
            position_target -= 20

        elif square_index == 4:
            position_target -= 40

        elif square_index == 6:
            position_target -= 20

        elif square_index == 8:
            pass

        else:
            raise ScanError(
                "colorarm_edge was given unsupported square_index %d" %
                square_index)

        self.colorarm.on_to_position(SpeedDPS(600), position_target)

    def colorarm_remove(self):
        log.info("colorarm_remove()")
        self.colorarm.on_to_position(SpeedDPS(600), 0)

    def colorarm_remove_halfway(self):
        log.info("colorarm_remove_halfway()")
        self.colorarm.on_to_position(SpeedDPS(600), -400)

    def scan_face(self, face_number):
        log.info("scan_face() %d/6" % face_number)

        if self.shutdown:
            return

        if self.flipper.position > 35:
            self.flipper_away(100)

        self.colorarm_middle()
        self.colors[int(MindCuber.scan_order[self.k])] = self.color_sensor.rgb

        self.k += 1
        i = 1
        target_pos = 115
        self.colorarm_corner(i)

        # The gear ratio is 3:1 so 1080 is one full rotation
        self.turntable.reset()
        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed),
                                      1080,
                                      block=False)
        self.turntable.wait_until('running')

        while True:

            # 135 is 1/8 of full rotation
            if self.turntable.position >= target_pos:
                current_color = self.color_sensor.rgb
                self.colors[int(MindCuber.scan_order[self.k])] = current_color

                i += 1
                self.k += 1

                if i == 9:
                    # Last face, move the color arm all the way out of the way
                    if face_number == 6:
                        self.colorarm_remove()

                    # Move the color arm far enough away so that the flipper
                    # arm doesn't hit it
                    else:
                        self.colorarm_remove_halfway()

                    break

                elif i % 2:
                    self.colorarm_corner(i)

                    if i == 1:
                        target_pos = 115
                    elif i == 3:
                        target_pos = 380
                    else:
                        target_pos = i * 135

                else:
                    self.colorarm_edge(i)

                    if i == 2:
                        target_pos = 220
                    elif i == 8:
                        target_pos = 1060
                    else:
                        target_pos = i * 135

            if self.shutdown:
                return

        if i < 9:
            raise ScanError('i is %d..should be 9' % i)

        self.turntable.wait_until_not_moving()
        self.turntable.off()
        self.turntable.reset()
        log.info("\n")

    def scan(self):
        log.info("scan()")
        self.colors = {}
        self.k = 0
        self.scan_face(1)

        self.flip()
        self.scan_face(2)

        self.flip()
        self.scan_face(3)

        self.rotate_cube(-1, 1)
        self.flip()
        self.scan_face(4)

        self.rotate_cube(1, 1)
        self.flip()
        self.scan_face(5)

        self.flip()
        self.scan_face(6)

        if self.shutdown:
            return

        log.info("RGB json:\n%s\n" % json.dumps(self.colors))
        self.rgb_solver = RubiksColorSolverGeneric(3)
        self.rgb_solver.enter_scan_data(self.colors)
        self.rgb_solver.crunch_colors()
        self.cube_kociemba = self.rgb_solver.cube_for_kociemba_strict()
        log.info("Final Colors (kociemba): %s" % ''.join(self.cube_kociemba))

        # This is only used if you want to rotate the cube so U is on top, F is
        # in the front, etc. You would do this if you were troubleshooting color
        # detection and you want to pause to compare the color pattern on the
        # cube vs. what we think the color pattern is.
        '''
        log.info("Position the cube so that U is on top, F is in the front, etc...to make debugging easier")
        self.rotate_cube(-1, 1)
        self.flip()
        self.flipper_away()
        self.rotate_cube(1, 1)
        input('Paused')
        '''

    def move(self, face_down):
        log.info("move() face_down %s" % face_down)

        position = self.state.index(face_down)
        actions = {
            0: ["flip", "flip"],
            1: [],
            2: ["rotate_cube_2", "flip"],
            3: ["rotate_cube_1", "flip"],
            4: ["flip"],
            5: ["rotate_cube_3", "flip"]
        }.get(position, None)

        for a in actions:

            if self.shutdown:
                break

            getattr(self, a)()

    def run_kociemba_actions(self, actions):
        log.info('Action (kociemba): %s' % ' '.join(actions))
        total_actions = len(actions)

        for (i, a) in enumerate(actions):

            if self.shutdown:
                break

            if a.endswith("'"):
                face_down = list(a)[0]
                rotation_dir = 1
            elif a.endswith("2"):
                face_down = list(a)[0]
                rotation_dir = 2
            else:
                face_down = a
                rotation_dir = 3

            log.info("Move %d/%d: %s%s (a %s)" %
                     (i, total_actions, face_down, rotation_dir, pformat(a)))
            self.move(face_down)

            if rotation_dir == 1:
                self.rotate_cube_blocked_1()
            elif rotation_dir == 2:
                self.rotate_cube_blocked_2()
            elif rotation_dir == 3:
                self.rotate_cube_blocked_3()
            log.info("\n")

    def resolve(self):

        if self.shutdown:
            return

        cmd = ['kociemba', ''.join(map(str, self.cube_kociemba))]
        output = check_output(cmd).decode('ascii')

        if 'ERROR' in output:
            msg = "'%s' returned the following error\n%s\n" % (' '.join(cmd),
                                                               output)
            log.error(msg)
            print(msg)
            sys.exit(1)

        actions = output.strip().split()
        self.run_kociemba_actions(actions)
        self.cube_done()

    def cube_done(self):
        self.flipper_away()

    def wait_for_cube_insert(self):
        rubiks_present = 0
        rubiks_present_target = 10
        log.info('wait for cube...to be inserted')

        while True:

            if self.shutdown:
                break

            dist = self.infrared_sensor.proximity

            # It is odd but sometimes when the cube is inserted
            # the IR sensor returns a value of 100...most of the
            # time it is just a value less than 50
            if dist < 50 or dist == 100:
                rubiks_present += 1
                log.info("wait for cube...distance %d, present for %d/%d" %
                         (dist, rubiks_present, rubiks_present_target))
            else:
                if rubiks_present:
                    log.info('wait for cube...cube removed (%d)' % dist)
                rubiks_present = 0

            if rubiks_present >= rubiks_present_target:
                log.info('wait for cube...cube found and stable')
                break

            time.sleep(0.1)
예제 #24
0
class Dinor3x:
    FAST_WALK_SPEED = 80
    NORMAL_WALK_SPEED = 40
    SLOW_WALK_SPEED = 20

    def __init__(self,
                 jaw_motor_port: str = OUTPUT_A,
                 left_motor_port: str = OUTPUT_B,
                 right_motor_port: str = OUTPUT_C,
                 touch_sensor_port: str = INPUT_1,
                 color_sensor_port: str = INPUT_3,
                 ir_sensor_port: str = INPUT_4,
                 ir_beacon_channel: int = 1):
        self.jaw_motor = MediumMotor(address=jaw_motor_port)

        self.left_motor = LargeMotor(address=left_motor_port)
        self.right_motor = LargeMotor(address=right_motor_port)
        self.tank_driver = MoveTank(left_motor_port=left_motor_port,
                                    right_motor_port=right_motor_port,
                                    motor_class=LargeMotor)
        self.steer_driver = MoveSteering(left_motor_port=left_motor_port,
                                         right_motor_port=right_motor_port,
                                         motor_class=LargeMotor)

        self.touch_sensor = TouchSensor(address=touch_sensor_port)
        self.color_sensor = ColorSensor(address=color_sensor_port)

        self.ir_sensor = InfraredSensor(address=ir_sensor_port)
        self.ir_beacon_channel = ir_beacon_channel

        self.speaker = Sound()

        self.roaring = False
        self.walk_speed = self.NORMAL_WALK_SPEED

    def roar_by_ir_beacon(self):
        """
        Dinor3x roars when the Beacon button is pressed
        """
        if self.ir_sensor.beacon(channel=self.ir_beacon_channel):
            self.roaring = True
            self.open_mouth()
            self.roar()

        elif self.roaring:
            self.roaring = False
            self.close_mouth()

    def change_speed_by_color(self):
        """
        Dinor3x changes its speed when detecting some colors
        - Red: walk fast
        - Green: walk normally
        - White: walk slowly
        """
        if self.color_sensor.color == ColorSensor.COLOR_RED:
            self.speaker.speak(text='RUN!',
                               volume=100,
                               play_type=Sound.PLAY_NO_WAIT_FOR_COMPLETE)
            self.walk_speed = self.FAST_WALK_SPEED
            self.walk(speed=self.walk_speed)

        elif self.color_sensor.color == ColorSensor.COLOR_GREEN:
            self.speaker.speak(text='Normal',
                               volume=100,
                               play_type=Sound.PLAY_NO_WAIT_FOR_COMPLETE)
            self.walk_speed = self.NORMAL_WALK_SPEED
            self.walk(speed=self.walk_speed)

        elif self.color_sensor.color == ColorSensor.COLOR_WHITE:
            self.speaker.speak(text='slow...',
                               volume=100,
                               play_type=Sound.PLAY_NO_WAIT_FOR_COMPLETE)
            self.walk_speed = self.SLOW_WALK_SPEED
            self.walk(speed=self.walk_speed)

    def walk_by_ir_beacon(self):
        """
        Dinor3x walks or turns according to instructions from the IR Beacon
        - 2 top/up buttons together: walk forward
        - 2 bottom/down buttons together: walk backward
        - Top Left / Red Up: turn left on the spot
        - Top Right / Blue Up: turn right on the spot
        - Bottom Left / Red Down: stop
        - Bottom Right / Blue Down: calibrate to make the legs straight
        """

        # forward
        if self.ir_sensor.top_left(channel=self.ir_beacon_channel) and \
                self.ir_sensor.top_right:
            self.walk(speed=self.walk_speed)

        # backward
        elif self.ir_sensor.bottom_left(channel=self.ir_beacon_channel) and \
                self.ir_sensor.bottom_right(channel=self.ir_beacon_channel):
            self.walk(speed=-self.walk_speed)

        # turn left on the spot
        elif self.ir_sensor.top_left(channel=self.ir_beacon_channel):
            self.turn(speed=self.walk_speed)

        # turn right on the spot
        elif self.ir_sensor.top_right(channel=self.ir_beacon_channel):
            self.turn(speed=-self.walk_speed)

        # stop
        elif self.ir_sensor.bottom_left(channel=self.ir_beacon_channel):
            self.tank_driver.off(brake=True)

        # calibrate legs
        elif self.ir_sensor.bottom_right(channel=self.ir_beacon_channel):
            self.calibrate_legs()

    def calibrate_legs(self):
        self.tank_driver.on(left_speed=10, right_speed=20)

        self.touch_sensor.wait_for_released()

        self.tank_driver.off(brake=True)

        self.left_motor.on(speed=40)

        self.touch_sensor.wait_for_pressed()

        self.left_motor.off(brake=True)

        self.left_motor.on_for_rotations(rotations=-0.2,
                                         speed=50,
                                         brake=True,
                                         block=True)

        self.right_motor.on(speed=40)

        self.touch_sensor.wait_for_pressed()

        self.right_motor.off(brake=True)

        self.right_motor.on_for_rotations(rotations=-0.2,
                                          speed=50,
                                          brake=True,
                                          block=True)

        self.left_motor.reset()
        self.right_motor.reset()

    def walk(self, speed: float = 100):
        self.calibrate_legs()

        self.steer_driver.on(steering=0, speed=-speed)

    def turn(self, speed: float = 100):
        self.calibrate_legs()

        if speed >= 0:
            self.left_motor.on_for_degrees(degrees=180,
                                           speed=speed,
                                           brake=True,
                                           block=True)

        else:
            self.right_motor.on_for_degrees(degrees=180,
                                            speed=-speed,
                                            brake=True,
                                            block=True)

        self.tank_driver.on(left_speed=speed, right_speed=-speed)

    def close_mouth(self):
        self.jaw_motor.on_for_seconds(speed=-20,
                                      seconds=1,
                                      brake=False,
                                      block=False)

    def open_mouth(self):
        self.jaw_motor.on_for_seconds(speed=20,
                                      seconds=1,
                                      block=False,
                                      brake=False)

    def roar(self):
        self.speaker.play_file(wav_file='T-rex roar.wav',
                               volume=100,
                               play_type=Sound.PLAY_NO_WAIT_FOR_COMPLETE)

        self.jaw_motor.on_for_degrees(speed=40,
                                      degrees=-60,
                                      block=True,
                                      brake=True)

        for i in range(12):
            self.jaw_motor.on_for_seconds(speed=-40,
                                          seconds=0.05,
                                          block=True,
                                          brake=True)

            self.jaw_motor.on_for_seconds(speed=40,
                                          seconds=0.05,
                                          block=True,
                                          brake=True)

        self.jaw_motor.on_for_seconds(speed=20,
                                      seconds=0.5,
                                      brake=False,
                                      block=True)

    def main(self):
        self.close_mouth()

        while True:
            self.roar_by_ir_beacon()
            self.change_speed_by_color()
            self.walk_by_ir_beacon()
class Spik3r:
    def __init__(self,
                 sting_motor_port: str = OUTPUT_D,
                 go_motor_port: str = OUTPUT_B,
                 claw_motor_port: str = OUTPUT_A,
                 touch_sensor_port: str = INPUT_1,
                 color_sensor_port: str = INPUT_3,
                 ir_sensor_port: str = INPUT_4,
                 ir_beacon_channel: int = 1):
        self.sting_motor = LargeMotor(address=sting_motor_port)
        self.go_motor = LargeMotor(address=go_motor_port)
        self.claw_motor = MediumMotor(address=claw_motor_port)

        self.ir_sensor = InfraredSensor(address=ir_sensor_port)
        self.ir_beacon_channel = ir_beacon_channel

        self.touch_sensor = TouchSensor(address=touch_sensor_port)
        self.color_sensor = ColorSensor(address=color_sensor_port)

        self.dis = Display()
        self.speaker = Sound()

    def sting_by_ir_beacon(self):
        while True:
            if self.ir_sensor.beacon(channel=self.ir_beacon_channel):
                self.sting_motor.on_for_degrees(speed=-75,
                                                degrees=220,
                                                brake=True,
                                                block=False)

                self.speaker.play_file(wav_file='/home/robot/sound/Blip 1.wav',
                                       volume=100,
                                       play_type=Sound.PLAY_WAIT_FOR_COMPLETE)

                self.sting_motor.on_for_seconds(speed=-100,
                                                seconds=1,
                                                brake=True,
                                                block=True)

                self.sting_motor.on_for_seconds(speed=100,
                                                seconds=1,
                                                brake=True,
                                                block=True)

            while self.ir_sensor.beacon(channel=self.ir_beacon_channel):
                pass

    def be_noisy_to_people(self):
        while True:
            if self.color_sensor.reflected_light_intensity > 30:
                for i in range(4):
                    self.speaker.play_file(
                        wav_file='/home/robot/sound/Blip 2.wav',
                        volume=100,
                        play_type=Sound.PLAY_WAIT_FOR_COMPLETE)

    def pinch_if_touched(self):
        while True:
            if self.touch_sensor.is_pressed:
                self.claw_motor.on_for_seconds(speed=50,
                                               seconds=1,
                                               brake=True,
                                               block=True)

                self.claw_motor.on_for_seconds(speed=-50,
                                               seconds=0.3,
                                               brake=True,
                                               block=True)

    def keep_driving_by_ir_beacon(self):
        while True:
            if self.ir_sensor.top_left(channel=self.ir_beacon_channel) and \
                    self.ir_sensor.top_right(channel=self.ir_beacon_channel):
                self.go_motor.on(speed=91, block=False, brake=False)

            elif self.ir_sensor.top_right(channel=self.ir_beacon_channel):
                self.go_motor.on(speed=-100, brake=False, block=False)

            else:
                self.go_motor.off(brake=True)

    def main(self):
        self.dis.image_filename(filename='/home/robot/image/Evil.bmp',
                                clear_screen=True)
        self.dis.update()

        # FIXME: .sting_by_ir_beacon stops responding after a while
        Process(target=self.be_noisy_to_people, daemon=True).start()

        Process(target=self.sting_by_ir_beacon, daemon=True).start()

        Process(target=self.pinch_if_touched, daemon=True).start()

        self.keep_driving_by_ir_beacon()
예제 #26
0
class MindstormsGadget(AlexaGadget):
    """
    A Mindstorms gadget that performs movement based on voice commands.
    
    """

    def __init__(self):
        """
        Performs Alexa Gadget initialization routines and ev3dev resource allocation.
        """
        super().__init__()
        # Ev3dev initialization
        self.leds = Leds()
        self.sound = Sound()
        self.drive = LargeMotor(OUTPUT_B)
        self.dealmotor = MediumMotor(OUTPUT_A)
        self.bcolor = ColorSensor(INPUT_1)
        self.pushsensor = TouchSensor(INPUT_2)
        self.leftmargin = 0
        self.rigtmargin = 0
        self._init_reset()
    

    def _init_reset(self):
        self.numCards = 2
        self.numPlayers = 0
        self.game = 'blackjack'
        self.degreeStep = 180
        self.players = ["red","yellow"] #Default player
        self._send_event(EventName.SPEECH, {'speechOut': "Restart game"})


    def on_connected(self, device_addr):
        """
        Gadget connected to the paired Echo device.
        :param device_addr: the address of the device we connected to
        """
        self.leds.set_color("LEFT", "GREEN")
        self.leds.set_color("RIGHT", "GREEN")
        logger.info("{} connected to Echo device".format(self.friendly_name))

    def on_disconnected(self, device_addr):
        """
        Gadget disconnected from the paired Echo device.
        :param device_addr: the address of the device we disconnected from
        """
        self.leds.set_color("LEFT", "BLACK")
        self.leds.set_color("RIGHT", "BLACK")
        logger.info("{} disconnected from Echo device".format(self.friendly_name))

    def on_custom_mindstorms_gadget_control(self, directive):
        """
        Handles the Custom.Mindstorms.Gadget control directive.
        :param directive: the custom directive with the matching namespace and name
        """
        try:
            payload = json.loads(directive.payload.decode("utf-8"))
            print("Control payload: {}".format(payload), file=sys.stderr)
            control_type = payload["type"]
            if control_type == "move":
                # Expected params: [direction, duration, speed]
                self._move(payload["direction"], int(payload["duration"]), int(payload["speed"]))

            if control_type == "command":
                # Expected params: [command]
                self._activate(payload["command"])
            
            if control_type == "dealcard":
                # Expected params: [command] = Number of Cards
                # Expected params: [player]
                num = payload["command"]
                player = payload["player"]
                speak = "Give "+ num + " card to " + player
                if player == "all":
                    if (self.numPlayers == 0):
                        self.numPlayers = 2
                    for i in  range(int(num)):
                        for j in range(self.numPlayers):
                           self._dealcard(1,j)                                   
                else:
                    try:
                        num = self.players.index(player) 
                        self._dealcard(int(payload["command"]),num)
                    except ValueError:
                        speak = "There is no user " + player 
                print (speak,file=sys.stderr)   
                self._send_event(EventName.SPEECH, {'speechOut': speak})
        except KeyError:
            print("Missing expected parameters: {}".format(directive), file=sys.stderr)
 

    def _dealcard(self, num, player):
        """
        Deal  number of cards to player
        """
        if num < 1:
            num = 1
        degree = self._calcDegree(player)
        print("Give player : {} card : {}  Move angle : {}".format(player, num,degree), file=sys.stderr)
        self.drive.on_to_position(SpeedPercent(10),degree) 
        self.drive.wait_until_not_moving()  
        for i in range(num):
            self.dealmotor.on_for_degrees(SpeedPercent(-100), 340)
            self.dealmotor.wait_until_not_moving()
            time.sleep(1)
            self.dealmotor.on_for_degrees(SpeedPercent(100), 270)
            self.dealmotor.wait_until_not_moving()
            time.sleep(1)
 
    def _calcDegree (self,player):
        degree = (player*self.degreeStep)+self.leftmargin
        return degree

    def _gameinit(self,game):
        """
        Check and start game
        """
        if (self.numPlayers == 0):
            self.numPlayers = 2
        if game == "poker":
            self.numCards = 5
        if game == "blackjack":
            self.numCards = 2
        if game == "rummy":
            self.numCards = 7
            if (self.numPlayers == 2):
                self.numCards = 10
        speak = ""
        for i in range(self.numPlayers):
            print("Player : {}  Color : {}".format(i,self.players[i]), file=sys.stderr)
            speak = speak + self.players[i]
  
        speak = "Start " + game + "with " + str(self.numPlayers) + "player " + speak
        self._send_event(EventName.SPEECH, {'speechOut': speak})


        self._findboundary()    
        self.drive.on_to_position(SpeedPercent(10),self.leftmargin)    
        time.sleep(1)
        print("Game : {}  Number of Card : {}".format(game,self.numCards), file=sys.stderr)
        for i in  range(self.numCards):
            for j in range(self.numPlayers):
                self._dealcard(1,j)
       
            
    def _findboundary (self):
        "Move to left until sensor pressed "
        self.drive.on(SpeedPercent(10))
        self.pushsensor.wait_for_pressed ()
        self.drive.stop()
        "Get position"
        self.rightmargin = self.drive.position
        print("Right position  : {}  ".format(self.rightmargin), file=sys.stderr)
        self.drive.on(SpeedPercent(-10))
        time.sleep(1)
        self.pushsensor.wait_for_pressed ()
        self.drive.stop()
        "Get position + offset 45 for not to close limitation"
        self.leftmargin = self.drive.position
        self.leftmargin = self.leftmargin + 60 
        print("Left position  : {}  ".format(self.leftmargin), file=sys.stderr)
        self.degreeStep = int(abs((self.leftmargin - self.rightmargin)/self.numPlayers))
        print("Degree steps  : {}  ".format(self.degreeStep), file=sys.stderr)
      
    def _addUser (self):
        if self.numPlayers == 0:
            self.players.clear()
        player = self.bcolor.color_name
        self.players.append(player.lower())
        print("Player {} color: {}".format(self.players[self.numPlayers],player), file=sys.stderr)
        self.numPlayers  += 1
        self._send_event(EventName.PLAYER, {'player': player})


    def _move(self, direction, duration: int, speed: int, is_blocking=False):
        """
        Handles move commands from the directive.
        Right and left movement can under or over turn depending on the surface type.
        :param direction: the move direction
        :param duration: the duration in seconds
        :param speed: the speed percentage as an integer
        :param is_blocking: if set, motor run until duration expired before accepting another command
        """
        print("Move command: ({}, {}, {}, {})".format(direction, speed, duration, is_blocking), file=sys.stderr)
        if direction in Direction.FORWARD.value:
            self.drive.on_for_degrees(SpeedPercent(10),90)

        if direction in Direction.BACKWARD.value:
            self.drive.on_for_degrees(SpeedPercent(-10),90)
        if direction in Direction.STOP.value:
            self.drive.off()
    def _send_event(self, name: EventName, payload):
        """
        Sends a custom event to trigger a sentry action.
        :param name: the name of the custom event
        :param payload: the sentry JSON payload
        """
        self.send_custom_event('Custom.Mindstorms.Gadget', name.value, payload)


    def _activate(self, command, speed=50):
        """
        Handles preset commands.
        :param command: the preset command
        :param speed: the speed if applicable
        """
        print("Activate command: ({}, {})".format(command, speed), file=sys.stderr)
        if command in Command.GAMES.value:
            self.game = command
            print("Play game: {}".format(self.game), file=sys.stderr)
            self._gameinit(self.game)

        if command in Command.RESET_GAME.value:
            # Reset game
            self._init_reset()

        if command in Command.ADD_CMD.value:
            self._addUser()
time.sleep(3)

start_pos = 0
target_end_pos = 0
start_time = 0.0
end_time = 0.0
target_speedDPS = 900
adjusted_speedDPS = 0

m = LargeMotor(OUTPUT_A)
time.sleep(0.1)
m.reset()
time.sleep(0.1)
start_time = time.time()

m.on(SpeedDPS(0))
t1 = time.time()
""" 
Notes:
 - LPF technique needs to be more generalized than it is currently (v0.1, 3/1/2020)
   - needs calculation that takes actual acceleration/decceleration, in DPS, into consideration
   - current implementation ramps up from '0' DPS to target_speedDPS and back down to '0'
   - need to alter to change from current DPS to new DSP (not assume starting at '0')
   - current implementation ramps up/down based on static time duration, rather than constant accel/decel rate


Possible implementation based on  ---> y = (m * x) + b

---- y = new adjusted_speedDPS
---- m (slope) = ramp_rateDPS
---- x delta_t (change in time - measured in seconds)
            polarCoordscmpMean = np.array([], dtype=np.int32)
            print("r pushed - reinitialized polarCoords* arrays")

        if x == 105: # i pushed - toggle sample mode on and off
            sample_mode *= -1
            print("toggled sample_mode (i); now set to...  ", sample_mode)
        
        if sample_mode > 0:
            try:
                # rototate to cmp angle and take data samples
                for i in range(360):
                    ## move motor to new cmps angle
                    while compassVal < i - 1 or compassVal > i + 1:
                        compassVal = cmp.value(0)
                        print("compasVal = ", compassVal)
                        mL.on(1, brake=False)
                    mL.on(0, brake=True)
                    time.sleep(2)   # pause to let the shaking stop before collecting data
                    # init the data collection arrays for each angle/collection series
                    polarCoordsUSr = np.array([], dtype=np.int32)
                    polarCoordscmpDeg = np.array([], dtype=np.int32)
                    # take 100 samples
                    for j in range(100):
                        usDistCmVal = us.distance_centimeters
                        compassVal = cmp.value(0)
                        polarCoordsUSr = np.append(polarCoordsUSr, usDistCmVal)
                        polarCoordscmpDeg = np.append(polarCoordscmpDeg, compassVal)
                    print("")
                    print ("polarCoordsUSr.size = ", polarCoordsUSr.size)
                    print("min      max      mean      std")
                    print(np.min(polarCoordsUSr), np.max(polarCoordsUSr), np.mean(polarCoordsUSr), np.std(polarCoordsUSr))
예제 #29
0
while not halt:

# Read the Gyro and calulate error
gyroError = targetAngle - gyro.angle
print(gyroError)

# Calulate the differential between motor speeds
if abs(gyroError) < 2.5:
differential = 0
else:
differential = 2 * gyroError
# Make sure the differentialis are not too wild
# If you want the robot to spin then max(differential) >= 2 * forwardSpeed
differential = min(max(differential, -60), 60)

# Calculate the motor speeds
lmSpeed = forwardSpeed + differential / 2
rmSpeed = forwardSpeed - differential / 2

# Make sure the motor speeds are not too wild
lmSpeed = min(max(lmSpeed, -50), 50)
rmSpeed = min(max(rmSpeed, -50), 50)

# Set motor speeds for this iteration of the loop
# motor.on(speed) turn the motor on for ever, so don't forget to stop
leftMotor.on(lmSpeed)
rightMotor.on(rmSpeed)
print(lmSpeed, ', ', rmSpeed)

# Small delay to help read screen print, too slow and the robot motion will be jerky
sleep(0.2)
#!/usr/bin/env micropython

from ev3dev2.motor import LargeMotor
from ev3dev2.sensor.lego import ColorSensor
from ev3dev2.button import Button

btn = Button()

ma = LargeMotor('outA')
mb = LargeMotor('outD')

cl = ColorSensor()
cl.mode='COL-AMBIENT'
while True:
    if btn.any():
        break

    ma.on(speed=10)
    mb.on(speed=10)
    
    print(cl.value())

ma.off()
mb.off()
예제 #31
0
class Robot:
    # Import stuff
    from ev3dev2.motor import MoveTank, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, LargeMotor
    from ev3dev2.sensor.lego import ColorSensor, GyroSensor, InfraredSensor, TouchSensor, UltrasonicSensor
    from ev3dev2.sensor import INPUT_1, INPUT_2, INPUT_3, INPUT_4
    from ev3dev2.sound import Sound
    from ev3dev2.button import Button
    from ev3dev2.led import Leds, LED_COLORS, LED_DEFAULT_COLOR, LED_GROUPS, LEDS
    from ev3dev2.display import Display
    import ev3dev2.fonts as fonts
    import math

    def __init__(self, filename):
        """
        Stores all the properties of the robot, such as wheel circumference, motor ports, ect.  Also provides methods for higher-level
        interaction with the robot, such as driving in a straight line at a specific heading, following a line, or driving until hitting 
        an obstacle.  Also instantiates motor and sensor objects for direct use later, if necessary.
        Reads ``filename`` for robot properties; ``filename`` should be a .ini or .cfg file in INI format.  See the current robot.cfg 
        for format example.
        """
        # Load and read the config file
        from configparser import SafeConfigParser
        conf = SafeConfigParser()
        conf.read(filename)

        # Set the "ForFLL" flag based on it's status in the config file (used in some input validation)
        self.ForFLL = bool(conf.get('Other', 'ForFLL') == "TRUE")

        # Instantiate objects for controlling things on the brick itself (Speaker, Buttons, Lights, and the LCD)
        self.spkr = self.Sound()
        self.btn = self.Button()
        self.led = self.Leds()
        self.disp = self.Display()

        # Read the drive motor ports from the config file, and store.  "eval()" is used because the port names "OUTPUT_#",
        # where # is a capital letter, A - D, are variables used as constants, and reading as a string does not work.
        self.LeftMotor = eval(conf.get('Drivebase', 'LeftMotorPort'))
        self.RightMotor = eval(conf.get('Drivebase', 'RightMotorPort'))
        # Read and store the wheel circumference and width between the wheels
        self.WheelCircumference = float(
            conf.get('Drivebase', 'WheelCircumference'))
        self.WidthBetweenWheels = float(
            conf.get('Drivebase', 'WidthBetweenWheels'))
        # Read and store MotorInverted and GyroInverted.  Both are relative to the robot, and drive functions will not work correctly if these
        # values are incorrect, and they are the first things to check if the drive functions do not work correctly.
        self.MotorInverted = bool(
            conf.get('Drivebase', 'MotorInverted') == "TRUE")
        self.GyroInverted = bool(
            conf.get('Drivebase', 'GyroInverted') == "TRUE")
        # Reads and stores the gear ratio value.
        self.GearRatio = float(conf.get('Drivebase', 'GearRatio'))
        # Reads and stores the PID gains for driving in a straight line.
        self.kp = float(conf.get('Drivebase', 'kp'))
        self.ki = float(conf.get('Drivebase', 'ki'))
        self.kd = float(conf.get('Drivebase', 'kd'))

        # Read the sensor ports from the config file, and store.  "eval()" is used because the port names "INPUT_#",
        # where # is a number, 1 - 4, are variables used as constants, and reading as a string does not work.
        self.ColorPort = eval(conf.get('Sensors', 'ColorPort'))
        self.GyroPort = eval(conf.get('Sensors', 'GyroPort'))
        self.InfraredPort = eval(conf.get('Sensors', 'InfraredPort'))
        self.TouchPort = eval(conf.get('Sensors', 'TouchPort'))
        self.UltrasonicPort = eval(conf.get('Sensors', 'UltrasonicPort'))
        # Reads and stores the PID gains for following a line.
        self.kpLine = float(conf.get('Sensors', 'kpLine'))
        self.kiLine = float(conf.get('Sensors', 'kiLine'))
        self.kdLine = float(conf.get('Sensors', 'kdLine'))

        # Read the auxillary motor ports, if any, from the config file, and store.  "eval()" is used because the port names "OUTPUT_#",
        # where # is a capital letter, A - D, are variables used as constants, and reading as a string does not work.
        self.AuxMotor1 = eval(conf.get('AuxMotors', 'AuxMotor1'))
        self.AuxMotor2 = eval(conf.get('AuxMotors', 'AuxMotor2'))

        # Instantiate the auxillary motor objects, checking if they are connected first.
        if self.AuxMotor1 is not None:
            try:
                self.m1 = MediumMotor(self.AuxMotor1)
            except:
                print("Aux Motor 1 Not Connected!")
                self.spkr.beep('-f 220')
        if self.AuxMotor2 is not None:
            try:
                self.m2 = MediumMotor(self.AuxMotor2)
            except:
                print("Aux Motor 2 Not Connected!")
                self.spkr.beep('-f 220')
                sleep(0.3)
                self.spkr.beep('-f 220')

        # Instantiate the sensor objects
        self.cs = ColorSensor(self.ColorPort)
        self.gs = GyroSensor(self.GyroPort)
        # Only instantiate auxillary sensors if the config file shows they exist
        if self.InfraredPort is not None:
            try:
                self.ir = InfraredSensor(self.InfraredPort)
            except:
                pass
        if self.UltrasonicPort is not None:
            try:
                self.us = UltrasonicSensor(self.UltrasonicPort)
            except:
                pass
        if self.TouchPort is not None:
            try:
                self.ts = TouchSensor(self.TouchPort)
            except:
                pass

        # Instantiate the drive motor objects, as well as the motorset objects for controlling both simultainiously
        self.tank = MoveTank(self.LeftMotor, self.RightMotor)
        self.steer = MoveSteering(self.LeftMotor, self.RightMotor)
        self.lm = LargeMotor(self.LeftMotor)
        self.rm = LargeMotor(self.RightMotor)

        # Reset the gyro angle to zero by switching modes
        self.gs._ensure_mode(self.gs.MODE_GYRO_G_A)
        self.cs._ensure_mode(self.cs.MODE_COL_REFLECT)

        # If the motors are inverted xor the gear ratio is negative, set the motor poloraity to be inverted,
        # so normal motor commands will run the motors in the opposite direction.
        if self.MotorInverted ^ (self.GearRatio / abs(self.GearRatio) == -1):
            self.lm.polarity = "inversed"
            self.rm.polarity = "inversed"
            self.tank.set_polarity = "inversed"
        else:
            self.lm.polarity = "normal"
            self.rm.polarity = "normal"
            self.tank.set_polarity = "normal"

        # Set the integer GyroInvertedNum to reflect the boolean GyroInverted, with -1 = True, and 1 = False,
        # for use in calculations later
        if self.GyroInverted:
            self.GyroInvertedNum = -1
        else:
            self.GyroInvertedNum = 1

        # Beep to signify the robot isdone initialization (it takes a while)
        self.spkr.beep()

    def reflectCal(self):
        """
        "Calibrate" the color sensor using high and low setpoints, and a simple linear mapping.
        The adjusted value can then be accessed using robot.correctedRLI, and the raw value can be acessed using
        robot.cs.reflected_light_intensity.

        Use:  When called, the robot will emit a high-pitched beep.  This is a signal to place the robot on a white surface
        and press the center button.  The robot then emits a low-pitched beep.  This is a signal to repeat the procedure with a
        black surface.
        """
        # These variables need to be accessed by the correctedRLI function, and thus need to be global.
        global reflHighVal
        global reflLowVal
        global reflRate
        # Signal for white
        self.spkr.beep('-f 880')
        # Wait for user conformation of a white surface
        self.btn.wait_for_bump('enter')
        # Set High fixpoint
        reflHighVal = (self.cs.reflected_light_intensity)
        # Conformation of completion
        self.spkr.beep()
        # Signal for black
        self.spkr.beep('-f 220')
        # Wait for user conformation of a black surface
        self.btn.wait_for_bump('enter')
        # Set Low fixpoint
        reflLowVal = self.cs.reflected_light_intensity
        # Conformation of completion
        self.spkr.beep()
        # Calculate the slope of the linear function that maps the fixpoints to 0 - 100
        reflRate = 100 / (reflHighVal - reflLowVal)

    @property
    def correctedRLI(self):
        """
        Returns the reflected light intensity from the color sensor, scaled based on the high and low values created by reflectCal

        This means LineFollow can use 50 as the target, even though the actual reading for black might be 20, and white 75, as it
        will be scaled to 0 - 100.
        """
        # Calculates adjusted value with a linear mapping.  To see how this works go here: https://www.desmos.com/calculator/d4mudhrdng
        value = min([
            100,
            max([
                0, (self.cs.reflected_light_intensity * reflRate) +
                (-reflLowVal * reflRate)
            ])
        ])
        return (value)

    @property
    def correctedAngle(self):
        """
        Retuns the gyro value corrected for the orientation of the gyro in the robot; turning right will always increase the value,
        and turning left will always decrease the value.  The raw value can be accessed with robot.gs.angle_and_rate[0]

        Angle and rate is used to prevent switching modes and resetting the angle.
        """

        # Multiply the gyro angle by -1 if the gyro is mounted upside-down relative to the motors in the robot.
        # GyroInvertedNum is set up in __init__()
        return (self.gs.angle_and_rate[0] * self.GyroInvertedNum)

    def zeroGyro(self):
        """
        Reset the gyro angle to zero by switching modes.  gyro.reset would have been used instead of this function, 
        but it does not work
        """
        self.gs._ensure_mode(self.gs.MODE_GYRO_RATE)
        self.gs._ensure_mode(self.gs.MODE_GYRO_G_A)

    def DriveAtHeading(self, Heading, Distance, Speed, Stop):
        """
        Moves the robot in a specified direction at a specified speed for a certian number of centimeters, while using the gyro sensor to keep the robot moving in a straight line.

        ``Heading``: The angle at which to drive, with the direction the gyro was last calibrated in being zero.
        ``Distance``: The distance to drive, in centimeters (positive only).
        ``Speed``: The speed at which to drive, in motor percentage (same speed units as EV3-G).  A negative value will make the robot drive backwards.
        ``Stop``: Stop motors after completion.  If ``FALSE``, motors will continue running after ``Distance`` has been traveled.  Otherwise, motors will stop after ``Distance`` cm.
        """
        # Ensure values are within reasonable limits, and change them if necessary (Idiotproofing).
        if Distance <= 0:
            print(
                "Distance must be greater than zero.  Use negative speed to drive backwards."
            )
            return
        elif Distance > 265:
            # The longest distance on an FLL table (diagonal) is about 265cm.
            if self.ForFLL:
                print("Please don't use silly distances (max = 265cm)")
                return
        if Speed > 75:
            Speed = 75
            print("Speed must be between -75 and 75 (inclusive).")
        elif Speed < -75:
            Speed = -75
            print("Speed must be between -75 and 75 (inclusive).")

        # "Reset" motor encoders by subtracting start values
        left_motor_start = self.lm.degrees
        right_motor_start = self.rm.degrees
        left_motor_now = self.lm.degrees
        right_motor_now = self.rm.degrees
        left_motor_change = left_motor_now - left_motor_start
        right_motor_change = right_motor_now - right_motor_start

        # Determine the sign of the speed, for PID correction
        sign = Speed / abs(Speed)

        # Find number of degrees that motors need to rotate to reach the desired number of cm.
        target = (Distance * 360) / self.WheelCircumference * abs(
            self.GearRatio)

        # Find the average of the left and right encoders, as they could be different from PID correction
        avg = abs((left_motor_change + right_motor_change) / 2)

        # Initialize variables for PID control
        integral = 0.0
        last_error = 0.0
        derivative = 0.0

        # Check if the motors have gone far enough
        while avg < target:
            # Read the gyro
            current_angle = self.correctedAngle

            # Calculate the PID components
            error = current_angle - Heading
            integral = integral + error
            derivative = error - last_error
            last_error = error

            # Calculate Steering value based on PID components and kp, ki, and kd
            turn_native_units = sign * max([
                min([(self.kp * error) + (self.ki * integral) +
                     (self.kd * derivative), 100]), -100
            ])

            # Check if the motors will stop at the end.  If not, the speed will be adjusted to come to a smooth stop.
            if Stop == False:
                speedMult = 1
            else:
                # Check if the robot has gone 70% or more of the distance.  If so, start slowing down
                if (target - avg) <= (0.3 * target):
                    # Calculate the pecrentage of the distance left to travel
                    targDist = 1 - (avg / target)
                    # Calculate speedMult based on pecentage; linear function was designed to bring the robot to a
                    # smooth stop while still reaching the target, resulting in 20% of the intial speed at end.
                    speedMult = ((8 / 3) * targDist) + 0.2
                else:
                    speedMult = 1

            # Start the motors, using the steering value calculated by the PID control, and the input speed multiplied by speedMult (0 - 1, see above).
            self.steer.on(-turn_native_units, (Speed * speedMult))

            # Update corrected encoder values
            left_motor_now = self.lm.degrees
            right_motor_now = self.rm.degrees
            left_motor_change = left_motor_now - left_motor_start
            right_motor_change = right_motor_now - right_motor_start
            avg = abs((left_motor_change + right_motor_change) / 2)

        # If the robot is to stop, stop the motors.  Otherwise, leave the motors on and return.
        if not Stop == False:
            self.steer.stop()

    def degrees2power(self, currentDifference):
        """
        Returns a power value based on the degrees left to turn, using a linear function that allows the robot
        to reach the desired angle, while slowing down as to not overshoot.  Used only in GyroTurn.
        """
        if currentDifference == 0:
            # Minimum power value is 5
            return (5)
        # Using and returning absolute values, for simplicity.  GyroTurn fixes the sign.
        currentDifference = abs(currentDifference)
        # Return calculated value
        return (min([50, max([5, ((0.125 * currentDifference) + 4.875)])]))

    def GyroTurn(self, Heading):
        """
        Turns the robot to ``Heading``, slowing down as it approaches.  Will unwind any full circles
        (if the gyro reads 540, and the value given is 90, the robot will spin until reaching 90, not 450).
        """

        # Initalize the sign variable (used to correct overshoot)
        sign = 1

        # If the current heading is equal to the desired heading, no turning is needed.
        if Heading - self.correctedAngle == 0:
            return

        # Read the gyro, and store in currentHeading
        currentHeading = self.correctedAngle
        # Continue turning until the robot is within 1 degree of the target (can be reduced if necessary)
        while (currentHeading > 0.5 + Heading) or (currentHeading <
                                                   Heading - 0.5):
            # Calculate the difference between where the robot should be and where it is
            currentDifference = Heading - currentHeading
            # The sign variable defines the direction in which to turn. It should have the same sign as the currentDifference variable.
            # If not, multiply by -1 to fix it.
            if ((sign > 0) and
                (currentDifference < 0)) or ((sign < 0) and
                                             (currentDifference > 0)):
                sign *= -1
            # Set the power variable to the absolute power (calculated by degrees2power) multiplied by the sign variable
            power = sign * self.degrees2power(currentDifference)
            # Start turning
            self.tank.on(power, -1 * power)
            # Update currentHeading
            currentHeading = self.correctedAngle
        # When the loop finishes, stop the motors.
        self.tank.stop()

    def ArcTurn(self, Degrees, Radius, Speed):
        """
        Drive the robot in an arc with a specified radius, for a certain number of degrees.

        ``Degrees``:  The number or degrees to drive around the arc.  Positive will turn the front of the robot right, negative left (car turn).  
        ``Radius``:  The radius of the arc to drive, in cm.  Must be positive.
        ``Speed``:  The speed at which to drive around the arc, in percentage of full power (same units as EV3-G).  Negative will drive
        backwards.
        """

        # Ensure the parameters are within reasonable limits, and adjust/reject as necessary.
        if Speed > 75:
            Speed = 75
            print("Speed must be between -75 and 75 (inclusive).")
        elif Speed < -75:
            Speed = -75
            print("Speed must be between -75 and 75 (inclusive).")
        if Radius <= 0:
            print(
                "Radius must be greater than zero.  Use negative degrees to turn the opposite direction."
            )
            return
        # No point in driving in circles
        Degrees = math.fmod(Degrees, 360)

        # Read the angle of the robot, and store in startHeading
        startHeading = self.correctedAngle

        # If both Degrees and Speed have the same sign, the right wheel should be slowed down.
        # Otherwise, slow down the left wheel.
        if ((Degrees > 0) and (Speed > 0)) or ((Degrees < 0) and (Speed < 0)):
            self.tank.on(Speed,
                         (Radius - self.WidthBetweenWheels) * Speed / Radius)
        else:
            self.tank.on((Radius - self.WidthBetweenWheels) * Speed / Radius,
                         Speed)

        # If Degrees is positive, wait for the degrees turned to become >= Degrees (to turn).
        # Otherwise, wait for the degrees turned to become <= Degrees
        if Degrees > 0:
            while (self.correctedAngle - startHeading) < Degrees:
                pass
        else:
            while (self.correctedAngle - startHeading) > Degrees:
                pass

        # Stop the motors
        self.tank.stop()

    def DriveBump(self, Heading, Speed):
        """
        Moves the robot in a specified direction at a specified speed until it hits something, while using the gyro sensor to keep the robot moving in a straight line.

        ``Heading``: The angle at which to drive, with the direction the gyro was last calibrated in being zero.
        ``Speed``: The speed at which to drive, in motor percentage (same speed units as EV3-G).  A negative value will make the robot drive backwards.
        """

        # Ensure values are within reasonable limits, and change them if necessary (Idiotproofing).
        if Speed > 75:
            Speed = 75
            print("Speed must be between -75 and 75 (inclusive).")
        elif Speed < -75:
            Speed = -75
            print("Speed must be between -75 and 75 (inclusive).")

        # Check and store the sign of the input speed (for PID correction), and convert the target speed to encoder ticks per second
        sign = Speed * -1 / abs(Speed)
        target = abs((self.lm.max_speed * Speed) / 100)

        # Initialize variables for PID control
        integral = 0.0
        last_error = 0.0
        derivative = 0.0

        # Read the gyro
        current_angle = self.correctedAngle

        # Calculate the PID components
        error = current_angle - Heading
        integral = integral + error
        derivative = error - last_error
        last_error = error

        # Calculate Steering value based on PID components and kp, ki, and kd
        turn_native_units = sign * max([
            min([(self.kp * error) + (self.ki * integral) +
                 (self.kd * derivative), 100]), -100
        ])

        # Start the motors without speed regulation, using the Steering value and Speed
        lsrs = self.steer.get_speed_steering(
            turn_native_units, Speed)  # lsrs = left-speed right-speed
        lsNative = lsrs[0]
        rsNative = lsrs[1]
        self.lm.on(SpeedNativeUnits(lsNative))
        self.rm.on(SpeedNativeUnits(rsNative))

        # Wait for motors to get up to speed, then check and store the average speed (between the two motors)
        time.sleep(1)
        avgSpd = abs((self.lm.speed + self.rm.speed) / 2)

        # Check if the motors have slowed down (because the robot hit something)
        while avgSpd > 0.90 * target:
            # Read the gyro
            current_angle = self.correctedAngle

            # Calculate the PID components
            error = current_angle - Heading
            integral = integral + error
            derivative = error - last_error
            last_error = error

            # Calculate Steering value based on PID components and kp, ki, and kd
            turn_native_units = sign * max([
                min([(self.kp * error) + (self.ki * integral) +
                     (self.kd * derivative), 100]), -100
            ])

            # Start the motors without speed regulation, using the Steering value and Speed
            lsrs = self.steer.get_speed_steering(turn_native_units, Speed)
            lsNative = lsrs[0]
            rsNative = lsrs[1]
            self.lm.on(SpeedNativeUnits(lsNative))
            self.rm.on(SpeedNativeUnits(rsNative))

            # Check and store the average speed again
            avgSpd = abs((self.lm.speed + self.rm.speed) / 2)

        # Stop the motors
        self.lm.stop()
        self.rm.stop()

    def AuxMotorBumpStop(self, Speed, Threshold, Port):
        """
        Similar to DriveBump, will run an auxillary motor until the speed drops below ``Threshold``% of ``Speed``.

        ``Speed``: Speed at which to run the motor, in motor percentage (Same units as EV3-G).
        ``Threshold``: Percentage of ``Speed`` that the motor speed must drop below before shutting off.
        ``Port``: Motor port.
        """
        # Most if statments are only because there are two possible ports; one case for each port

        # Ensure values are within reasonable, and adjust/reject as necessary
        if Speed > 75:
            Speed = 75
            print("Speed must be between -75 and 75 (inclusive).")
        elif Speed < -75:
            Speed = -75
            print("Speed must be between -75 and 75 (inclusive).")
        if Threshold <= 0:
            print("Threshold must be greater than zero and less than one")
            return
        elif Threshold > 100:
            print(
                "Threshold must be greater than zero and less than or equal to 100"
            )
            return

        # Different commands for different motors, check which motor to use
        if Port == self.AuxMotor1:
            # Find the target speed in encoder ticks per second
            target = abs((self.m1.max_speed * Speed) / 100)
            # Start the motor, with the calculated speed
            self.m1.on(SpeedNativeUnits(target))
            # Wait for the motor to get up to speed
            time.sleep(0.5)
            # Set motrspeed to the current motor speed
            motrspeed = abs(self.m1.speed)
        else:
            # Everything here is the same as the first case statement, but using m2 instead of m1 (motor 2, not motor 1)
            target = abs((self.m2.max_speed * Speed) / 100)
            self.m2.on(SpeedNativeUnits(target))
            time.sleep(0.5)
            motrspeed = abs(self.m2.speed)
            # Keep the motor on until the motor speed drops below Threshold% of Speed
        while motrspeed > (target * Threshold) / 100:
            if Port == self.AuxMotor1:
                # Update motrspeed until the motor slows down enough to stop
                motrspeed = abs(self.m1.speed)
            else:
                # Same as before, just for the other motor
                motrspeed = abs(self.m2.speed)
        # Shut off the motor
        if Port == self.AuxMotor1:
            self.m1.off()
        else:
            self.m2.off()

    def LineStop(self, Heading, Speed, Stop):
        """
        Moves the robot in a specified direction at a specified speed until a line (White-Black) is seen, while using the gyro sensor to keep the robot moving in a straight line.

        ``Heading``: The angle at which to drive, with the direction the gyro was last calibrated in being zero.
        ``Speed``: The speed at which to drive, in motor percentage (same speed units as EV3-G).  A negative value will make the robot drive backwards.
        ``Stop``: Stop motors after completion.  If ``FALSE``, motors will continue running after ``Distance`` has been traveled.  Otherwise, motors will stop after ``Distance`` cm.
        """
        # Ensure values are within reasonable limits, and change them if necessary (Idiotproofing).
        if Speed > 75:
            Speed = 75
            print("Speed must be between -75 and 75 (inclusive).")
        elif Speed < -75:
            Speed = -75
            print("Speed must be between -75 and 75 (inclusive).")

        # Check and store the sign of the input speed for PID correction
        sign = Speed / abs(Speed)

        # Set the color sensor to "Color" mode
        self.cs._ensure_mode(self.cs.MODE_COL_COLOR)

        # Set the brick light to solid amber
        #EV3.SetLEDColor("ORANGE", "NORMAL")

        # Initialize variables for PID control and end checking
        integral = 0.0
        last_error = 0.0
        derivative = 0.0
        end = False
        seenWhite = False

        # Check if the motors have gone far enough
        while not end:
            # Read the gyro
            current_angle = self.correctedAngle

            # Calculate the PID components
            error = current_angle - Heading
            integral = integral + error
            derivative = error - last_error
            last_error = error

            # Calculate Steering value based on PID components and kp, ki, and kd
            turn_native_units = sign * max([
                min([(self.kp * error) + (self.ki * integral) +
                     (self.kd * derivative), 100]), -100
            ])

            # Start the motors, using the steering value calculated by the PID control, and the input speed multiplied by speedMult (0 - 1, see above).
            self.steer.on(-turn_native_units, (Speed))

            # Check if the sensor is seeing white
            color = self.cs.color
            if color == self.cs.COLOR_WHITE:
                seenWhite = True
            elif (color == self.cs.COLOR_BLACK) and seenWhite:
                end = True
            elif color == self.cs.COLOR_BLUE:
                seenWhite = seenWhite
            else:
                seenWhite = False

        # If the robot is to stop, stop the motors.  Otherwise, leave the motors on.
        if not Stop == False:
            self.steer.stop()

        # Set the brick light back to green flashing
        #EVS.SetLEDColor("GREEN", "PULSE")

    def LineFollow(self, Distance, Speed, Stop):
        """
        Follows the edge of a line for a specific distance at a specific speed.

        ``Distance``: The distance to drive, in centimeters (positive only).
        ``Speed``: The speed at which to drive, in motor percentage (same speed units as EV3-G).  (Positive only; there's no going back)
        ``Stop``: Stop motors after completion.  If ``FALSE``, motors will continue running after ``Distance`` has been traveled.  Otherwise, motors will stop after ``Distance`` cm.
        """
        # Ensure values are within reasonable limits, and change them if necessary (Idiotproofing).
        if Speed > 50:
            Speed = 50
            print("Speed must be between -50 and 50 (inclusive).")
        elif Speed < -50:
            Speed = -50
            print("Speed must be between -50 and 50 (inclusive).")

        # "Reset" motor encoders by subtracting start values
        left_motor_start = self.lm.degrees
        right_motor_start = self.rm.degrees
        left_motor_now = self.lm.degrees
        right_motor_now = self.rm.degrees
        left_motor_change = left_motor_now - left_motor_start
        right_motor_change = right_motor_now - right_motor_start

        # Determine the sign of the speed, for PID correction
        sign = Speed / abs(Speed)

        # Find number of degrees that motors need to rotate to reach the desired number of cm.
        target = (Distance * 360) / self.WheelCircumference * abs(
            self.GearRatio)

        # Find the average of the left and right encoders, as they could be different from PID correction
        avg = abs((left_motor_change + right_motor_change) / 2)

        # Initialize variables for PID control
        integral = 0.0
        last_error = 0.0
        derivative = 0.0

        # Check if the motors have gone far enough
        while avg < target:
            # Read the gyro
            current_RLI = self.correctedRLI

            # Calculate the PID components
            error = 50 - current_RLI
            integral = integral + error
            derivative = error - last_error
            last_error = error

            # Calculate Steering value based on PID components and kp, ki, and kd
            turn_native_units = sign * max([
                min([(self.kpLine * error) + (self.kiLine * integral) +
                     (self.kdLine * derivative), 100]), -100
            ])

            # Check if the motors will stop at the end.  If not, the speed will be adjusted to come to a smooth stop.
            if Stop == False:
                speedMult = 1
            else:
                # Check if the robot has gone 70% or more of the distance.  If so, start slowing down
                if (target - avg) <= (0.3 * target):
                    # Calculate the pecrentage of the distance left to travel
                    targDist = 1 - (avg / target)
                    # Calculate speedMult based on pecentage; linear function was designed to bring the robot to a
                    # smooth stop while still reaching the target.
                    speedMult = ((8 / 3) * targDist) + 0.2
                else:
                    speedMult = 1

            # Start the motors, using the steering value calculated by the PID control, and the input speed multiplied by speedMult (0 - 1, see above).
            self.steer.on(-turn_native_units, (Speed * speedMult))

            # Update corrected encoder values
            left_motor_now = self.lm.degrees
            right_motor_now = self.rm.degrees
            left_motor_change = left_motor_now - left_motor_start
            right_motor_change = right_motor_now - right_motor_start
            avg = abs((left_motor_change + right_motor_change) / 2)

        # If the robot is to stop, stop the motors.  Otherwise, leave the motors on and return.
        if not Stop == False:
            self.steer.stop()

    def TriangleAvoid(self, Heading, Distance, Speed):
        """
        Moves the robot in a specified direction at a specified speed for a certian number of centimeters, while using the gyro sensor to keep the robot moving in a straight line.

        ``Heading``: The angle at which to drive, with the direction the gyro was last calibrated in being zero.
        ``Distance``: The distance to drive, in centimeters (positive only).
        ``Speed``: The speed at which to drive, in motor percentage (same speed units as EV3-G).  A negative value will make the robot drive backwards.
        ``Stop``: Stop motors after completion.  If ``FALSE``, motors will continue running after ``Distance`` has been traveled.  Otherwise, motors will stop after ``Distance`` cm.
        """
        # Ensure values are within reasonable limits, and change them if necessary (Idiotproofing).
        if Distance <= 0:
            print(
                "Distance must be greater than zero.  Use negative speed to drive backwards."
            )
            return
        elif Distance > 265:
            # The longest distance on an FLL table (diagonal) is about 265cm.
            if self.ForFLL:
                print("Please don't use silly distances (max = 265cm)")
                return
        if Speed > 75:
            Speed = 75
            print("Speed must be between -75 and 75 (inclusive).")
        elif Speed < -75:
            Speed = -75
            print("Speed must be between -75 and 75 (inclusive).")
        if not self.us:
            print("Avoidance Functions need the US sensor to work.")
            return

        # "Reset" motor encoders by subtracting start values
        left_motor_start = self.lm.degrees
        right_motor_start = self.rm.degrees
        left_motor_now = self.lm.degrees
        right_motor_now = self.rm.degrees
        left_motor_change = left_motor_now - left_motor_start
        right_motor_change = right_motor_now - right_motor_start

        # Determine the sign of the speed, for PID correction
        sign = Speed / abs(Speed)

        # Find number of degrees that motors need to rotate to reach the desired number of cm.
        target = (Distance * 360) / self.WheelCircumference * abs(
            self.GearRatio)

        # Find the average of the left and right encoders, as they could be different from PID correction
        avg = abs((left_motor_change + right_motor_change) / 2)

        # Find the number of centimeters driven and left to go
        driven_so_far = (avg * self.WheelCircumference) / 360
        left_to_go = Distance - driven_so_far

        # Initialize variables for PID control
        integral = 0.0
        last_error = 0.0
        derivative = 0.0

        # Check if the motors have gone far enough
        while avg < target:
            # Read the gyro and ultrasonic sensors
            current_angle = self.correctedAngle
            dist_to_obstacle = self.us.distance_centimeters

            # Calculate the PID components
            error = current_angle - Heading
            integral = integral + error
            derivative = error - last_error
            last_error = error

            # Calculate Steering value based on PID components and kp, ki, and kd
            turn_native_units = sign * max([
                min([(self.kp * error) + (self.ki * integral) +
                     (self.kd * derivative), 100]), -100
            ])

            # Check if the motors will stop at the end.  If not, the speed will be adjusted to come to a smooth stop.
            # Check if the robot has gone 70% or more of the distance.  If so, start slowing down
            if (target - avg) <= (0.3 * target):
                # Calculate the pecrentage of the distance left to travel
                targDist = 1 - (avg / target)
                # Calculate speedMult based on pecentage; linear function was designed to bring the robot to a
                # smooth stop while still reaching the target, resulting in 20% of the intial speed at end.
                speedMult = ((8 / 3) * targDist) + 0.2
            else:
                speedMult = 1

            if (dist_to_obstacle <= 30) and (left_to_go > 30):
                self.steer.off(brake=False)
                left_motor_now = self.lm.degrees
                right_motor_now = self.rm.degrees
                left_motor_change = left_motor_now - left_motor_start
                right_motor_change = right_motor_now - right_motor_start
                avg = abs((left_motor_change + right_motor_change) / 2)
                driven_so_far = (avg * self.WheelCircumference) / 360
                dist_to_obstacle = self.us.distance_centimeters
                start_angle = self.correctedAngle
                while self.us.distance_centimeters < 60:
                    self.tank.on(-10, 10)
                self.tank.off()
                self.GyroTurn(self.correctedAngle - 5)
                end_angle = self.correctedAngle
                degrees_turned = abs(end_angle - start_angle)
                first_hypotenuse = dist_to_obstacle / math.cos(
                    math.radians(degrees_turned))
                self.DriveAtHeading(end_angle, first_hypotenuse, 20, True)
                second_triangle_short_leg = math.sqrt((first_hypotenuse**2) -
                                                      (dist_to_obstacle**2))
                second_triangle_long_leg = Distance - (driven_so_far +
                                                       dist_to_obstacle + 2.21)
                second_triangle_second_angle = math.degrees(
                    math.atan(second_triangle_long_leg /
                              second_triangle_short_leg))
                degrees_to_turn = 90 - second_triangle_second_angle
                self.GyroTurn(Heading)
                self.GyroTurn(Heading + degrees_to_turn)
                second_hypotenuse = math.sqrt((second_triangle_long_leg**2) +
                                              (second_triangle_short_leg**2))
                self.TriangleAvoid(self.correctedAngle, second_hypotenuse, 20)
                self.GyroTurn(Heading)
                return

            # Start the motors, using the steering value calculated by the PID control, and the input speed multiplied by speedMult (0 - 1, see above).
            self.steer.on(-turn_native_units, (Speed * speedMult))

            # Update corrected encoder values
            left_motor_now = self.lm.degrees
            right_motor_now = self.rm.degrees
            left_motor_change = left_motor_now - left_motor_start
            right_motor_change = right_motor_now - right_motor_start
            avg = abs((left_motor_change + right_motor_change) / 2)
            driven_so_far = (avg * self.WheelCircumference) / 360

        # Stop the motors.
        self.steer.stop()

    def CircleAvoid(self, Heading, Distance, Speed):
        """
        Moves the robot in a specified direction at a specified speed for a certian number of centimeters, while using the gyro sensor to keep the robot moving in a straight line.

        ``Heading``: The angle at which to drive, with the direction the gyro was last calibrated in being zero.
        ``Distance``: The distance to drive, in centimeters (positive only).
        ``Speed``: The speed at which to drive, in motor percentage (same speed units as EV3-G).  A negative value will make the robot drive backwards.
        ``Stop``: Stop motors after completion.  If ``FALSE``, motors will continue running after ``Distance`` has been traveled.  Otherwise, motors will stop after ``Distance`` cm.
        """
        # Ensure values are within reasonable limits, and change them if necessary (Idiotproofing).
        if Distance <= 0:
            print(
                "Distance must be greater than zero.  Use negative speed to drive backwards."
            )
            return
        elif Distance > 265:
            # The longest distance on an FLL table (diagonal) is about 265cm.
            if self.ForFLL:
                print("Please don't use silly distances (max = 265cm)")
                return
        if Speed > 75:
            Speed = 75
            print("Speed must be between -75 and 75 (inclusive).")
        elif Speed < -75:
            Speed = -75
            print("Speed must be between -75 and 75 (inclusive).")
        if not self.us:
            print("Avoidance Functions need the US sensor to work.")
            return

        # "Reset" motor encoders by subtracting start values
        left_motor_start = self.lm.degrees
        right_motor_start = self.rm.degrees
        left_motor_now = self.lm.degrees
        right_motor_now = self.rm.degrees
        left_motor_change = left_motor_now - left_motor_start
        right_motor_change = right_motor_now - right_motor_start

        # Determine the sign of the speed, for PID correction
        sign = Speed / abs(Speed)

        # Find number of degrees that motors need to rotate to reach the desired number of cm.
        target = (Distance * 360) / self.WheelCircumference * abs(
            self.GearRatio)

        # Find the average of the left and right encoders, as they could be different from PID correction
        avg = abs((left_motor_change + right_motor_change) / 2)

        # Find the number of centimeters driven and left to go
        driven_so_far = (avg * self.WheelCircumference) / 360
        left_to_go = Distance - driven_so_far

        # Initialize variables for PID control
        integral = 0.0
        last_error = 0.0
        derivative = 0.0

        # Check if the motors have gone far enough
        while avg < target:
            # Read the gyro and ultrasonic sensors
            current_angle = self.correctedAngle
            dist_to_obstacle = self.us.distance_centimeters

            # Calculate the PID components
            error = current_angle - Heading
            integral = integral + error
            derivative = error - last_error
            last_error = error

            # Calculate Steering value based on PID components and kp, ki, and kd
            turn_native_units = sign * max([
                min([(self.kp * error) + (self.ki * integral) +
                     (self.kd * derivative), 100]), -100
            ])

            # Check if the motors will stop at the end.  If not, the speed will be adjusted to come to a smooth stop.
            # Check if the robot has gone 70% or more of the distance.  If so, start slowing down
            if (target - avg) <= (0.3 * target):
                # Calculate the pecrentage of the distance left to travel
                targDist = 1 - (avg / target)
                # Calculate speedMult based on pecentage; linear function was designed to bring the robot to a
                # smooth stop while still reaching the target, resulting in 20% of the intial speed at end.
                speedMult = ((8 / 3) * targDist) + 0.2
            else:
                speedMult = 1

            if (dist_to_obstacle <= 30) and (left_to_go > 30):
                self.steer.off(brake=False)
                left_motor_now = self.lm.degrees
                right_motor_now = self.rm.degrees
                left_motor_change = left_motor_now - left_motor_start
                right_motor_change = right_motor_now - right_motor_start
                avg = abs((left_motor_change + right_motor_change) / 2)
                driven_so_far = (avg * self.WheelCircumference) / 360
                dist_to_obstacle = self.us.distance_centimeters
                start_angle = self.correctedAngle
                while self.us.distance_centimeters < 60:
                    self.tank.on(-10, 10)
                self.tank.off()
                self.GyroTurn(self.correctedAngle - 5)
                end_angle = self.correctedAngle
                degrees_turned = abs(end_angle - start_angle)
                second_point_y = dist_to_obstacle * math.tan(
                    math.radians(degrees_turned))
                third_point_x = Distance - driven_so_far
                x_numerator = -(third_point_x**2) * second_point_y
                y_numerator = -((dist_to_obstacle**2) * third_point_x) - (
                    (second_point_y**2) * third_point_x) + (
                        (third_point_x**2) * dist_to_obstacle)
                denominator = -2 * third_point_x * second_point_y
                h = x_numerator / denominator
                k = y_numerator / denominator
                radius = math.sqrt((h**2) + (k**2))
                begin_arc_angle = math.degrees(math.atan(h / -k))
                arc_angle = -2 * begin_arc_angle
                self.GyroTurn(Heading + begin_arc_angle)
                self.ArcTurn(arc_angle, radius, 10)
                self.GyroTurn(Heading)
                return

            # Start the motors, using the steering value calculated by the PID control, and the input speed multiplied by speedMult (0 - 1, see above).
            self.steer.on(-turn_native_units, (Speed * speedMult))

            # Update corrected encoder values
            left_motor_now = self.lm.degrees
            right_motor_now = self.rm.degrees
            left_motor_change = left_motor_now - left_motor_start
            right_motor_change = right_motor_now - right_motor_start
            avg = abs((left_motor_change + right_motor_change) / 2)
            driven_so_far = (avg * self.WheelCircumference) / 360

        # Stop the motors.
        self.steer.stop()