├── Chapter 1 - Getting Up and Running └── hello_world.py ├── Chapter 2 - Electronics Basics ├── blink.py └── button.py ├── Chapter 4 - Making your Robot Move ├── accel_test.py ├── first_move.py ├── remote_control.py └── remote_control_accel.py ├── Chapter 5 - Obstacle Avoidance ├── distance_test.py └── obstacle_avoider.py ├── Chapter 6 - Adding RGB LEDs and Sound ├── beep_obstacle_avoider.py ├── neo_remote_control.py ├── neo_speaker_remote_control.py ├── sounds │ ├── beep.wav │ └── horn.wav └── strandtest.py ├── Chapter 7 - Line Following ├── line_follower.py ├── line_following_tiles │ └── track_generator.pdf └── line_test.py ├── Chapter 8 - Computer Vision ├── ball_follower.py └── hsv_tester.py ├── LICENSE └── README.md /Chapter 1 - Getting Up and Running/hello_world.py: -------------------------------------------------------------------------------- 1 | print("Hello, world!") 2 | -------------------------------------------------------------------------------- /Chapter 2 - Electronics Basics/blink.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import time 3 | 4 | led = gpiozero.LED(4) 5 | 6 | while True: 7 | led.on() 8 | time.sleep(1) 9 | led.off() 10 | time.sleep(1) 11 | 12 | -------------------------------------------------------------------------------- /Chapter 2 - Electronics Basics/button.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | 3 | button = gpiozero.Button(17) 4 | 5 | while True: 6 | if button.is_pressed: 7 | print("Button is pressed!") 8 | else: 9 | print("Button is not pressed!") 10 | -------------------------------------------------------------------------------- /Chapter 4 - Making your Robot Move/accel_test.py: -------------------------------------------------------------------------------- 1 | import cwiid 2 | import time 3 | 4 | print("Press and hold the 1+2 buttons on your Wiimote simultaneously") 5 | wii = cwiid.Wiimote() 6 | print("Connection established") 7 | wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC 8 | 9 | while True: 10 | print(wii.state['acc']) 11 | time.sleep(0.01) 12 | -------------------------------------------------------------------------------- /Chapter 4 - Making your Robot Move/first_move.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import time 3 | 4 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 5 | 6 | for i in range(4): 7 | robot.forward() 8 | time.sleep(0.5) 9 | robot.right() 10 | time.sleep(0.25) 11 | -------------------------------------------------------------------------------- /Chapter 4 - Making your Robot Move/remote_control.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import cwiid 3 | 4 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 5 | 6 | print("Press and hold the 1+2 buttons on your Wiimote simultaneously") 7 | wii = cwiid.Wiimote() 8 | print("Connection established") 9 | wii.rpt_mode = cwiid.RPT_BTN 10 | 11 | while True: 12 | buttons = wii.state["buttons"] 13 | 14 | if (buttons & cwiid.BTN_LEFT): 15 | robot.left() 16 | if (buttons & cwiid.BTN_RIGHT): 17 | robot.right() 18 | if (buttons & cwiid.BTN_UP): 19 | robot.forward() 20 | if (buttons & cwiid.BTN_DOWN): 21 | robot.backward() 22 | if (buttons & cwiid.BTN_B): 23 | robot.stop() 24 | -------------------------------------------------------------------------------- /Chapter 4 - Making your Robot Move/remote_control_accel.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import cwiid 3 | 4 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 5 | 6 | print("Press and hold the 1+2 buttons on your Wiimote simultaneously") 7 | wii = cwiid.Wiimote() 8 | print("Connection established") 9 | wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC 10 | 11 | while True: 12 | x = (wii.state["acc"][cwiid.X] - 95) - 25 13 | y = (wii.state["acc"][cwiid.Y] - 95) - 25 14 | 15 | if x < -25: 16 | x = -25 17 | if y < -25: 18 | y = -25 19 | if x > 25: 20 | x = 25 21 | if y > 25: 22 | y = 25 23 | 24 | forward_value = (float(x)/50)*2 25 | turn_value = (float(y)/50)*2 26 | 27 | if (turn_value < 0.3) and (turn_value > -0.3): 28 | robot.value = (forward_value, forward_value) 29 | else: 30 | robot.value = (-turn_value, turn_value) 31 | 32 | 33 | -------------------------------------------------------------------------------- /Chapter 5 - Obstacle Avoidance/distance_test.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import time 3 | 4 | TRIG = 23 5 | ECHO = 24 6 | 7 | trigger = gpiozero.OutputDevice(TRIG) 8 | echo = gpiozero.DigitalInputDevice(ECHO) 9 | 10 | trigger.on() 11 | time.sleep(0.00001) 12 | trigger.off() 13 | 14 | while echo.is_active == False: 15 | pulse_start = time.time() 16 | 17 | while echo.is_active == True: 18 | pulse_end = time.time() 19 | 20 | pulse_duration = pulse_end - pulse_start 21 | 22 | distance = 34300 * (pulse_duration/2) 23 | 24 | round_distance = round(distance,2) 25 | 26 | print("Distance: ", round_distance) 27 | -------------------------------------------------------------------------------- /Chapter 5 - Obstacle Avoidance/obstacle_avoider.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import time 3 | 4 | TRIG = 23 5 | ECHO = 24 6 | 7 | trigger = gpiozero.OutputDevice(TRIG) 8 | echo = gpiozero.DigitalInputDevice(ECHO) 9 | 10 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 11 | 12 | def get_distance(trigger, echo): 13 | trigger.on() 14 | time.sleep(0.00001) 15 | trigger.off() 16 | 17 | while echo.is_active == False: 18 | pulse_start = time.time() 19 | 20 | while echo.is_active == True: 21 | pulse_end = time.time() 22 | 23 | pulse_duration = pulse_end - pulse_start 24 | 25 | distance = 34300 * (pulse_duration/2) 26 | 27 | round_distance = round(distance,1) 28 | 29 | return(round_distance) 30 | 31 | while True: 32 | dist = get_distance(trigger,echo) 33 | if dist <= 15: 34 | robot.right(0.3) 35 | time.sleep(0.25) 36 | else: 37 | robot.forward(0.3) 38 | time.sleep(0.1) 39 | -------------------------------------------------------------------------------- /Chapter 6 - Adding RGB LEDs and Sound/beep_obstacle_avoider.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import time 3 | import os 4 | 5 | TRIG = 23 6 | ECHO = 24 7 | 8 | trigger = gpiozero.OutputDevice(TRIG) 9 | echo = gpiozero.DigitalInputDevice(ECHO) 10 | 11 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 12 | 13 | def get_distance(trigger, echo): 14 | trigger.on() 15 | time.sleep(0.00001) 16 | trigger.off() 17 | 18 | while echo.is_active == False: 19 | pulse_start = time.time() 20 | 21 | while echo.is_active == True: 22 | pulse_end = time.time() 23 | 24 | pulse_duration = pulse_end - pulse_start 25 | 26 | distance = 34300 * (pulse_duration/2) 27 | 28 | round_distance = round(distance,1) 29 | 30 | return(round_distance) 31 | 32 | while True: 33 | dist = get_distance(trigger,echo) 34 | if dist <= 15: 35 | os.system("aplay sounds/beep.wav") 36 | robot.right(0.3) 37 | time.sleep(0.25) 38 | else: 39 | robot.forward(0.3) 40 | time.sleep(0.1) 41 | -------------------------------------------------------------------------------- /Chapter 6 - Adding RGB LEDs and Sound/neo_remote_control.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import cwiid 3 | import time 4 | from rpi_ws281x import * 5 | 6 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 7 | 8 | print("Press and hold the 1+2 buttons on your Wiimote simultaneously") 9 | wii = cwiid.Wiimote() 10 | print("Connection established") 11 | wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC 12 | 13 | LED_COUNT = 8 14 | LED_PIN = 10 15 | LED_FREQ_HZ = 800000 16 | LED_DMA = 10 17 | LED_BRIGHTNESS = 150 18 | LED_INVERT = False 19 | LED_CHANNEL = 0 20 | LED_STRIP = ws.WS2811_STRIP_GRB 21 | 22 | strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP) 23 | strip.begin() 24 | 25 | def colorWipe(strip, color, wait_ms=50): 26 | """Wipe color across display a pixel at a time.""" 27 | for i in range(strip.numPixels()): 28 | strip.setPixelColor(i, color) 29 | strip.show() 30 | time.sleep(wait_ms/1000.0) 31 | 32 | while True: 33 | buttons = wii.state["buttons"] 34 | if (buttons & cwiid.BTN_PLUS): 35 | colorWipe(strip, Color(255, 0, 0)) # Red wipe 36 | if (buttons & cwiid.BTN_HOME): 37 | colorWipe(strip, Color(0, 255, 0)) # Blue wipe 38 | if (buttons & cwiid.BTN_MINUS): 39 | colorWipe(strip, Color(0, 0, 255)) # Green wipe 40 | if (buttons & cwiid.BTN_B): 41 | colorWipe(strip, Color(0, 0, 0)) # Blank 42 | 43 | x = (wii.state["acc"][cwiid.X] - 95) - 25 44 | y = (wii.state["acc"][cwiid.Y] - 95) - 25 45 | 46 | if x < -25: 47 | x = -25 48 | if y < -25: 49 | y = -25 50 | if x > 25: 51 | x = 25 52 | if y > 25: 53 | y = 25 54 | 55 | forward_value = (float(x)/50)*2 56 | turn_value = (float(y)/50)*2 57 | 58 | if (turn_value < 0.3) and (turn_value > -0.3): 59 | robot.value = (forward_value, forward_value) 60 | else: 61 | robot.value = (-turn_value, turn_value) 62 | 63 | 64 | -------------------------------------------------------------------------------- /Chapter 6 - Adding RGB LEDs and Sound/neo_speaker_remote_control.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import cwiid 3 | import time 4 | from rpi_ws281x import * 5 | import os 6 | 7 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 8 | 9 | print("Press and hold the 1+2 buttons on your Wiimote simultaneously") 10 | wii = cwiid.Wiimote() 11 | print("Connection established") 12 | wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC 13 | 14 | LED_COUNT = 8 15 | LED_PIN = 10 16 | LED_FREQ_HZ = 800000 17 | LED_DMA = 10 18 | LED_BRIGHTNESS = 150 19 | LED_INVERT = False 20 | LED_CHANNEL = 0 21 | LED_STRIP = ws.WS2811_STRIP_GRB 22 | 23 | strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP) 24 | strip.begin() 25 | 26 | def colorWipe(strip, color, wait_ms=50): 27 | """Wipe color across display a pixel at a time.""" 28 | for i in range(strip.numPixels()): 29 | strip.setPixelColor(i, color) 30 | strip.show() 31 | time.sleep(wait_ms/1000.0) 32 | 33 | while True: 34 | buttons = wii.state["buttons"] 35 | if (buttons & cwiid.BTN_PLUS): 36 | colorWipe(strip, Color(255, 0, 0)) # Red wipe 37 | if (buttons & cwiid.BTN_HOME): 38 | colorWipe(strip, Color(0, 255, 0)) # Blue wipe 39 | if (buttons & cwiid.BTN_MINUS): 40 | colorWipe(strip, Color(0, 0, 255)) # Green wipe 41 | if (buttons & cwiid.BTN_B): 42 | colorWipe(strip, Color(0, 0, 0)) # Blank 43 | 44 | if (buttons & cwiid.BTN_A): 45 | os.system("aplay sounds/horn.wav") 46 | 47 | x = (wii.state["acc"][cwiid.X] - 95) - 25 48 | y = (wii.state["acc"][cwiid.Y] - 95) - 25 49 | 50 | if x < -25: 51 | x = -25 52 | if y < -25: 53 | y = -25 54 | if x > 25: 55 | x = 25 56 | if y > 25: 57 | y = 25 58 | 59 | forward_value = (float(x)/50)*2 60 | turn_value = (float(y)/50)*2 61 | 62 | if (turn_value < 0.3) and (turn_value > -0.3): 63 | robot.value = (forward_value, forward_value) 64 | else: 65 | robot.value = (-turn_value, turn_value) 66 | 67 | 68 | -------------------------------------------------------------------------------- /Chapter 6 - Adding RGB LEDs and Sound/sounds/beep.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-raspberry-pi-guy/raspirobots/3819dd3a89ae5d66bced578f25ffbc627b07087f/Chapter 6 - Adding RGB LEDs and Sound/sounds/beep.wav -------------------------------------------------------------------------------- /Chapter 6 - Adding RGB LEDs and Sound/sounds/horn.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-raspberry-pi-guy/raspirobots/3819dd3a89ae5d66bced578f25ffbc627b07087f/Chapter 6 - Adding RGB LEDs and Sound/sounds/horn.wav -------------------------------------------------------------------------------- /Chapter 6 - Adding RGB LEDs and Sound/strandtest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # NeoPixel library strandtest example 3 | # Author: Tony DiCola (tony@tonydicola.com) 4 | # 5 | # Direct port of the Arduino NeoPixel library strandtest example. Showcases 6 | # various animations on a strip of NeoPixels. 7 | 8 | # Minor edits by Matt Timmons-Brown for "Learn Robotics with Raspberry Pi" 9 | 10 | import time 11 | from rpi_ws281x import * 12 | import argparse 13 | 14 | # LED strip configuration: 15 | LED_COUNT = 16 # Number of LED pixels. 16 | LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!). 17 | #LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0). 18 | LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) 19 | LED_DMA = 10 # DMA channel to use for generating signal (try 10) 20 | LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest 21 | LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) 22 | LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 23 | LED_STRIP = ws.WS2811_STRIP_GRB # Strip type and color ordering 24 | 25 | # Define functions which animate LEDs in various ways. 26 | def colorWipe(strip, color, wait_ms=50): 27 | """Wipe color across display a pixel at a time.""" 28 | for i in range(strip.numPixels()): 29 | strip.setPixelColor(i, color) 30 | strip.show() 31 | time.sleep(wait_ms/1000.0) 32 | 33 | def theaterChase(strip, color, wait_ms=50, iterations=10): 34 | """Movie theater light style chaser animation.""" 35 | for j in range(iterations): 36 | for q in range(3): 37 | for i in range(0, strip.numPixels(), 3): 38 | strip.setPixelColor(i+q, color) 39 | strip.show() 40 | time.sleep(wait_ms/1000.0) 41 | for i in range(0, strip.numPixels(), 3): 42 | strip.setPixelColor(i+q, 0) 43 | 44 | def wheel(pos): 45 | """Generate rainbow colors across 0-255 positions.""" 46 | if pos < 85: 47 | return Color(pos * 3, 255 - pos * 3, 0) 48 | elif pos < 170: 49 | pos -= 85 50 | return Color(255 - pos * 3, 0, pos * 3) 51 | else: 52 | pos -= 170 53 | return Color(0, pos * 3, 255 - pos * 3) 54 | 55 | def rainbow(strip, wait_ms=20, iterations=1): 56 | """Draw rainbow that fades across all pixels at once.""" 57 | for j in range(256*iterations): 58 | for i in range(strip.numPixels()): 59 | strip.setPixelColor(i, wheel((i+j) & 255)) 60 | strip.show() 61 | time.sleep(wait_ms/1000.0) 62 | 63 | def rainbowCycle(strip, wait_ms=20, iterations=5): 64 | """Draw rainbow that uniformly distributes itself across all pixels.""" 65 | for j in range(256*iterations): 66 | for i in range(strip.numPixels()): 67 | strip.setPixelColor(i, wheel((int(i * 256 / strip.numPixels()) + j) & 255)) 68 | strip.show() 69 | time.sleep(wait_ms/1000.0) 70 | 71 | def theaterChaseRainbow(strip, wait_ms=50): 72 | """Rainbow movie theater light style chaser animation.""" 73 | for j in range(256): 74 | for q in range(3): 75 | for i in range(0, strip.numPixels(), 3): 76 | strip.setPixelColor(i+q, wheel((i+j) % 255)) 77 | strip.show() 78 | time.sleep(wait_ms/1000.0) 79 | for i in range(0, strip.numPixels(), 3): 80 | strip.setPixelColor(i+q, 0) 81 | 82 | # Main program logic follows: 83 | if __name__ == '__main__': 84 | # Process arguments 85 | parser = argparse.ArgumentParser() 86 | parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit') 87 | args = parser.parse_args() 88 | 89 | # Create NeoPixel object with appropriate configuration. 90 | strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL) 91 | # Intialize the library (must be called once before other functions). 92 | strip.begin() 93 | 94 | print ('Press Ctrl-C to quit.') 95 | if not args.clear: 96 | print('Use "-c" argument to clear LEDs on exit') 97 | 98 | try: 99 | 100 | while True: 101 | print ('Color wipe animations.') 102 | colorWipe(strip, Color(255, 0, 0)) # Red wipe 103 | colorWipe(strip, Color(0, 255, 0)) # Blue wipe 104 | colorWipe(strip, Color(0, 0, 255)) # Green wipe 105 | print ('Theater chase animations.') 106 | theaterChase(strip, Color(127, 127, 127)) # White theater chase 107 | theaterChase(strip, Color(127, 0, 0)) # Red theater chase 108 | theaterChase(strip, Color( 0, 0, 127)) # Blue theater chase 109 | print ('Rainbow animations.') 110 | rainbow(strip) 111 | rainbowCycle(strip) 112 | theaterChaseRainbow(strip) 113 | 114 | except KeyboardInterrupt: 115 | if args.clear: 116 | colorWipe(strip, Color(0,0,0), 10) 117 | -------------------------------------------------------------------------------- /Chapter 7 - Line Following/line_follower.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | 3 | SPEED = 0.25 4 | 5 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 6 | 7 | left = gpiozero.DigitalInputDevice(9) 8 | right = gpiozero.DigitalInputDevice(11) 9 | 10 | while True: 11 | if (left.is_active == True) and (right.is_active == True): 12 | robot.forward(SPEED) 13 | elif (left.is_active == False) and (right.is_active == True): 14 | robot.right(SPEED) 15 | elif (left.is_active == True) and (right.is_active == False): 16 | robot.left(SPEED) 17 | else: 18 | robot.stop() 19 | -------------------------------------------------------------------------------- /Chapter 7 - Line Following/line_following_tiles/track_generator.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-raspberry-pi-guy/raspirobots/3819dd3a89ae5d66bced578f25ffbc627b07087f/Chapter 7 - Line Following/line_following_tiles/track_generator.pdf -------------------------------------------------------------------------------- /Chapter 7 - Line Following/line_test.py: -------------------------------------------------------------------------------- 1 | import gpiozero 2 | import time 3 | 4 | line_sensor = gpiozero.DigitalInputDevice(9) 5 | 6 | while True: 7 | if line_sensor.is_active == False: 8 | print("Line detected") 9 | else: 10 | print("No line detected") 11 | 12 | time.sleep(0.2) 13 | -------------------------------------------------------------------------------- /Chapter 8 - Computer Vision/ball_follower.py: -------------------------------------------------------------------------------- 1 | from picamera.array import PiRGBArray 2 | from picamera import PiCamera 3 | import cv2 4 | import numpy as np 5 | import gpiozero 6 | 7 | camera = PiCamera() 8 | image_width = 640 9 | image_height = 480 10 | camera.resolution = (image_width, image_height) 11 | camera.framerate = 32 12 | rawCapture = PiRGBArray(camera, size=(image_width, image_height)) 13 | center_image_x = image_width / 2 14 | center_image_y = image_height / 2 15 | minimum_area = 250 16 | maximum_area = 100000 17 | 18 | robot = gpiozero.Robot(left=(17,18), right=(27,22)) 19 | forward_speed = 0.3 20 | turn_speed = 0.25 21 | 22 | HUE_VAL = 28 23 | 24 | lower_color = np.array([HUE_VAL-10,100,100]) 25 | upper_color = np.array([HUE_VAL+10, 255, 255]) 26 | 27 | for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True): 28 | image = frame.array 29 | 30 | hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) 31 | 32 | color_mask = cv2.inRange(hsv, lower_color, upper_color) 33 | 34 | contours, hierarchy = cv2.findContours(color_mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) 35 | 36 | object_area = 0 37 | object_x = 0 38 | object_y = 0 39 | 40 | for contour in contours: 41 | x, y, width, height = cv2.boundingRect(contour) 42 | found_area = width * height 43 | center_x = x + (width / 2) 44 | center_y = y + (height / 2) 45 | if object_area < found_area: 46 | object_area = found_area 47 | object_x = center_x 48 | object_y = center_y 49 | if object_area > 0: 50 | ball_location = [object_area, object_x, object_y] 51 | else: 52 | ball_location = None 53 | 54 | if ball_location: 55 | if (ball_location[0] > minimum_area) and (ball_location[0] < maximum_area): 56 | if ball_location[1] > (center_image_x + (image_width/3)): 57 | robot.right(turn_speed) 58 | print("Turning right") 59 | elif ball_location[1] < (center_image_x - (image_width/3)): 60 | robot.left(turn_speed) 61 | print("Turning left") 62 | else: 63 | robot.forward(forward_speed) 64 | print("Forward") 65 | elif (ball_location[0] < minimum_area): 66 | robot.left(turn_speed) 67 | print("Target isn't large enough, searching") 68 | else: 69 | robot.stop() 70 | print("Target large enough, stopping") 71 | else: 72 | robot.left(turn_speed) 73 | print("Target not found, searching") 74 | 75 | rawCapture.truncate(0) 76 | -------------------------------------------------------------------------------- /Chapter 8 - Computer Vision/hsv_tester.py: -------------------------------------------------------------------------------- 1 | # import the necessary packages 2 | from picamera.array import PiRGBArray 3 | from picamera import PiCamera 4 | import time 5 | import cv2 6 | import numpy as np 7 | 8 | # initialize the camera and grab a reference to the raw camera capture 9 | camera = PiCamera() 10 | camera.resolution = (640, 480) 11 | camera.framerate = 32 12 | rawCapture = PiRGBArray(camera, size=(640, 480)) 13 | 14 | while True: 15 | while True: 16 | try: 17 | hue_value = int(input("Hue value between 10 and 245: ")) 18 | if (hue_value < 10) or (hue_value > 245): 19 | raise ValueError 20 | except ValueError: 21 | print("That isn't an integer between 10 and 245, try again") 22 | else: 23 | break 24 | 25 | lower_red = np.array([hue_value-10,100,100]) 26 | upper_red = np.array([hue_value+10, 255, 255]) 27 | 28 | for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True): 29 | image = frame.array 30 | 31 | hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) 32 | 33 | color_mask = cv2.inRange(hsv, lower_red, upper_red) 34 | 35 | result = cv2.bitwise_and(image, image, mask= color_mask) 36 | 37 | cv2.imshow("Camera Output", image) 38 | cv2.imshow("HSV", hsv) 39 | cv2.imshow("Color Mask", color_mask) 40 | cv2.imshow("Final Result", result) 41 | 42 | rawCapture.truncate(0) 43 | 44 | k = cv2.waitKey(5) #& 0xFF 45 | if "q" == chr(k & 255): 46 | break 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 the-raspberry-pi-guy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn Robotics with Raspberry Pi - Code Repository 2 | 3 | ![alt text](https://www.theraspberrypiguy.com/wp-content/uploads/2018/12/blank_3dbook_slider.png) 4 | 5 | ## Purchase Book: https://mybook.to/raspirobots (Amazon Worldwide Link) 6 | 7 | ## Book Description 8 | 9 | Learn Robotics with Raspberry Pi will take you from inexperienced maker to robot builder. You’ll start off building a two-wheeled robot powered by a Raspberry Pi minicomputer and then program it using Python, the world’s most popular programming language. Gradually, you’ll improve your robot by adding increasingly advanced functionality until it can follow lines, avoid obstacles, and even recognize objects of a certain size and color using computer vision. 10 | 11 | Learn how to: 12 | 13 | * Control your robot remotely using only a Wii remote 14 | * Teach your robot to use sensors to avoid obstacles 15 | * Program your robot to follow a line autonomously 16 | * Customize your robot with LEDs and speakers to make it light up and play sounds 17 | * See what your robot sees with a Pi Camera 18 | 19 | As you work through the book, you’ll learn fundamental electronics skills like how to wire up parts, use resistors and regulators, and determine how much power your robot needs. By the end, you’ll have learned the basics of coding in Python and know enough about working with hardware like LEDs, motors, and sensors to expand your creations beyond simple robots. 20 | 21 | Requirements: Raspberry Pi and Python 3 22 | 23 | ## Author Bio 24 | 25 | Matt Timmons-Brown runs the world’s most-popular Raspberry Pi YouTube channel, “The Raspberry Pi Guy” (www.youtube.com/theraspberrypiguy) with over 6 million views. Originally from Cambridge, UK, Matt is a Computer Science student at the University of Edinburgh and has worked for Amazon Robotics and Huawei. He is a Robotics Research Intern in the School of Informatics, Edinburgh. 26 | 27 | ## This repository? 28 | 29 | This repository stores all of the code and resources used in the book. It will be updated when necessary and if the code requires changes. 30 | 31 | ## How to download? 32 | 33 | You can download this code directly onto your Raspberry Pi with the terminal command: 34 | 35 | `git clone https://github.com/the-raspberry-pi-guy/raspirobots` 36 | 37 | Alternatively you can download this code locally by clicking on the "Clone or download" button at the top of the page. You will also find a zipped version of this code on the No Starch Press product page: https://nostarch.com/raspirobots 38 | 39 | ## Requirements/Recommendations 40 | 41 | This book is compatible with all models of Raspberry Pi. 42 | 43 | Recommended Pi Model: Raspberry Pi 3B+/3A+ or Pi Zero W (more efficient and lower power consumption) 44 | 45 | ## Reviews 46 | 47 | "Learn Robotics with Raspberry Pi" is currently rated 5* on Amazon, with 100+ 5* reviews. It has featured on several category best-selling lists. 48 | 49 | ## Erratum 50 | 51 | If you stumble upon any errors or incorrect parts of my book, please submit a PR to document them in this section, or send me an email for me to investigate into (theraspberrypiguy [at] gmail.com). Below is a list of known minor errata (page numbers from physical book). 52 | 53 | Errors fixed in the reprints of the book (as of Aug 2020): 54 | * Chapter 5, p115 - In the terminal prompt where I show the outputted distance metric from the HC-SR04 sensor, the command shown to have been run is ```python3 button.py``` whereas it should be the same as the previous page: ```python3 distance_test.py``` 55 | * Chapter 6, p140 - The ```wget``` links to the raw audio files are slightly different due to reorganisation of this Git repo. To download the audio files to your Pi, the commands should be: 56 | * ```wget https://github.com/the-raspberry-pi-guy/raspirobots/tree/master/Chapter%206%20-%20Adding%20RGB%20LEDs%20and%20Sound/sounds/beep.wav``` 57 | * ```wget https://github.com/the-raspberry-pi-guy/raspirobots/tree/master/Chapter%206%20-%20Adding%20RGB%20LEDs%20and%20Sound/sounds/horn.wav``` 58 | * Appendix: Resistor Guide, p203 - The example resistor calculation should result in a value of 560,000Ω (560kΩ), not 56,000Ω (56kΩ) 59 | 60 | Thanks to Minoosh Heidari & Daryoush Alipour for spotting these errors. 61 | 62 | Other errors: 63 | * Chapter 2, p35 - I state that the forward voltage of my LED is 2.5V, when in reality it was 3V. This then keeps the Ohm's law calculation on p36 consistent (it uses 3V for a forward voltage value, not 2.5V). 64 | 65 | Thanks to Kurt Werner for spotting this error. 66 | 67 | ## Parts List 68 | 69 | The following is an exhaustive list of the parts that I use in the book, Chapter by Chapter. I have tried to make things as cheap and accessible as possible. Please note that all parts are not required to follow the book, you can mix and match as you please, and do the Chapters that you feel would be of most interest! 70 | 71 | All of the electronic components in the book can be purchased from online shops like eBay, or dedicated online electronics stores such as Adafruit, Pimoroni, The Pi Hut, CPC Farnell, and RS Components. This list is by no means exhaustive and you may find cheaper, closer online retailers in your own country. You might even be fortunate enough to have a local electronics hardware store where you can grab your stuff! For this list, I have mixed and matched - let me know if any of the listings are unavailable and I will seek to update. 72 | 73 | ### Chapter 1: Getting Up and Running 74 | |Part |UK Link |USA Link | 75 | |--- |--- |--- | 76 | |Raspberry Pi 3 Model B+| https://thepihut.com/products/raspberry-pi-3-model-b-plus | https://www.adafruit.com/product/3775 | 77 | |8GB+ microSD card| https://thepihut.com/products/noobs-preinstalled-sd-card | https://www.adafruit.com/product/1294 | 78 | |HDMI cable/USB keyboard mouse | https://thepihut.com/products/official-raspberry-pi-hdmi-cable | https://www.adafruit.com/product/608 | 79 | |5V micro USB power adapter | https://thepihut.com/products/official-raspberry-pi-universal-power-supply | https://www.adafruit.com/product/1995 | 80 | 81 | ### Chapter 2: Electronics Basics 82 | |Part |UK Link |USA Link | 83 | |--- |--- |--- | 84 | |400 point breadboard| https://thepihut.com/products/raspberry-pi-breadboard-half-size | https://www.adafruit.com/product/4539 | 85 | |1x LED and appropriate resistor (for basic HW project)| https://thepihut.com/products/ultra-bright-led-5mm-white-10-pack | https://www.adafruit.com/product/754 | 86 | |Jumper wires (an assortment) | https://thepihut.com/pages/search-results?q=jumper%20wire&page_num=5 | https://www.adafruit.com/?q=jumper%20wires | 87 | |1x Momentary push button | https://thepihut.com/products/mini-push-button-switch-5-pcs | https://www.adafruit.com/product/367 | 88 | 89 | ### Chapter 3: Building Your Robot 90 | |Part |UK Link |USA Link | 91 | |--- |--- |--- | 92 | |Robot chassis (make out of what you wish - more details in the book!)| Lego, cardboard boxes | Plastic, wood etc! | 93 | |2x brushed 5V to 9V DC motors with tires | https://thepihut.com/products/dc-motor-3v-inc-gearbox-wheel-and-tyre | https://www.adafruit.com/product/3216 | 94 | |6xAA battery box | https://thepihut.com/products/panel-mount-battery-box-6x-aa-9v | https://ebay.to/3cGDS70 | 95 | |6x AA batteries (I recommend rechargeable, but can use disposable) | https://www.amazon.co.uk/s?k=6+rechargeable+battery+aa&ref=nb_sb_noss_1 | https://www.amazon.com/s?k=6+rechargeable+battery+aa&ref=nb_sb_noss_1 | 96 | |LM2596 buck converter module | https://bit.ly/2XFMaru | https://ebay.to/2Uf0cyw | 97 | |L293D motor driver chip | https://bit.ly/3f0OD5Z | https://ebay.to/3eS3IGE | 98 | 99 | ### Chapter 4: Making Your Robot Move 100 | |Part |UK Link |USA Link | 101 | |--- |--- |--- | 102 | |Official Nintendo Wiimote (Second-hand works great! Just not 3rd party)| https://bit.ly/3dHgpE9 | https://ebay.to/2XIubkB | 103 | 104 | ### Chapter 5: Obstacle Avoidance 105 | |Part |UK Link |USA Link | 106 | |--- |--- |--- | 107 | |HC-SR04 Ultrasonic Distance Sensor | https://thepihut.com/products/ultrasonic-distance-sensor-hcsr04 | https://www.adafruit.com/product/3942 | 108 | |1kΩ resistor and 2kΩ resistor (invest in a resistor assortment!) | https://bit.ly/379ajtR | https://ebay.to/2MDdh0h| 109 | 110 | ### Chapter 6: Adding RGB LEDs and Sound 111 | |Part |UK Link |USA Link | 112 | |--- |--- |--- | 113 | |NeoPixel stick with headers | https://thepihut.com/products/adafruit-neopixel-stick-8-x-5050-rgb-led-with-integrated-drivers | https://www.adafruit.com/product/1426 | 114 | |Small 3.5mm speaker | https://bit.ly/2APaJcw | https://ebay.to/2MEkahC| 115 | 116 | ### Chapter 7: Line Following 117 | |Part |UK Link |USA Link | 118 | |--- |--- |--- | 119 | |2x TCRT5000-based infrared line-following modules | https://bit.ly/2Y6Qors | https://ebay.to/2MxM8M8 | 120 | 121 | ### Chapter 8: Computer Vision: Follow a Colored Ball 122 | |Part |UK Link |USA Link | 123 | |--- |--- |--- | 124 | |Official Raspberry Pi camera module | https://thepihut.com/products/raspberry-pi-camera-module | https://www.adafruit.com/product/3099 | 125 | 126 | You also may find these tools/materials handy along the way: 127 | * Variety of screwdrivers 128 | * Hot-glue gun 129 | * Multimeter 130 | * Soldering iron 131 | * Wire stripper 132 | * Sticky tack/Velco/3M Dual Lock 133 | --------------------------------------------------------------------------------