├── README.md ├── diagrams ├── 11b_buzzer.fzz ├── 12_servo_pico.fzz ├── 13_adc_photoresistor.fzz ├── 14_seven_segment.fzz ├── 1_Circuit.fzz ├── 2_Circuit.fzz ├── 3_Circuit.fzz ├── 4_Circuit.fzz ├── 4_Circuit_bb.png ├── 5_button.fzz ├── 6_blink.fzz ├── 7_blink_external.fzz ├── 8_button_pico.fzz ├── Readme.md ├── game_1_lab.fzz ├── game_2_lab.fzz ├── game_3_lab.fzz ├── joystick 2.fzz ├── servo_with_led_pico.fzz └── turret6.fzz ├── game ├── bbgame.py ├── turret_laser_target.py └── uglygame.py ├── images ├── 11b_buzzer_bb.png ├── 12_servo_pico_bb.png ├── 13_adc_photoresistor_bb.png ├── 14_seven_segment_bb.png ├── 1_Circuit_bb.png ├── 2_Circuit_bb.png ├── 3_Circuit_bb.png ├── 4_Circuit_bb.png ├── 5_button_bb.png ├── 6_blink_bb.png ├── 7_blink_external_bb.png ├── 8_button_pico_bb.png ├── Circuit.png ├── GPIO_PWM-Table.webp ├── LED_SPECS.PNG ├── PICO_PIN_OUT.PNG ├── Pulse-Width-Modulation.jpg ├── Rasbnerry-Pi-Pico-Pinout-1-sideways.png ├── Readme.md ├── adcpins.PNG ├── button.jpg ├── button_bottom.jpg ├── buzzerbottom.jpg ├── buzzertop.jpg ├── final_lab_doodle.png ├── game_1_lab_bb.png ├── game_2_lab_bb.png ├── game_3_lab_bb.png ├── gamestage.png ├── joystick 2_bb.png ├── laser-diode.png ├── laser.png ├── photeresistor.png ├── pico.jpg ├── pulse-width-diagram.webp ├── redled.webp ├── resistor.png ├── servo_with_led_pico_bb.png ├── sg90-servo-horns.png ├── sg90.png ├── sg90_wires.PNG ├── shark_bottom.jpg ├── shark_side.jpg ├── switch_circuit.png ├── switch_circuit_on.png ├── target_back.jpg ├── target_full.jpg ├── target_zoom.jpg ├── thonny_pico.PNG ├── tm1637.jpeg ├── tm1637_back.jpg ├── trimpot.png └── turret6_bb.png ├── labs ├── 01_first_circuit.md ├── 02_resistor_intro.md ├── 03_photo_resistor.md ├── 04_potentiometer.md ├── 05_button_circuit.md ├── 06_blink_yo_self.md ├── 07_blink_led.md ├── 08_button_control.md ├── 09_button_debounce.md ├── 10_button_interrupt.md ├── 11_PWM_LED.md ├── 11b_Buzzer.md ├── 12_servo_control.md ├── 13_threading.md ├── 14_adc_photoresistor.md ├── 15_seven_segment.md ├── 16_button_led_reaction_time.md ├── Joystick_intro.md ├── f01_fire_zee_lasers.md ├── f02_sharks_with_lasers.md ├── f03_grand_finale.md └── turret.md ├── leds └── pwmfade.py ├── models ├── madscishark.3mf ├── picoin_v1.3mf ├── servocap.stl ├── shark.3mf ├── targetcap.3mf └── turret │ ├── Readme.md │ ├── TurretFinal-bottomCap.stl │ ├── TurretFinal-screwPegs.stl │ ├── TurretFinal-topArm.stl │ ├── TurretFinal-topServoMount.stl │ └── TurretFinal_baseBottomServoMount.stl ├── reference ├── breadboards.md ├── hackathon.md ├── part_description.md └── pico_gpio.md └── servos ├── scan.py ├── servo_class_sample.py ├── servosampleFull.py ├── sg90.py ├── sg90_class.py └── sg90sample.py /README.md: -------------------------------------------------------------------------------- 1 | # Pico Projects 2 | 3 | This is our amazing introduction to basic electronics and working with the Raspberry Pi Pico microcontroller. These lessons will help you bring code to life and release your inner mad scientist! 4 | 5 | ## Prerequisites 6 | 7 | Basically you just need the simple Python editor called Thonny which allows you write code on your laptop and execute it on the Pico via a USB cable. USB cables will be provided just make sure you have a laptop with Thonny installed and an available USB jack on your laptop. We will have a few USB C to USB A adapters for those with only tiny ports. We will not have Mac dongles so make sure you have a way to connect a USB A cable into your laptop. 8 | 9 | Please download and install the latest version(4.x or higher) of Thonny. 10 | [Download Thonny](https://thonny.org/) 11 | 12 | For these labs, you do NOT have to be a Python expert. You can probably get by fine without having ever done Python programming before. However, some general programming knowledge is required. As long as you are comfortable with basic programming constructs(IF/ELSE statements, For/While loops, etc...) in other languagues we will have enough of the code for you to figure out the Python bits. 13 | If you want to get a little familar with Python before coming you can check out this free tutorial get comfortable with Python. We will have code samples and links to reference materials if you just need to see how to do "normal" programming things in Python. 14 | [Python Tutorial](https://www.learnpython.org/) 15 | 16 | 17 | ## Are you Running a Hackathon 18 | 19 | If you are using this as part of a Hackathon or contest, check out our [Hackathon Guide](/reference/hackathon.md). 20 | 21 | ## Overview 22 | 23 | We start with a basic introduction to circuits and some basic electronics. So, the first several labs only use the Pico as a power source to introduce basic circuits and some electronic components we will be working with. Without this foundational knowledge, it will be difficult to build useful solutions that integrate code and electronics. 24 | 25 | If you aren't familar with how to use a breadboard, please take a moment and look at our introduction to them before starting the labs: [Introduction to Breadboards](/reference/breadboards.md) 26 | 27 | **NOTE on LABS** 28 | We provide working code for each lab, but you are welcome to try to code some of the stretch goals or solutions on your own once you get the hang of things. 29 | 30 | Many of the labs reference specific columns and rows to use when plugging in electronics. This is just to make it easier for beginners. The exact column and rows do not matter if you already understand how a breadboard works and know how to complete the circuit. If this is all brand new to this, you should follow our instructions exactly. But just know as you learn more about breadboards and circuits the exact location you plug things into the breadboard in many of the labs aren't important if you still complete the circuit. 31 | 32 | If you finish a lab quickly and see others that are struggling, **your stretch goal is to help a neighbor!** 33 | 34 | ## Optional Path 35 | 36 | Instead of going sequentially through the labs, you can instead use the [Parts Description](https://github.com/javaplus/PicoProjects/blob/main/reference/part_description.md) page to see a list of all the cool gadgets you can use to build a game and then choose your own adventure. 37 | 38 | ## Intro to Circuits. 39 | 40 | Simple circuit with LED using power from Pico and turn on LED. 41 | [Lab 1](/labs/01_first_circuit.md) 42 | 43 | ## Resistors. 44 | 45 | Same simple circuit from above and just add resistors to control the brightness of the LED. 46 | [Lab 2](/labs/02_resistor_intro.md) 47 | 48 | ## Variable Resistors (Photoresistor) 49 | 50 | Working with Light Sensitive Resistors. Also known as Photoresistors. 51 | [Lab 3](/labs/03_photo_resistor.md) 52 | 53 | ## Variable Resistor (Potentiometer) 54 | 55 | Use a Potentiometer to control brightness of LED. 56 | [Lab 4](/labs/04_potentiometer.md) 57 | 58 | ## Buttons/Switches 59 | 60 | Introduction to using Buttons/Switches with cicuits: 61 | [Lab 5](/labs/05_button_circuit.md) 62 | 63 | ## Use Code to Flash LED (First Lab with Pico and MicroPython) 64 | 65 | Finally, we will use code to light up LEDs: 66 | [Lab 6](/labs/06_blink_yo_self.md) 67 | [Lab 7](/labs/07_blink_led.md) 68 | 69 | 70 | ## Working with Buttons and the Pico 71 | 72 | Use the Pico to detect when a button is pressed. 73 | [Lab 8](/labs/08_button_control.md) 74 | [Lab 9](/labs/09_button_debounce.md) 75 | [Optional Game - Reaction Time Lab 16](/labs/16_button_led_reaction_time.md) 76 | [Lab 10](/labs/10_button_interrupt.md) 77 | 78 | 79 | 80 | ## Pulse Width Modulation (PWM) 81 | 82 | Explain PWM and use PWM to fade an LED in and out and control brightness. 83 | [Lab 11](/labs/11_PWM_LED.md) 84 | 85 | Buzzer lab with PWM. 86 | [Lab 11b](/labs/11b_Buzzer.md) 87 | 88 | ## PWM to Control Servos 89 | 90 | Use PWM to control a servo: 91 | [Lab 12](/labs/12_servo_control.md) 92 | 93 | ## Joystick and Turrets(Optional) 94 | [Joystick Lab](/labs/Joystick_intro.md) 95 | [Turret Lab](/labs/turret.md) 96 | 97 | ## Threading in MicroPython 98 | 99 | Threading on the Pico: 100 | [Lab 13](/labs/13_threading.md) 101 | 102 | 103 | ## Reading PhotoResistor Values 104 | 105 | Using Analog input with the Pico: 106 | [Lab 14](/labs/14_adc_photoresistor.md) 107 | 108 | ## Seven Segment Display 109 | 110 | Seven Segment Display: 111 | [Lab 15](/labs/15_seven_segment.md) 112 | 113 | 114 | ## Build the Laser Shooting Shark Game: 115 | [Final Lab 01](/labs/f01_fire_zee_lasers.md) 116 | [Final Lab 02](/labs/f02_sharks_with_lasers.md) 117 | [Final Lab 03](/labs/f03_grand_finale.md) 118 | 119 | 120 | 121 | ## References: 122 | #### Parts List 123 | - Pico, Pico H, or Pico W (Pico H is less work since it has pins soldered already) 124 | - Breadboard 125 | - Jumper Wires 126 | - LEDs 127 | - Button (push button switch) 128 | - micro USB cable 129 | - Active Buzzer 130 | - Photoresistor(5528, but others would work) 131 | - Resistors(220 Ohm, 10K Ohm) 2 of each 132 | - sg90 type mini servo 133 | - 10K Ohm Trim Potentiometer 134 | - 3D printed parts for final 3 game labs & paint stirring stick.[Models](https://github.com/javaplus/PicoProjects/tree/main/models) 135 | 136 | [Spreadsheet with Links where I ordered most parts](https://docs.google.com/spreadsheets/d/19XlUfh7XKboxZuTpR78YdXvtKbAR8O2FZtGRgrgSMsw/edit?usp=sharing) 137 | 138 | #### Python: 139 | - [While loops](https://www.geeksforgeeks.org/python-while-loop/) 140 | - [for loops](https://www.geeksforgeeks.org/python-for-loops/) 141 | - [if statements](https://www.geeksforgeeks.org/python3-if-if-else-nested-if-if-elif-statements/) 142 | - [time calculations/deltas](https://docs.micropython.org/en/latest/library/time.html#time.ticks_diff) 143 | 144 | #### Pico: 145 | 146 | - [Pico GPIO Pinout](/reference/pico_gpio.md) 147 | 148 | - [MicroPython RP Pico Library](https://docs.micropython.org/en/latest/rp2/quickref.html) 149 | - [RP2040 Datasheet](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf) 150 | ## 151 | -------------------------------------------------------------------------------- /diagrams/11b_buzzer.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/11b_buzzer.fzz -------------------------------------------------------------------------------- /diagrams/12_servo_pico.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/12_servo_pico.fzz -------------------------------------------------------------------------------- /diagrams/13_adc_photoresistor.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/13_adc_photoresistor.fzz -------------------------------------------------------------------------------- /diagrams/14_seven_segment.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/14_seven_segment.fzz -------------------------------------------------------------------------------- /diagrams/1_Circuit.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/1_Circuit.fzz -------------------------------------------------------------------------------- /diagrams/2_Circuit.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/2_Circuit.fzz -------------------------------------------------------------------------------- /diagrams/3_Circuit.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/3_Circuit.fzz -------------------------------------------------------------------------------- /diagrams/4_Circuit.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/4_Circuit.fzz -------------------------------------------------------------------------------- /diagrams/4_Circuit_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/4_Circuit_bb.png -------------------------------------------------------------------------------- /diagrams/5_button.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/5_button.fzz -------------------------------------------------------------------------------- /diagrams/6_blink.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/6_blink.fzz -------------------------------------------------------------------------------- /diagrams/7_blink_external.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/7_blink_external.fzz -------------------------------------------------------------------------------- /diagrams/8_button_pico.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/8_button_pico.fzz -------------------------------------------------------------------------------- /diagrams/Readme.md: -------------------------------------------------------------------------------- 1 | # Fritzing files 2 | -------------------------------------------------------------------------------- /diagrams/game_1_lab.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/game_1_lab.fzz -------------------------------------------------------------------------------- /diagrams/game_2_lab.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/game_2_lab.fzz -------------------------------------------------------------------------------- /diagrams/game_3_lab.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/game_3_lab.fzz -------------------------------------------------------------------------------- /diagrams/joystick 2.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/joystick 2.fzz -------------------------------------------------------------------------------- /diagrams/servo_with_led_pico.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/servo_with_led_pico.fzz -------------------------------------------------------------------------------- /diagrams/turret6.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/diagrams/turret6.fzz -------------------------------------------------------------------------------- /game/bbgame.py: -------------------------------------------------------------------------------- 1 | from machine import Pin,PWM,ADC 2 | from math import modf 3 | import utime, sg90, _thread, tm1637, sys 4 | 5 | photoresistor_value = machine.ADC(28) 6 | 7 | initial_photo_reading = photoresistor_value.read_u16() 8 | print("Initial Laser Voltage Reading: ", initial_photo_reading) 9 | 10 | # target will recognize a hit when there is a 20% increase in light 11 | target_reading = initial_photo_reading * 1.2 # TODO - potentially need a different percentage based on laser and photores being used 12 | print("Target Goal Lighting: ", target_reading) 13 | 14 | # Initialize LEDs to on at beginning 15 | # These LEDs indicate lives remaining 16 | led1 = Pin(16, Pin.OUT) 17 | led1.value(1) 18 | led1_on = True 19 | led2 = Pin(18, Pin.OUT) 20 | led2.value(1) 21 | led2_on = True 22 | led3 = Pin(19, Pin.OUT) 23 | led3.value(1) 24 | led3_on = True 25 | lives_left = True 26 | 27 | laser = Pin(20, Pin.OUT) 28 | laser.value(0) 29 | 30 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 31 | 32 | # Initialize Score and Display 33 | display = tm1637.TM1637(clk=Pin(1), dio=Pin(0)) 34 | score = 0 35 | display.number(score) 36 | 37 | # Initialize Servo 38 | sg90.servo_pin(15) 39 | SMOOTH_TIME = 80 40 | servo_speed = 1 41 | 42 | # flag so the laser can interrupt the scan cycle 43 | kill_flag = False 44 | 45 | # debounce utime saying wait 5 seconds between button presses 46 | DEBOUNCE_utime = 5000 47 | 48 | # debounce counter is our counter from the last button press 49 | # initialize to current utime 50 | debounce_counter = utime.ticks_ms() 51 | 52 | def scan(servo): 53 | stepping = servo_speed 54 | for i in range(45,130, stepping): 55 | if (kill_flag): 56 | break 57 | servo.move_to(i) 58 | utime.sleep_ms(SMOOTH_TIME) 59 | 60 | for i in range(130,45, -stepping): 61 | if (kill_flag): 62 | break 63 | servo.move_to(i) 64 | utime.sleep_ms(SMOOTH_TIME) 65 | 66 | # define a function to execute in the second thread 67 | def second_thread_func(): 68 | while True: 69 | # fix for import failing in second thread when it's inside a function 70 | servo = sg90 71 | stepping = servo_speed 72 | scan(servo) 73 | #print("servo_speed=", servo_speed) 74 | utime.sleep_ms(100) 75 | 76 | # Start the second thread 77 | _thread.start_new_thread(second_thread_func,()) 78 | 79 | # Function to handle darkening one LED 80 | def remove_led(): 81 | global led3_on, led3, led2_on, led2, led1_on, led1, lives_left 82 | if(led3_on): 83 | led3.value(0) 84 | led3_on = False 85 | else: 86 | if(led2_on): 87 | led2.value(0) 88 | led2_on = False 89 | else: 90 | led1.value(0) 91 | led1_on = False 92 | lives_left = False 93 | end_of_game_buzz() 94 | 95 | # Function to handle when the button is pressed 96 | def button_press_detected(): 97 | global debounce_counter 98 | current_utime = utime.ticks_ms() 99 | 100 | # Calculate utime passed since last button press 101 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 102 | 103 | # print("utime passed=" + str(utime_passed)) 104 | if (utime_passed > DEBOUNCE_utime): 105 | print("Button Pressed!") 106 | # set debounce_counter to current utime 107 | debounce_counter = utime.ticks_ms() 108 | 109 | fire_the_laser() 110 | #else: 111 | #print("Not enough utime") 112 | 113 | def fire_the_laser(): 114 | print("FIRE ZEE LASERS!") 115 | global servo_speed 116 | 117 | enable_laser() 118 | check_target() 119 | disable_laser() 120 | 121 | if (photo_reading > target_reading): 122 | its_a_hit() 123 | else: 124 | its_a_miss() 125 | 126 | def enable_laser(): 127 | global kill_flag 128 | kill_flag = True 129 | laser.value(1) 130 | utime.sleep_ms(2000) 131 | 132 | def disable_laser(): 133 | global kill_flag 134 | utime.sleep_ms(1000) 135 | kill_flag = False 136 | laser.value(0) 137 | 138 | def check_target(): 139 | global photo_reading 140 | photo_reading = photoresistor_value.read_u16() 141 | print("Laser Voltage Reading: ",photo_reading) 142 | 143 | def increase_difficulty(): 144 | global servo_speed 145 | servo_speed = servo_speed + 1 146 | 147 | def increase_score(): 148 | global score 149 | score = score + 1 150 | 151 | def display_score(): 152 | display.number(score) 153 | 154 | def its_a_hit(): 155 | print("Nice! - A Hit!") 156 | happy_buzz() 157 | increase_difficulty() 158 | increase_score() 159 | display_score() 160 | print("Score: ", score) 161 | 162 | def its_a_miss(): 163 | print("Ouch - A Miss!") 164 | sad_buzz() 165 | remove_led() 166 | 167 | def happy_buzz(): 168 | print("Time to get buzzed!") # TODO - this method 169 | 170 | def sad_buzz(): 171 | print("Time to get buzzed!") # TODO - this method 172 | 173 | def end_of_game_buzz(): 174 | print("Time to get buzzed!") # TODO - this method 175 | 176 | # Below executes in the main(first) thread. 177 | while True: 178 | if (lives_left): 179 | if button.value()==True: 180 | button_press_detected() 181 | else: 182 | print("Game Over!") 183 | kill_flag = True 184 | laser.value(1) 185 | sys.exit() 186 | -------------------------------------------------------------------------------- /game/turret_laser_target.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, ADC 2 | import utime 3 | from turret import turret 4 | 5 | laser = Pin(16, Pin.OUT) 6 | 7 | laser.value(1) 8 | 9 | led = Pin(13, Pin.OUT) 10 | 11 | photoresistor_value = machine.ADC(28) 12 | 13 | SMOOTH_TIME = (20) 14 | 15 | xAxis = ADC(Pin(27)) 16 | yAxis = ADC(Pin(26)) 17 | button = Pin(17,Pin.IN, Pin.PULL_UP) 18 | 19 | #turret(servoXpin, servoYpin) 20 | myturret = turret(15,14) 21 | 22 | while True: 23 | xValue = xAxis.read_u16() 24 | yValue = yAxis.read_u16() 25 | buttonValue = button.value() 26 | photo_reading = photoresistor_value.read_u16() 27 | 28 | #recenters both servos 29 | if buttonValue == 0: 30 | myturret.center() 31 | 32 | #Adjust x and y values based on sensitivity of your joystick 33 | #myturret.move_(direction)(movement_speed) 34 | if xValue <= 48000: 35 | myturret.move_right(1) 36 | 37 | if photo_reading <= 15000: 38 | led.value(1) 39 | 40 | if not photo_reading <= 15000: 41 | led.value(0) 42 | 43 | if xValue >= 54000: 44 | myturret.move_left(1) 45 | 46 | if yValue <=46500: 47 | myturret.move_up(1) 48 | 49 | if yValue >= 54000: 50 | myturret.move_down(1) 51 | 52 | utime.sleep_ms(SMOOTH_TIME) 53 | -------------------------------------------------------------------------------- /game/uglygame.py: -------------------------------------------------------------------------------- 1 | from machine import Pin,PWM 2 | import utime 3 | import _thread 4 | import sg90 5 | 6 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) # potential TODO - change PIN of button 7 | # debounce utime saying wait 3 seconds between button presses 8 | DEBOUNCE_utime = 3000 9 | 10 | # debounce counter is our counter from the last button press 11 | # initialize to current utime 12 | debounce_counter = utime.ticks_ms() 13 | 14 | # Initialize LASER 15 | laser = Pin(16, Pin.OUT) 16 | 17 | photoresistor_value = machine.ADC(28) # potential TODO - change PIN of photores 18 | conversion_factor = 3.3/(65535) 19 | 20 | 21 | laser.value(0) 22 | firing_flag = False 23 | firing_start_time = 0 24 | 25 | # Initiliaze Servo 26 | sg90.servo_pin(15) 27 | SMOOTH_TIME = 20 28 | servo_speed = 1 29 | score = 0 30 | 31 | lives_left = True 32 | 33 | def its_a_hit(): 34 | # TODO - happy buzzer buzz 35 | global servo_speed, score 36 | print("HIT!!!!!!!!!!!!!!!!!!!!!!!!!!!") 37 | servo_speed = servo_speed + 1 38 | score = score + 1 39 | #display.number(score) 40 | 41 | def its_a_miss(): 42 | # TODO - sad buzzer buzz 43 | #remove_led() 44 | print("Missed!") 45 | 46 | def get_target_value(): 47 | photo_reading = photoresistor_value.read_u16() * conversion_factor 48 | return photo_reading 49 | 50 | def check_target_hit(photo_reading, initial_photo_reading): 51 | variance = 1 # TODO - figure out proper variance for shot logic 52 | 53 | if (photo_reading > (initial_photo_reading + variance)): 54 | its_a_hit() 55 | else: 56 | its_a_miss() 57 | 58 | 59 | # Function to handle when the button is pressed 60 | def button_press_detected(): 61 | global debounce_counter, firing_flag, firing_start_time 62 | current_utime = utime.ticks_ms() 63 | # Calculate utime passed since last button press 64 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 65 | #print("utime passed=" + str(utime_passed)) 66 | if (utime_passed > DEBOUNCE_utime): 67 | print("Button Pressed!") 68 | # set debounce_counter to current utime 69 | debounce_counter = utime.ticks_ms() 70 | 71 | laser.value(1) # TODO - no idea if this logic is right for firing the laser 72 | firing_flag = True 73 | firing_start_time = utime.ticks_ms() 74 | 75 | #else: 76 | # print("Not enough utime") 77 | 78 | 79 | def scan(servo): 80 | stepping = servo_speed 81 | for i in range(90,130, stepping): 82 | servo.move_to(i) 83 | utime.sleep_ms(SMOOTH_TIME) 84 | 85 | for i in range(130,89, -stepping): 86 | servo.move_to(i) 87 | utime.sleep_ms(SMOOTH_TIME) 88 | 89 | 90 | for i in range(90,45,-stepping): 91 | servo.move_to(i) 92 | utime.sleep_ms(SMOOTH_TIME) 93 | 94 | for i in range(45,91, stepping): 95 | servo.move_to(i) 96 | utime.sleep_ms(SMOOTH_TIME) 97 | 98 | 99 | # define a function to execute in the second thread 100 | def second_thread_func(): 101 | while True: 102 | # fix for import failing in second thread when it's inside a function 103 | servo = sg90 104 | stepping = servo_speed 105 | scan(servo) 106 | print("servo_speed=", servo_speed) 107 | utime.sleep_ms(100) 108 | 109 | # Start the second thread 110 | _thread.start_new_thread(second_thread_func,()) 111 | 112 | # every 5 second increase servo speed 113 | last_time_checked = utime.ticks_ms() 114 | def set_servo_speed(): 115 | global last_time_checked 116 | diff_time = utime.ticks_diff(utime.ticks_ms(), last_time_checked) 117 | if(diff_time > 5000): 118 | last_time_checked = utime.ticks_ms() 119 | return (servo_speed + 1) 120 | else: 121 | return servo_speed 122 | 123 | current_target_value = 0 124 | highest_target_value = 0 125 | firing_time_ms = 0 126 | firing_time_limit_ms = 500 127 | ## get initial value from target 128 | initial_photo_reading = get_target_value() 129 | utime.sleep_ms(1000) 130 | print("Initial Voltage Reading: ",initial_photo_reading) 131 | 132 | # Below executes in the main(first) thread. 133 | 134 | try: 135 | 136 | while True: 137 | if (lives_left): 138 | if button.value()==True: 139 | button_press_detected() 140 | if(firing_flag == True): 141 | firing_time_ms = utime.ticks_ms() - firing_start_time 142 | current_target_value = get_target_value() 143 | if(current_target_value > highest_target_value): 144 | highest_target_value = current_target_value 145 | #print("firing_time=",firing_time_ms) 146 | if(firing_time_ms > firing_time_limit_ms): 147 | print("highest target value=", highest_target_value) 148 | firing_flag = False 149 | firing_time_ms = 0 150 | laser.value(0) 151 | check_target_hit(highest_target_value, initial_photo_reading) 152 | highest_target_value = 0 153 | 154 | else: 155 | print("YOu dead") 156 | except Exception as e: 157 | ## TODO Handle exception 158 | print("Exception",e) 159 | except KeyboardInterrupt as ki: 160 | ## TODO Handle exception (kill second thread) 161 | print("keyboard Interrupt", ki) 162 | 163 | 164 | -------------------------------------------------------------------------------- /images/11b_buzzer_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/11b_buzzer_bb.png -------------------------------------------------------------------------------- /images/12_servo_pico_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/12_servo_pico_bb.png -------------------------------------------------------------------------------- /images/13_adc_photoresistor_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/13_adc_photoresistor_bb.png -------------------------------------------------------------------------------- /images/14_seven_segment_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/14_seven_segment_bb.png -------------------------------------------------------------------------------- /images/1_Circuit_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/1_Circuit_bb.png -------------------------------------------------------------------------------- /images/2_Circuit_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/2_Circuit_bb.png -------------------------------------------------------------------------------- /images/3_Circuit_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/3_Circuit_bb.png -------------------------------------------------------------------------------- /images/4_Circuit_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/4_Circuit_bb.png -------------------------------------------------------------------------------- /images/5_button_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/5_button_bb.png -------------------------------------------------------------------------------- /images/6_blink_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/6_blink_bb.png -------------------------------------------------------------------------------- /images/7_blink_external_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/7_blink_external_bb.png -------------------------------------------------------------------------------- /images/8_button_pico_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/8_button_pico_bb.png -------------------------------------------------------------------------------- /images/Circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/Circuit.png -------------------------------------------------------------------------------- /images/GPIO_PWM-Table.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/GPIO_PWM-Table.webp -------------------------------------------------------------------------------- /images/LED_SPECS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/LED_SPECS.PNG -------------------------------------------------------------------------------- /images/PICO_PIN_OUT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/PICO_PIN_OUT.PNG -------------------------------------------------------------------------------- /images/Pulse-Width-Modulation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/Pulse-Width-Modulation.jpg -------------------------------------------------------------------------------- /images/Rasbnerry-Pi-Pico-Pinout-1-sideways.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/Rasbnerry-Pi-Pico-Pinout-1-sideways.png -------------------------------------------------------------------------------- /images/Readme.md: -------------------------------------------------------------------------------- 1 | ## Place for images 2 | -------------------------------------------------------------------------------- /images/adcpins.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/adcpins.PNG -------------------------------------------------------------------------------- /images/button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/button.jpg -------------------------------------------------------------------------------- /images/button_bottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/button_bottom.jpg -------------------------------------------------------------------------------- /images/buzzerbottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/buzzerbottom.jpg -------------------------------------------------------------------------------- /images/buzzertop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/buzzertop.jpg -------------------------------------------------------------------------------- /images/final_lab_doodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/final_lab_doodle.png -------------------------------------------------------------------------------- /images/game_1_lab_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/game_1_lab_bb.png -------------------------------------------------------------------------------- /images/game_2_lab_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/game_2_lab_bb.png -------------------------------------------------------------------------------- /images/game_3_lab_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/game_3_lab_bb.png -------------------------------------------------------------------------------- /images/gamestage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/gamestage.png -------------------------------------------------------------------------------- /images/joystick 2_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/joystick 2_bb.png -------------------------------------------------------------------------------- /images/laser-diode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/laser-diode.png -------------------------------------------------------------------------------- /images/laser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/laser.png -------------------------------------------------------------------------------- /images/photeresistor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/photeresistor.png -------------------------------------------------------------------------------- /images/pico.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/pico.jpg -------------------------------------------------------------------------------- /images/pulse-width-diagram.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/pulse-width-diagram.webp -------------------------------------------------------------------------------- /images/redled.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/redled.webp -------------------------------------------------------------------------------- /images/resistor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/resistor.png -------------------------------------------------------------------------------- /images/servo_with_led_pico_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/servo_with_led_pico_bb.png -------------------------------------------------------------------------------- /images/sg90-servo-horns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/sg90-servo-horns.png -------------------------------------------------------------------------------- /images/sg90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/sg90.png -------------------------------------------------------------------------------- /images/sg90_wires.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/sg90_wires.PNG -------------------------------------------------------------------------------- /images/shark_bottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/shark_bottom.jpg -------------------------------------------------------------------------------- /images/shark_side.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/shark_side.jpg -------------------------------------------------------------------------------- /images/switch_circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/switch_circuit.png -------------------------------------------------------------------------------- /images/switch_circuit_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/switch_circuit_on.png -------------------------------------------------------------------------------- /images/target_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/target_back.jpg -------------------------------------------------------------------------------- /images/target_full.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/target_full.jpg -------------------------------------------------------------------------------- /images/target_zoom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/target_zoom.jpg -------------------------------------------------------------------------------- /images/thonny_pico.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/thonny_pico.PNG -------------------------------------------------------------------------------- /images/tm1637.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/tm1637.jpeg -------------------------------------------------------------------------------- /images/tm1637_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/tm1637_back.jpg -------------------------------------------------------------------------------- /images/trimpot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/trimpot.png -------------------------------------------------------------------------------- /images/turret6_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/images/turret6_bb.png -------------------------------------------------------------------------------- /labs/01_first_circuit.md: -------------------------------------------------------------------------------- 1 | # Creating Your First Circuit 2 | 3 | To create your first circuit, we first want to understand what a circuit is. A circuit is just path for electricity to flow. 4 | In a typical circuit, electricity flows from a battery or some power source through wires and into something that converts electricity to some other form of energy. 5 | 6 | The first circuit we will build will be to power a simple light (LED). 7 | 8 | ![Basic Circuit](/images/Circuit.png) 9 | 10 | An important part of a working circuit is to make sure the circuit is complete or closed. That is when there is a connection from the battery or power sources positive terminal through the light and to the ground(negative). Electricity flows from the positive terminal to the ground(negative) and if there is a break or disconnect in the circuit then the circuit is "open" and therefore no electricity is flowing and your light won't shine. 11 | 12 | ## What we will build 13 | 14 | The first circuit is to simply power an LED. A LED is a Light Emitting Diode. A Diode only allows electricity to flow in one direction. So, there is a positive and negative side to the LED. Typically the longer leg of the LED is the positive side. 15 | 16 | 17 | So, we will simply hook our power source to our bread board and then connect the power to the LED in the appropriate way. 18 | 19 | ## What to do: 20 | 21 | As mentioned above, a completed circuit needs to go from a positive power source to a negative or ground terminal. For the first few labs, we are going to use the Pico only as a power source. 22 | 23 | We will now connect the power rails of the breadboard to the Raspberry Pi Pico. 24 | 25 | 26 | NOTE: Technically the color of wires you use don't matter (internally they are the same), but the color does make it easier to know the purpose. Usually, red wires indicate positive(+) and black or white wires indicate ground/negative(-). On the breadboard, the blue line represents the ground/negative power strip and the red/pink line indicates the positive side. 27 | 28 | ##### Orientation 29 | 30 | It will be easiest if you orient your breadboard as seen below in the [wiring diagram](#wiring-diagram). 31 | The USB connection should be to the left and on the left edge of the breadboard you should see letters A through J going from the bottom up with J being at the top. Across the breadboard left to right you should see numbers indicating the columns of pins starting at 1 and then counting by 5's across the board. 32 | 33 | 34 | **NOTE** If you recieved a kit for these labs, the ground and positive wires may already be placed for you. 35 | ##### Ground (negative) 36 | 37 | We will start by connecting one of the ground pins on the Pico to the top ground(-) rail of the breadboard. To do this run a black wire from Pin 3 in Row I or J to the negative rail(ground) on the bread board. 38 | 39 | ##### Positive(positive) 40 | Now to connect the positive side of the power rail, run a red wire from Pin 5 Row I or J to the top positive(red) rail. Pin 5 on the Pico here is a 3.3Volt output pin. So, if the Pico is powered up it will be producing 3.3Volts of power. 41 | 42 | 43 | ##### LED 44 | 45 | Now take your **BLUE** LED and connect it to the breadboard plugging the slightly longer leg into Pin 30 and the shorter leg into Pin 31 (preferably in Row F) 46 | 47 | Now run a red wire from Pin 30 (any Row G-J) to the positive power rail at the top. Now connect the shorter leg of the LED to ground, by running a black wire from Pin 31 (any Row G-J) to the top Ground(negative) rail. 48 | 49 | ##### Test IT! 50 | Once everything is wired, if you plug in your Pico via the USB cable, you should see the LED light up. 51 | 52 | When you have light, rejoice! You've just made the world a little brighter literally! :) 53 | 54 | If it works do a slow nod of satisfaction. 55 | 56 | 57 | #### Follow Up and Troubleshooting: 58 | 59 | It's important to always make sure you have a closed circuit... that is does the electricty have a path from the positive terminal of the power source to the negative/ground. Especially when troubleshooting issues, you want to trace the route from the positive terminal(in our case Pin 5 of the Pico) through each wire and component to make sure it has a path to go to ground. 60 | 61 | Get used to always visually tracing this flow through your breadboard to make sure you verify the circuit is closed. An open circuit means electricity can't flow and nothing will work. 62 | 63 | ## Wiring Diagram 64 | (*NOTE*)If you recieved a kit for these labs, there may be extra wires on your breadboard to provide power to the bottom power rails of the breadboard. Don't remove these wires, just add the two wires and the LED to the right of the Pico. 65 | 66 | ![Basic LED Wiring Diagram](/images/1_Circuit_bb.png) 67 | 68 | 69 | 70 | ### Resources: 71 | 72 | [In depth How a Breadboard Works](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/all) 73 | -------------------------------------------------------------------------------- /labs/02_resistor_intro.md: -------------------------------------------------------------------------------- 1 | # Resistors 2 | 3 | ## Overview 4 | 5 | From the previous lab, you should see your Blue LED is very bright. We know that we are getting power from the 3.3V pin from Pico. But what we didn't talk about was the voltage rating of the LED. Let's look at the Voltage rating and other specifications for the LEDs in our kit: 6 | 7 | ##### LED Specification Table 8 | ![LED Specs](/images/LED_SPECS.PNG) 9 | 10 | 11 | Our LED's (like most electronics) have voltage ranges in which they are designed to run. As mentioned above, we are currently running off 3.3Volts, but if we look again at the specifciations for the LEDs, we will see we are actually running a little over the specified voltage range of 3.0 to 3.2V for our Blue LED. This is why it's so bright. It's running slightly above max power! 12 | 13 | Notice that the WHITE, BLUE, and GREEN LEDS support up to 3.2Volts. The other LEDs (RED and YELLOW) only support upto 2.2Volts. So, if we tried to use a Red or Yellow LED with our current circuit we could burn them out. 14 | 15 | Since we are barely over spec with our Blue LED we most likely won't have an issue, but it would be safer for the lifespan of the LED to run at a lower voltage. 16 | 17 | 18 | ## Resistors 19 | 20 | One simple way to lower the voltage in a circuit is to use a resistor. A resistor simply resists(or restricts) the flow of electricity. So, by adding a resistor into our circuit we will drop our voltage to a safer level. 21 | 22 | Resistance is measured in Ohms. The higher the Ohms the more resistance. You should have at least 2 resistors in your kit. We will try them both to determine which has the most resistance. 23 | 24 | Resistors as seen in the image below have two legs. These legs are not polarized... meaning it doesn't matter which leg plugs into what part of the circuit. as long as the legs are used to complete a circuit, the body in the middle will resist the flow of electron flow. 25 | 26 | ###### Resistor 27 | ![Resistor image](/images/resistor.png) 28 | 29 | 30 | 31 | ## What to do 32 | 33 | For our simple LED circuit it doesn't matter if we add the resistor to the positive side or the negative side because it will restrict the flow for the whole circuit. However, we will simply replace our Red wire connecting the long leg of the LED to the positive rail with a resistor. 34 | 35 | So, remove the red wire connecting the positve rail to Pin 30 (long side of the LED). Replace that wire with one of the resistors in your kit. It doesn't matter which resisitor at this point. 36 | 37 | Once you connect the resistor, you should see the LED light up again, but be dimmer. 38 | Swap out the resistor with another one in your kit and see if it gets even dimmer or brighter. Can you tell by the brightness level which resistor has the most resistance(more Ohms)? 39 | 40 | If it works pat yourself on the back. 41 | 42 | ![Resistor Circuit](/images/2_Circuit_bb.png) 43 | 44 | ### More Information 45 | 46 | While we tried to figure out which resistor had more resistance by just trying it in a circuit with an LED, it's typically required to KNOW the amount of resistance needed in your circuit and then choose the correct resistor. If you don't know the value of a resistor, you can use a Volt Meter set to the Ohms setting to read the exact Ohms level for the resistor. This is the easiest way. You can also use the color bands on the resistors to determine the resistance level. This can be complicated as some colors are hard to distinguish, but there is a neat resistor calculator that allows you to enter the color bands to tell you the resistance: [Resistor Calculator](https://www.digikey.com/en/resources/conversion-calculators/conversion-calculator-resistor-color-code) 47 | 48 | Another resistor calculator and explanation of the color bands: [Resistor Calculator and Description](https://www.utmel.com/tools/band-resistor-color-code-calculator?id=20) 49 | -------------------------------------------------------------------------------- /labs/03_photo_resistor.md: -------------------------------------------------------------------------------- 1 | # Photo Resistors 2 | 3 | ## Overview 4 | 5 | From the previous lab on resistors, you should understand how resistors play a valuable role in electronics by limiting or resisting the flow of electricity which we could see in our LED dimming. The resistors we used to this point provided a fixed amount of resistence, therefore, each resistor has had a specific Ohms rating. However, now in this lab we will work with a type of variable resistor... the Photoresistor 6 | 7 | ## Photresistor 8 | 9 | A Photoresistor(pictured below) is a type of variable resistor that provides some level of resistance that varies as the amount of light shining on it varies. That is as more light shines on the photoresistor, the less resistence it provides. So, in a dark environment the photoresistor will provide more resistence than when light is shining on it. 10 | 11 | ![Photoresistor image](/images/photeresistor.png) 12 | 13 | ## What to do 14 | 15 | For this lab, we will simply replace the resistor in our circuit with our photoresistor. So simply remove the resistor that connects the long side of the LED currently in column 30 to the power rail. Now add the photoresistor in place of it. Connect one side of the photoresistor leg to Column 30 and the other side to the positive power rail. The legs of the photoresistor can go either way. 16 | 17 | Once you have the photo resistor in place, try covering the photoresistor with your finger and see if the light dims. Then remove your finger from the top of the photoresistor and see if the LED brightens. 18 | 19 | Now you have a variable resistor in place! We can use variable resistors in the future as analog input devices. That is they are not digital where they provide a binary value, but analog in the fact they can provide a range of values that vary. Don't worry too much about this for now, but just have fun playing with your photoresistor... for fun shine a bright light(light from your phone) on the photoresistor and see if you can get your LED really bright. 20 | 21 | If it works let out a quiet "Oh Yeah!". 22 | 23 | 24 | ![Resistor Circuit](/images/3_Circuit_bb.png) 25 | -------------------------------------------------------------------------------- /labs/04_potentiometer.md: -------------------------------------------------------------------------------- 1 | # Potentiometer 2 | 3 | ## Overview 4 | 5 | We used our first type of variable resistor in the last lab when we used the Photoresistor. In this lab we will use another type of variable resistor the Potentiometer. 6 | 7 | ## Potentiometer 8 | 9 | A Potentiometer(pictured below) is a type of variable resistor that provides a different level of resistence based on the position of the knob. By turning the knob ontop of the potentiometer, you can vary the resistence it provides. The type of Potentiometer we are using is often referred to a as a trim potentiometer or "trim pot" for short. 10 | 11 | ![Potentiometer image](/images/trimpot.png) 12 | 13 | ## What to do 14 | 15 | For this lab, we will replace the photoresistor in our circuit with our potentiometer. So remove the photoresistor that connects the long side of the LED currently in column 30 to the power rail. 16 | 17 | Add the potentiometer to the breadboard making sure the side with the slots are near the middle section of the breadboard. Make sure the 3 pins of the potentiometer are in different columns. The far right pin when looking at the slots should go into the breadboard at Row G and column 25. This should position the middle pin into the breadboard at Row F and column 24. 18 | 19 | With the potentiometer in place, connect the far left pin to our power rail. So, that should mean connecting a wire from the positive power rail to Column 23. 20 | Now connect the middle pin of the potentiometer which is in column 24 to the long leg of the LED in column 30. Now connect the last pin (far right pin) of the potentiometer to ground. That is run a wire from Column 25 to the ground(negative) rail. 21 | 22 | If everything is connected properly you should be able to twist the knob ontop of the potentiometer and see the LED dim and brighten. 23 | 24 | If it works high five someone nearby. 25 | 26 | ![Resistor Circuit](/images/4_Circuit_bb.png) -------------------------------------------------------------------------------- /labs/05_button_circuit.md: -------------------------------------------------------------------------------- 1 | # Button/Switch 2 | 3 | ## Overview 4 | 5 | Now we will show how to use a simple button or momentary switch to keep the circuit open until you press the button. So, when you finish this lab, the LED should only light up when you hold in the button. 6 | 7 | ## How a Switch Works 8 | 9 | A button or switch is simply a way to close a circuit (allow electricity to flow) with a mechanical device. The easiest way to think of a button or switch is just a piece of metal that connects two leads(wires). See the picture below: 10 | 11 | ##### Open Circuit Image 12 | ![Switch Circuit Off](/images/switch_circuit.png) 13 | 14 | In the circuit above, you see the switch is just a metal bar that in it's current state would not allow the electrcity to flow. The blue wire from the battery pack connects to one side of the metal switch, but while it's up, the current cannot flow to the blue wire on the other side. But if the bar was pushed down(as in the picture below) it would connect the two blue wires which would close or complete the circuit and allow electricity to flow and the light would light up. 15 | ##### Closed Circuit Image 16 | ![Switch Circuit On](/images/switch_circuit_on.png) 17 | 18 | ## Our Buttons 19 | 20 | The buttons we are using for this lab are called momentary switches or push buttons or some combination of those terms. 21 | 22 | ![Button image](/images/button.jpg) 23 | 24 | The idea is that if you connect power to one side of the button and then the otherside connects to the rest of your circuit then electricity can only flow while you press the button down. 25 | 26 | 27 | ## What to do 28 | 29 | For this lab, we will replace the potentiometer with a button. You will no longer have resistance so your light will be super bright, but only while you press the button down. 30 | 31 | Remove the black ground wire that was connecting your potentiometer to the ground/negative rail and remove the Potentiometer altogether. 32 | 33 | Take your button and place the two right side pins into column 25. To determine left and right of the button hold the slot on the bottom side of the button vertically. To get the button to stick good into the breadboard, you may need to spread the pins out a little so that when they go into the breadboard there are two rows of pins in between the metal pins of the button. 34 | 35 | ##### Bottom view of button 36 | ![Button Slot](/images/button_bottom.jpg) 37 | 38 | The slot on the bottom of the button separates the two sides. So, just be sure the slot is in the same direction as the columns (vertical in the diagram below). 39 | 40 | Now move the wire connecting to the long leg of your LED to connect to column 25. The power rail should be connected to the left side of the button. 41 | 42 | Now if you press and hold the button your LED should light up. 43 | 44 | If it works think a happy thought. 45 | 46 | 47 | ![Button Circuit Diagram](/images/5_button_bb.png) 48 | -------------------------------------------------------------------------------- /labs/06_blink_yo_self.md: -------------------------------------------------------------------------------- 1 | # Blink the Onboard LED 2 | 3 | ## Overview 4 | 5 | We've finally made it to our first lab with actually using the Pico as a microcontroller and not as just a power source. We will write our first bit of code in Python to have the Pico flash it's onboard LED! This is the obligatory blink demo for nearly all microcontroller projects... this is the equivalent of the "hello world" program. 6 | 7 | ## Raspberry Pi Pico H 8 | 9 | We are using the Raspberry Pi Pico H which is part of the Pi Foundations new Microcontroller family of boards... You can read more about them here. 10 | 11 | [Official Pico Page](https://www.raspberrypi.com/products/raspberry-pi-pico/) 12 | 13 | ## Python 14 | 15 | If this is your first time playing with Python you may find this cheatsheet helpful: 16 | 17 | [Python Cheatsheet](https://www.pythoncheatsheet.org/) 18 | 19 | ## What to do 20 | 21 | To start you don't need anything but the pico for this lab. So, feel free to strip everything else off except the Pico. I would leave the wires connecting the Pico to the power rails although technically they are not needed for this lab. 22 | 23 | ![Blink Diagram](/images/6_blink_bb.png) 24 | 25 | With the breadboard cleared, and the Pico still connected to your USB port, open Thonny and in the bottom right hand corner choose the interpreter for Thonny to use. If your computer recognized the Pico, you can choose the item that says "**MicroPython(Raspberry Pi Pico)** in the list. (see image below) 26 | 27 | Note: if this is your first time launching Thonny you may have to click past the Welcome/language selection splash page. 28 | 29 | ![Thonny Select Pico](/images/thonny_pico.PNG) 30 | 31 | If having issues connecting see if this detailed guide helps: 32 | [Detailed guide for connecting Pico to Thonny](https://microcontrollerslab.com/getting-started-raspberry-pi-pico-thonny-ide/) 33 | 34 | 35 | If it's able to connect, you should see the print out in the shell like in the picture above that tells you the version of MicroPython running on the Pico. 36 | The shell below is a [REPL](https://pythonprogramminglanguage.com/repl/) where you could type Python statements have them executed immeditately. We are not going to use the shell. Instead, we will type our code into the text editor area above the shell. 37 | 38 | Here is the obligatory blink demo for the Pico: 39 | 40 | ``` Python 41 | from machine import Pin 42 | import utime 43 | 44 | led = Pin(25, Pin.OUT) 45 | 46 | while True: 47 | led.toggle() 48 | utime.sleep_ms(1000) 49 | ``` 50 | 51 | A note about the code above: 52 | 53 | You'll notice that there is a while True statement at the end. 54 | 55 | while True means loop forever. The while statement takes an expression and executes the loop body while the expression evaluates to (boolean) "true". True always evaluates to boolean "true" and thus executes the loop body indefinitely. 56 | 57 | This is the section of the code that our pico will run forever and ever, over and over again. 58 | (Unless we define a way for it to break out) 59 | 60 | 61 | **NOTE**
Click here for how to make this work with Pico W. 62 | If using the Pico W the internal pin for the LED is NOT 25. It's the string "LED". So, assuming you flashed your Pico W with the right MicroPython library(the one for the Pico W), then the led line above would look like this for the Pico W: 63 | ```Python 64 | led = Pin("LED", Pin.OUT) 65 | ``` 66 |
67 | 68 | Enter the code above into the Thonny editor and then click the Play button. 69 | If everything works, you should see the onboard LED flash green about once a second. 70 | 71 | **NOTE** You can save this code to your Pico, by clicking the SAVE button in Thonny and then choosing to save it on the Pico. Give it a file name and a ".py" extension. If Thonny complains about the Pico or device being busy OR you think it's stuck processing somewhere, click the red stop button to exit running the current program and then click save. The STOP button resets the connection with the Pico. Once you have saved a file in Thonny, usually clicking the "Play" button will automatically save the latest version again as well as running it. This may change with different releases of Thonny. So, if you need to save your code, click the Save button before closing Thonny to ensure a proper save. 72 | 73 | If it works, eat a snack or better yet, give your instructor one! 74 | 75 | If the instructor didn't explain each line of the code or it doesn't make sense, throw something at him/her and make them explain it! 76 | 77 | -------------------------------------------------------------------------------- /labs/07_blink_led.md: -------------------------------------------------------------------------------- 1 | # Blink External LED 2 | 3 | ## Overview 4 | 5 | This will be a short one, we are simply going to blink an external LED. 6 | 7 | 8 | ## What to do 9 | 10 | Grab your BLUE LED or any LED rated for 3volts. Put the long pin into column 30 and then the short pin into column 31. 11 | 12 | Connect the short side to the ground/negative rail of the breadboard. 13 | Connect the long side of the LED to column 20 which is GP16 pin of the Pico. "GP " stands for General Purpose Input Output. You can refer to the Pico Pinout image to see the different GP pins of the Pico. Here's the reference image for the Pico Pinout: [Pico Pin Reference Page](/reference/pico_gpio.md) 14 | 15 | ![Blink Diagram](/images/7_blink_external_bb.png) 16 | 17 | 18 | When the LED in place and connected to the Pico and to ground, then we just need to write the code. However, this is the exact same code as last time, other than we need to change the Pin number from the onboard LED pin 25 to the GP16 pin. 19 | 20 | 21 | ``` Python 22 | from machine import Pin 23 | import utime 24 | 25 | led = Pin(16, Pin.OUT) 26 | 27 | while True: 28 | led.toggle() 29 | utime.sleep_ms(1000) 30 | ``` 31 | Enter the code above into the Thonny editor and then click the Play button. 32 | If everything works, you should see the LED flash about once a second. 33 | 34 | If it works, blink twice! 35 | 36 | ## Other Pin functions. 37 | 38 | Another way to turn the LED off and on is to use the [value() function](https://docs.micropython.org/en/latest/library/machine.Pin.html#machine.Pin.value). 39 | 40 | Here is that code: 41 | 42 | ``` Python 43 | from machine import Pin 44 | import utime 45 | 46 | led = Pin(16, Pin.OUT) 47 | 48 | while True: 49 | led.value(1) 50 | utime.sleep_ms(1000) 51 | led.value(0) 52 | utime.sleep_ms(1000) 53 | ``` 54 | 55 | Try this out. If you want it to blink faster change the time it sleeps. 56 | 57 | -------------------------------------------------------------------------------- /labs/08_button_control.md: -------------------------------------------------------------------------------- 1 | # First Input with Pico 2 | 3 | ## Overview 4 | 5 | We will now use a GPIO (General Purpose Input/Output) pin on the Pico to detect when a button is pressed. So, this will be our first time using a GPIO pin for input. 6 | 7 | We will create a circuit and the code to make the Blue LED light up only when you press the button. However, unlike our first lab with the button, the LED and button will not be on the same circuit. The button will simply be an input to the Pico and we will write code to control what happens when the button is pressed. 8 | 9 | ## What to do 10 | 11 | Add your button back to the breadboard putting the far right pins of the button into column 40. Remember to keep the slot under the button vertical (in line with the columns). Connect the far right pin on column 40 to the positive power rail. 12 | Connect the left side of the button to the GP17 pin on the Pico which is in column 19 on the breadboard. 13 | 14 | ![Button Diagram](/images/8_button_pico_bb.png) 15 | 16 | 17 | 18 | At this point the LED from the last lab should still be connected to GP16 and now the button is connected to GP17. 19 | 20 | Now to write the code to add the button management. This just requires adding a line to initialize the button to be in a PULL_DOWN mode which means that GP17 pin acts as a ground. So, when the button is pressed electricty can flow from the positive power rail through the button to the GP17 pin on the Pico which acts as a ground. Then in our code we can detect when this happens by checking the value of the button or GP17 pin. 21 | 22 | Here's the code: 23 | 24 | ``` Python 25 | from machine import Pin 26 | 27 | led = Pin(16, Pin.OUT) 28 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 29 | 30 | while True: 31 | if button.value()==True: 32 | print("Button Pressed!") 33 | led.value(1) 34 | else: 35 | led.value(0) 36 | 37 | 38 | ``` 39 | Enter the code above into the Thonny editor and then click the Play button. 40 | If everything works, you should see the LED come on when you push and hold down the button. 41 | 42 | If it works, slap yo self! 43 | 44 | ## Stretch Goal 45 | 46 | Change the code above to make it so that when the button is pressed the light flashes 3 times before turning off. 47 | 48 | If you continue to hold the button down it should continue to flash. 49 | 50 | You may want to use a for loop. Here's Python for loop help: [Python For Loop with Range](https://www.w3schools.com/python/gloss_python_for_range.asp) 51 | 52 |
53 | To see working code for this click the arrow beside here to expand the code! 54 | 55 | 56 | ```Python 57 | from machine import Pin 58 | import utime 59 | 60 | led = Pin(16, Pin.OUT) 61 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 62 | 63 | while True: 64 | if button.value()==True: 65 | print("Button Pressed!") 66 | for count in range(3): 67 | print("looping:" + str(count)) 68 | led.value(1) 69 | utime.sleep_ms(400) 70 | led.value(0) 71 | utime.sleep_ms(400) 72 | else: 73 | led.value(0) 74 | 75 | 76 | ``` 77 | 78 |
79 | 80 | -------------------------------------------------------------------------------- /labs/09_button_debounce.md: -------------------------------------------------------------------------------- 1 | # Button Debounce 2 | 3 | ## Overview 4 | 5 | We are going to work on some programming techniques now when dealing with reading input especially from a button. So, we won't be changing our wiring for this lab we will just be working on code. 6 | 7 | Our goal for this lab is to use our button to toggle the LED from off to on and vice versa. That is if the LED is off, pressing and releasing the button should turn it on and leave it on. Then to turn the LED off again, we would press and release the button again to turn it off. 8 | 9 | ## What to do 10 | 11 | In case you messed up or re-arranged your breadboard since the last lab, here is what your breadboard should look like: 12 | ![Button Diagram](/images/8_button_pico_bb.png) 13 | 14 | To allow our button to be a toggle to turn our LED off or on update your code to match this: 15 | 16 | Here's the code: 17 | 18 | ``` Python 19 | from machine import Pin 20 | 21 | 22 | led = Pin(16, Pin.OUT) 23 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 24 | 25 | led.value(0) # init led to off 26 | # Flag for if LED is on or off 27 | led_on = False 28 | 29 | while True: 30 | if button.value()==True: 31 | print("Button Pressed!") 32 | if(led_on): 33 | led.value(0) 34 | led_on = False 35 | else: 36 | led.value(1) 37 | led_on = True 38 | 39 | 40 | ``` 41 | Enter the code above into the Thonny editor and then click the STOP button to reset and then click the Play button to run the new code. 42 | 43 | Try pressing the button to toggle the LED on and off. The idea is that if you tap the button when the LED is off, it should then come on. Then if the LED is on, pressing and releasing the button should turn it off. However, if you try it out, you should notice some inconsistency. That is it probably won't work consistently. Try pressing and releasing the button several times and see what happens. Can you identify the cause of the inconsistency? 44 | 45 |
46 | Click here when you are ready to read about the issue. 47 | 48 | The issue is what we call button bouncing. The while loop is running at such a fast pace that when you press the button it triggers multiple button presses. There is no pause in our code from the time it detects one button press til the time it tries to check again. So, if the button is held down for just a few milliseconds, it could trigger multiple button presses. 49 |
50 | 51 | ### Button Bounce Fix 52 | 53 | Fixing this issue is called "debouncing". One of the easiest ways to do this is by keeping track of the time from when the button was pressed before you register another button press. That is we can keep a timer that starts when we detect a button press and then not take any action unless a certain time passes before the next button press. 54 | 55 | In our code, we will now create a debounce_timer flag to keep track of the time when the button is pressed and only allow another button press after 500 milliseconds. 56 | 57 | If you'd like to try it yourself without copying our code, you may find the documentation for the [time library](https://docs.micropython.org/en/latest/library/time.html#module-time) helpful. NOTE: time and utime are the same. Importing time is the same as importing utime. 58 | The **ticks_ms()** and the **ticks_diff()** function are useful. 59 | 60 | So, using the time library referenced above, attempt to fix the issue by starting a timer when the button is pressed and then don't act on any other button presses until 500ms (half a second) has passed. You will need a global variable that keeps track of the last button pressed time. 61 | 62 |
63 | To see working code for this click the arrow beside here to expand the code! 64 | 65 | 66 | ```Python 67 | from machine import Pin 68 | import time 69 | 70 | led = Pin(16, Pin.OUT) 71 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 72 | 73 | led.value(0) # init led to off 74 | # Flag for if LED is on or off 75 | led_on = False 76 | 77 | 78 | # debounce TIME saying 500ms between button presses 79 | DEBOUNCE_TIME = 500 80 | # debounce counter is our counter from the last button press 81 | # initialize to current time 82 | debounce_counter = time.ticks_ms() 83 | 84 | while True: 85 | if button.value()==True: 86 | current_time = time.ticks_ms() 87 | # Calculate time passed since last button press 88 | time_passed = time.ticks_diff(current_time,debounce_counter) 89 | print("time passed=" + str(time_passed)) 90 | if (time_passed > DEBOUNCE_TIME): 91 | print("Button Pressed!") 92 | # set debounce_counter to current time 93 | debounce_counter = time.ticks_ms() 94 | if(led_on): 95 | led.value(0) 96 | led_on = False 97 | else: 98 | led.value(1) 99 | led_on = True 100 | else: 101 | print("Not enough time") 102 | 103 | ``` 104 | 105 |
106 | 107 | 108 | ### Run it! 109 | 110 | After adding your debounce logic, you should be able to run it and see that pressing and releasing the button now consistently toggles the LED off and on. 111 | 112 | If this works, give someone nearby a high five! 113 | 114 | ### Clean Code 115 | 116 | **NOTE** Our code is getting a little messy so it would be nice to move some logic into functions. Feel free to refactor and clean it up yourself as a stretch goal (or copy our example below). 117 | 118 | 119 |
If you wanna skip the stretch goal of cleaning then click here to see the code. 120 | 121 | ```Python 122 | from machine import Pin 123 | import utime 124 | 125 | led = Pin(16, Pin.OUT) 126 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 127 | 128 | led.value(0) # init led to off 129 | # Flag for if LED is on or off 130 | led_on = False 131 | 132 | 133 | # debounce utime saying 500ms between button presses 134 | DEBOUNCE_utime = 500 135 | # debounce counter is our counter from the last button press 136 | # initialize to current utime 137 | debounce_counter = utime.ticks_ms() 138 | 139 | # Function to handle turning LED off and on and setting flag 140 | def toggle_led(): 141 | global led_on 142 | if(led_on): 143 | led.value(0) 144 | led_on = False 145 | else: 146 | led.value(1) 147 | led_on = True 148 | 149 | # Function to handle when the button is pressed 150 | def button_press_detected(): 151 | global debounce_counter 152 | current_utime = utime.ticks_ms() 153 | # Calculate utime passed since last button press 154 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 155 | print("utime passed=" + str(utime_passed)) 156 | if (utime_passed > DEBOUNCE_utime): 157 | print("Button Pressed!") 158 | # set debounce_counter to current utime 159 | debounce_counter = utime.ticks_ms() 160 | toggle_led() 161 | 162 | else: 163 | print("Not enough utime") 164 | 165 | 166 | while True: 167 | if button.value()==True: 168 | button_press_detected() 169 | 170 | ``` 171 |
172 | 173 | After making the above changes, test you code again to make sure it still works. Having easy to understand code as well as single purpose functions is key to being able to continue to add features quickly and maintian and debug your code. 174 | -------------------------------------------------------------------------------- /labs/10_button_interrupt.md: -------------------------------------------------------------------------------- 1 | # Button Interrupt vs Polling 2 | 3 | ## Overview 4 | 5 | Like the last lab, we are going to work on another programming technique when dealing with input from buttons. Last time we dealt with debouncing our button input, this time we are going to look at the **polling** vs **interrupt** method for reading input. 6 | 7 | Our current while loop (see below) is constantly checking the **button.value()** to see if the button is pressed. 8 | ``` Python 9 | ... 10 | ... 11 | while True: 12 | if button.value()==True: 13 | button_press_detected() 14 | ``` 15 | This constant checking of the button value is called **polling**. It uses CPU cycles to constantly check the button state. A better way of doing this is using **interrupts**. Using the interrupt approach we can actully have the hardware (the GPIO pin) notify us of when something happened. It's kind of like event driven programming. The microcontroller will interrupt the main thread of the program to say something happened. 16 | 17 | 18 | ## What to do 19 | 20 | In case you messed up or re-arranged your breadboard since the last lab, here is what your breadboard should look like: 21 | ![Button Diagram](/images/8_button_pico_bb.png) 22 | 23 | 24 | So, using an interrupt on the Pico with MicroPython is easy. We will simply create a function to be called when the button is pressed. This will be like a callback function that gets invoked when the Pico detects a change on the GPIO pin connected to the button. 25 | 26 | Here I'll show some of new parts of the code we will be adding and then I'll show the full code below. 27 | We are going to start by adding a global flag that tells when the button was pressed and then a function to set the flag when the interrupt detects a button press. 28 | ```Python 29 | 30 | # define flag to say when button is pressed: 31 | button_pressed = False 32 | 33 | # define function to be called when button is pressed 34 | def button_interrupt_handler(pin): 35 | # since this is called by an interrupt do very little 36 | # need to give control back to CPU quickly. 37 | # Could possibly do debounce work here??? 38 | global button_pressed 39 | button_pressed = True 40 | 41 | ## define interrupt to call our function when button is pressed: 42 | button.irq(trigger=Pin.IRQ_RISING, handler=button_interrupt_handler) 43 | 44 | ``` 45 | In the snippet of code above, you can see our boolean flag to define when the button is pressed. 46 | Then the function **button_interrupt_handler()** that is simply setting that flag to true. 47 | Our **button_interrupt_handler()** is passed as the handler to our **irq** function call to set up the interrupt monitor. 48 | 49 | After this we just need to update our while loop to use this new flag instead of polling the button value each time and then we refactor our existing **button_press_detected()** function to set this button_pressed flag to False at appropriate times. 50 | 51 | Here's the full code: 52 | 53 | ``` Python 54 | from machine import Pin 55 | import utime 56 | 57 | led = Pin(16, Pin.OUT) 58 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 59 | 60 | led.value(0) # init led to off 61 | # Flag for if LED is on or off 62 | led_on = False 63 | 64 | 65 | # debounce utime saying 500ms between button presses 66 | DEBOUNCE_utime = 500 67 | # debounce counter is our counter from the last button press 68 | # initialize to current utime 69 | debounce_counter = utime.ticks_ms() 70 | 71 | # define flag to say when button is pressed: 72 | button_pressed = False 73 | 74 | # define function to be called when button is pressed 75 | def button_interrupt_handler(pin): 76 | # since this is called by an interrupt do very little 77 | # need to give control back to CPU quickly. 78 | # Could possibly do debounce work here??? 79 | global button_pressed 80 | button_pressed = True 81 | 82 | ## define interrupt to call our function when button is pressed: 83 | button.irq(trigger=Pin.IRQ_RISING, handler=button_interrupt_handler) 84 | 85 | # Function to handle turning LED off and on and setting flag 86 | def toggle_led(): 87 | global led_on 88 | if(led_on): 89 | led.value(0) 90 | led_on = False 91 | else: 92 | led.value(1) 93 | led_on = True 94 | 95 | # Function to handle when the button is pressed 96 | def button_press_detected(): 97 | global debounce_counter, button_pressed 98 | current_utime = utime.ticks_ms() 99 | # Calculate utime passed since last button press 100 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 101 | print("utime passed=" + str(utime_passed)) 102 | if (utime_passed > DEBOUNCE_utime): 103 | print("Button Pressed!") 104 | # set debounce_counter to current utime 105 | debounce_counter = utime.ticks_ms() 106 | toggle_led() 107 | button_pressed=False 108 | 109 | else: 110 | button_pressed = False 111 | print("Not enough utime") 112 | 113 | while True: 114 | if button_pressed==True: 115 | button_press_detected() 116 | 117 | ``` 118 | Enter the code above into the Thonny editor and then click the STOP button to reset and then click the Play button to run the new code. 119 | 120 | Try pressing the button to toggle the LED on and off. 121 | If everything is working, then you should see the button toggle off and on as you press and release the button. 122 | 123 | If it works, interrupt someone else by shouting "It's working! It's working!" 124 | 125 | 126 | ## References 127 | 128 | If you'd like to read more about the **irq()** function or other **Pin** functions here's the link to the official docs: 129 | - [Pin Documentation](https://docs.micropython.org/en/latest/library/machine.Pin.html) 130 | 131 | - [Polling vs Interrupts](https://electrocredible.com/raspberry-pi-pico-external-interrupts-button-micropython/) 132 | 133 | - [(Video)Simple Interrupt with Pico](https://www.youtube.com/watch?v=Qw2xr5a2rSA) 134 | 135 | - [(Video)Threading with the Pico](https://www.youtube.com/watch?v=QeDnjcdGrpY) 136 | 137 | - [(Video) How To Use Multiple Cores and Interrupts](https://www.youtube.com/watch?v=9vvobRfFOwk&t=574s) -------------------------------------------------------------------------------- /labs/11_PWM_LED.md: -------------------------------------------------------------------------------- 1 | # PWM(Pulse Width Modulation) 2 | 3 | ## Overview 4 | 5 | Now we will look at how to use PWM (Pulse Width Modulation) with the RaspberryPi Pico. If you aren't familar with PWM just think of it as a way to send a pulse of power at regular intervals. PWM is a more efficient way of powering electronics like motors or even LEDs. Instead of having constant power to a device you can send pulses of electricity to keep a motor running or light up an LED. That is you can specify a frequency at which to send pulses of electricity and then fluctuate the amount of time that signal or power is on during each pulse. The amount of time the power is on during each signal/pulse is called the **Duty Cycle**. The image below from [circuitdigest.com](https://circuitdigest.com/tutorial/what-is-pwm-pulse-width-modulation) illustrates PWM signals using various Duty Cycles. **NOTE** The frequency rate isn't shown below, but it doesn't matter, the duty cycle is independent of the frequency. 6 | 7 | ![PWM](/images/Pulse-Width-Modulation.jpg) 8 | 9 | 10 | If powering a motor with PWM, the higher the duty cycle the faster the motor would spin. 11 | If powering an LED with PWM, the higher the duty cycle the brighter the LED will be. 12 | This is caused by an increase in the average output voltage. (You will see this happen during this lab!) 13 | 14 | 15 | ## What to do 16 | 17 | In this lab, we are only going to change the code. If you messed up your wiring, look at the previous lab for how to set it back up. 18 | 19 | The first changes we will make are to slightly alter the way we are interacting with the GPIO pin connecting to our LED. Currently, we have the GPIO pin configured as a simple output pin and we can set the value to 1(or high) to turn the light on or set the value to 0 (or low) to turn the LED off. So, in our current implementation it's a strictly binary operation. 20 | 21 | With PWM, we will be able to change the frequency and the duty cycle. That is how many pulses per second we send and how long the power will be high during each pulse. However, initially we will just make a few tiny changes to keep the functionality of our button toggling the LED off and on, but it will use PWM to light up the LED. 22 | 23 | So, to start we need import [PWM](https://docs.micropython.org/en/latest/library/machine.PWM.html?highlight=pwm) from the machine library. So, alter the first import by adding "PWM" alongside the existing "Pin". The altered import line should look like this: 24 | 25 | ```Python 26 | from machine import Pin, PWM 27 | ``` 28 | Next we will alter the initiation of the "led" variable to use PWM. To do this, we simply create a Pin with our pin number and wrap that with "PWM()". 29 | Alter the "led" initialization line like this: 30 | ```Python 31 | led = PWM(Pin(16)) 32 | led.freq(1000) 33 | ``` 34 | Here we define the Pin #16 as our pin to use for PWM signals. We also set the frequency to 1000Hz. That's 1000 pulses per second. 35 | 36 | Since our `"led"` variable now is a PWM object, the `value()` function is invalid. So, we need to update each place we were calling the `value()` function, to use the [duty_u16()](https://docs.micropython.org/en/latest/library/machine.PWM.html?highlight=pwm#machine.PWM.duty_u16) function. 37 | 38 | This function allows us to set the duty cycle. 39 | 40 | The lowest possible value is **0** ... but we can also use 0%. 41 | 42 | The highest possible value is **65535** ... but we can also use 100%. 43 | 44 | Therefore, if we want our LED to be at the brightest level, replace `led.value(1)` to `led.duty_u16(65535)` (There's one place this needs replaced). 45 | To turn the LED completely off, replace `led.value(0)` to `led.duty_u16(0)`(There's two places to replace this). 46 | 47 | Here's the full code: 48 | 49 | ```Python 50 | from machine import Pin, PWM 51 | import utime 52 | 53 | led = PWM(Pin(16)) 54 | led.freq(1000) 55 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 56 | 57 | led.duty_u16(0) # init led to off 58 | # Flag for if LED is on or off 59 | led_on = False 60 | 61 | 62 | # debounce utime saying 500ms between button presses 63 | DEBOUNCE_utime = 500 64 | # debounce counter is our counter from the last button press 65 | # initialize to current utime 66 | debounce_counter = utime.ticks_ms() 67 | 68 | # define flag to say when button is pressed: 69 | button_pressed = False 70 | 71 | # define function to be called when button is pressed 72 | def button_interrupt_handler(pin): 73 | # since this is called by an interrupt do very little 74 | # need to give control back to CPU quickly. 75 | # Could possibly do debounce work here??? 76 | global button_pressed 77 | button_pressed = True 78 | 79 | ## define interrupt to call our function when button is pressed: 80 | button.irq(trigger=Pin.IRQ_RISING, handler=button_interrupt_handler) 81 | 82 | # Function to handle turning LED off and on and setting flag 83 | def toggle_led(): 84 | global led_on 85 | if(led_on): 86 | led.duty_u16(0) 87 | led_on = False 88 | else: 89 | led.duty_u16(65535) # 65535 is max 90 | led_on = True 91 | 92 | # Function to handle when the button is pressed 93 | def button_press_detected(): 94 | global debounce_counter, button_pressed 95 | current_utime = utime.ticks_ms() 96 | # Calculate utime passed since last button press 97 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 98 | print("utime passed=" + str(utime_passed)) 99 | if (utime_passed > DEBOUNCE_utime): 100 | print("Button Pressed!") 101 | # set debounce_counter to current utime 102 | debounce_counter = utime.ticks_ms() 103 | toggle_led() 104 | button_pressed=False 105 | 106 | else: 107 | button_pressed = False 108 | print("Not enough utime") 109 | 110 | while True: 111 | if button_pressed==True: 112 | button_press_detected() 113 | 114 | 115 | ``` 116 | After updating the code click the STOP button to reset and then click the Play button to run the new code. 117 | 118 | Try pressing the button to toggle the LED on and off. 119 | If everything is working, then you should see the button toggle off and on as you press and release the button. It should still operate the same, but now using PWM. 120 | 121 | Not super exciting yet, but wait there's more! 122 | 123 | ## See the Power of PWM! 124 | 125 | To see some difference with PWM verses the pure binary on and off, try playing with the value passed to the `led.duty_16(65535)` method. Replace **65535** with a lower value so that when the LED comes on, it's not as bright. Something like this: 126 | ```Python 127 | led.duty_u16(5000) # 65535 is max 128 | ``` 129 | 130 | Retest with different values to see how it affects the brightness of the LED. 131 | 132 | After you are bored with that, let's make some cool affects with PWM. 133 | 134 | What we'll do now is make pressing the button slowly increase the brightness to max and then pressing it again slowly dim it till it's off. 135 | 136 | To do this, we will simply add a for loop in the block of code that turns on or off the LED to slowly adjust the duty cycle up or down. Here's an example for loop to slowly increase in brightness: 137 | 138 | ```Python 139 | for duty in range(0,65535,1): 140 | led.duty_u16(duty) # 65535 is max 141 | ``` 142 | **NOTE** The 3rd parameter of the for loop is the step. That is how much to count by. If you want to could by 5's, then change the 1 to 5. 143 | 144 | Here's an example for loop to slowly decrease in brightness: 145 | 146 | ```Python 147 | for duty in range(65535,0,-1): 148 | led.duty_u16(duty) # 65535 is max 149 | ``` 150 | 151 | You can swap out the code that turns the LED on and off with these loops to see the LED more slowly light up and turn off. These for loops may still cause it to light up and dim quickly. Can you think how you could slow the light up or dimming down? 152 | 153 | Here's the full code: 154 | 155 | ```Python 156 | from machine import Pin, PWM 157 | import utime 158 | 159 | led = PWM(Pin(16)) 160 | led.freq(1000) 161 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 162 | 163 | led.duty_u16(0) # init led to off 164 | # Flag for if LED is on or off 165 | led_on = False 166 | 167 | 168 | # debounce utime saying 500ms between button presses 169 | DEBOUNCE_utime = 500 170 | # debounce counter is our counter from the last button press 171 | # initialize to current utime 172 | debounce_counter = utime.ticks_ms() 173 | 174 | # define flag to say when button is pressed: 175 | button_pressed = False 176 | 177 | # define function to be called when button is pressed 178 | def button_interrupt_handler(pin): 179 | # since this is called by an interrupt do very little 180 | # need to give control back to CPU quickly. 181 | # Could possibly do debounce work here??? 182 | global button_pressed 183 | button_pressed = True 184 | 185 | ## define interrupt to call our function when button is pressed: 186 | button.irq(trigger=Pin.IRQ_RISING, handler=button_interrupt_handler) 187 | 188 | # Function to handle turning LED off and on and setting flag 189 | def toggle_led(): 190 | global led_on 191 | if(led_on): 192 | for duty in range(65535,0,-1): 193 | led.duty_u16(duty) # 65535 is max 194 | led_on = False 195 | else: 196 | for duty in range(0,65535,1): 197 | led.duty_u16(duty) # 65535 is max 198 | led_on = True 199 | 200 | # Function to handle when the button is pressed 201 | def button_press_detected(): 202 | global debounce_counter, button_pressed 203 | current_utime = utime.ticks_ms() 204 | # Calculate utime passed since last button press 205 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 206 | print("utime passed=" + str(utime_passed)) 207 | if (utime_passed > DEBOUNCE_utime): 208 | print("Button Pressed!") 209 | # set debounce_counter to current utime 210 | debounce_counter = utime.ticks_ms() 211 | toggle_led() 212 | button_pressed=False 213 | 214 | else: 215 | button_pressed = False 216 | print("Not enough utime") 217 | 218 | while True: 219 | if button_pressed==True: 220 | button_press_detected() 221 | 222 | ``` 223 | 224 | If you got this to work, eat some gummies! 225 | 226 | ## Stretch Goal 227 | 228 | Play with the for loops and optionally some sleeping in your for loop to get the LEDs to light up slowly or dim slowly. 229 | 230 | After that, a bigger challenge would to have multiple presses of the button actually increase the brightness and then after it's at its brightest level it turns off. Kind of like the touch lamps of old. Each touch would brighten the light until it reached it's max and then it would turn off. 231 | 232 | -------------------------------------------------------------------------------- /labs/11b_Buzzer.md: -------------------------------------------------------------------------------- 1 | # Buzzer 2 | 3 | ## Overview 4 | 5 | Now we are going to make some noise! We are going to use a simple Active Piezo Buzzer. 6 | 7 | This type of simple buzzers allow you to make annoying buzzing noises. 8 | 9 | Here's a picture of what we are talking about. 10 | 11 | ##### Buzzer Top 12 | ![Buzzer Top](/images/buzzertop.jpg) 13 | ##### Buzzer Bottom 14 | ![Buzzer Bottom](/images/buzzerbottom.jpg) 15 | 16 | 17 | By simply adding power to them they make a sound. You can take your buzzer and plug it directly into your power rail to hear it buzz. They have a positve leg and a negative leg. Just like an LED, the longer leg is the positive side and the negative side is the shorter leg. The buzzers in your kit are 3volt buzzers, so plug it into the top (3.3V) power rail, plugging the longer leg into the positive and the shorter leg to the negative. 18 | 19 | Once it gets power, you should hear it's annoying buzz. 20 | 21 | ## What to do 22 | 23 | In this lab, we are going to learn how to make the buzzer buzz at different frequencies with PWM. 24 | 25 | In the last lab, we used PWM to fade an LED by updating the duty cycle after setting a fixed frequency. With the buzzer, we will use the duty cycle to control the volume of the buzzer and use the frequency to control the pitch. 26 | 27 | For wiring this one, we will remove the button from the last lab along with it's wires and then replace the LED with the buzzer. You can plug the long leg (+) of the buzzer into Column 30 and the short leg(-) into Column 33. Keep the wire going connecting the positive side of the buzzer at Column 30 to the Pico at column 20 (GP16). Next run a wire from the short pin of the buzzer(-) to ground. 28 | 29 | ![Buzzer Wiring Diagram](/images/11b_buzzer_bb.png) 30 | 31 | Next we will write a simple program to fluctuate the PWM frequency to make our buzzer make sounds at different pitches. 32 | 33 | Here is the code: 34 | 35 | ```Python 36 | from machine import Pin, PWM 37 | import utime 38 | 39 | buzzer = PWM(Pin(16)) 40 | 41 | 42 | for freq in range(10, 1000, 100): 43 | buzzer.freq(freq) 44 | buzzer.duty_u16(30000) 45 | utime.sleep_ms(300) 46 | 47 | ``` 48 | 49 | This code will loop from 10 to 1000 with steps of 100. That is freq will be 10, then 110, then 210, then 310, etc... up to 1000. This will cause the buzzer to buzz at each of these frequencies for 300 milliseconds(thanks to the sleep call) and at a hard coded duty cycle of 30000. 50 | 51 | If you got this to work, do your best bee impression and buzz! 52 | 53 | ## Stretch Goal 54 | 55 | Play with the for loop the start and stopping range as well as the steps and the sleep time to get it to make interesting noises. Rember with the `range(start, stop, step)` function, the start can be less than the stop if you use a negative step. This way you can go backwards. 56 | 57 | Also, play with the duty cycle value passed to the `duty_u16()` method to see what impact that has. Remember valid duty cycle values are between 0 and 65535 (max unsigned int size). 58 | 59 | ## References 60 | 61 | - [Play Music With Buzzer and Pico](https://www.tomshardware.com/how-to/buzzer-music-raspberry-pi-pico) 62 | 63 | -------------------------------------------------------------------------------- /labs/12_servo_control.md: -------------------------------------------------------------------------------- 1 | # SERVO MOTORS!! 2 | 3 | ## Overview 4 | 5 | We will now finally do something completely different! No more just flashing LEDs! Now we will use a [Servo](https://www.sparkfun.com/servos) to turn code into physical movement. 6 | 7 | 8 | ## What's a Servo? 9 | 10 | ###### Sg90 Servo 11 | ![Servo Image](/images/sg90.png) 12 | 13 | A **Servo** is typically just a simple motor with internal gears and a built-in controller that allows you to tell it what position to move to and hold. Servos are commonly used in robotics as well as R/C planes and cars. Most servos are designed to be controlled by a PWM signal which is like a digital code to say what angle or position to rotate to. 14 | 15 | ## How they Work 16 | 17 | Servos typically have 3 wires. Two are for power (positive and negative(ground)) and then the third is the signal wire which takes the PWM signal. 18 | ![Servo Wires](/images/sg90_wires.PNG) 19 | 20 | Red wire goes to Positive, brown wire goes to ground/negative, and the Orange wire is the PWM signal wire. 21 | 22 | To control a servo, the duty cycle of the PWM signal acts as the digital code telling on the servos controller where to move or hold the motor. 23 |
24 | Expand to read boring technical stuff about PWM and Servo control! 25 | Servos are designed to work at a specific frequency (50Hz) and use the duty cycle of the PWM signal to control the movemnt of the servo. 26 | Technically, for most servos, the pulse width (time the power is on in a pulse) matters more than the duty cycle(the % of time power is on), but at a given frequency the duty cycle directly controls the pulse width. 27 |
28 | 29 | ## What to do 30 | 31 | Upto this point everything we've been using is running of the Pico's 3.3Volt output. For this lab, we will use the Pico's 5Volt output. 32 | 33 | Clear the board of LED's and buttons and extra wires. You can leave the power rail wires that connect to the top power rail. We won't use the top power rail, but it doesn't hurt to leave them connected. 34 | 35 | With the board clear, grab a red wire and connect it from the Pico 5 Volt power (VBUS) to the bottom positive rail. The Pico's **VBUS** is a 5 volt out and it's connected to the top column 1. So, connect your red wire to column 1 row j and then to the bottom positve rail as seen in the diagram below. 36 | 37 | Connect a black wire from one of the Pico's bottm ground pins to the bottom negative rail. The bottom two pins in column 3 are a good choice. 38 | 39 | With the bottom power rails connected to the Pico, now wire up the servo. Use a male to male wire to connect the brown servo wire to the ground rail(negative) on the breadboard. 40 | Use a wire to connect the servo's red wire to the bottom positive rail. 41 | 42 | Use another wire to connect the servo's orange wire to GPIO 15 on the Pico which can be found in column 20 at the bottom( orange wire connected to column 20, Row B in the picture below). 43 | 44 | ![Servo Diagram](/images/12_servo_pico_bb.png) 45 | 46 | 47 | Once you have the pico wired, we need to write the code to control the servo. 48 | 49 | To begin with our code will simply move the servo to the center, then rotate 90 degrees in one direction and then rotate to the opposite extreme (180 degrees in the opposite direction). 50 | 51 | To make your code with the servo simple, I've created a library that you can simply copy to your pico and import into your program. 52 | 53 | Right click on the link below to open the SG90 library in another tab. Then copy it and paste it into a new file in Thonny (CTRL + N is the keyboard shortcut). After copying it into Thonny save it to the Pico and be sure to name it **"sg90.py**. 54 | [SG90 Library](https://raw.githubusercontent.com/javaplus/PicoProjects/main/servos/sg90.py) 55 | 56 | 57 | Once you have the **sg90.py** library saved to your Pico, open a new file/tab (CTRL + N) in Thonny and add the following code. 58 | 59 | Here's the code: 60 | 61 | ``` Python 62 | from sg90 import servo 63 | import utime 64 | 65 | # initialize with the Pin you are using 66 | servo1 = servo(15) 67 | 68 | #Center 69 | servo1.move_to(90) 70 | utime.sleep_ms(1000) 71 | 72 | #move_to to one extreme 73 | servo1.move_to(0) 74 | utime.sleep_ms(1000) 75 | 76 | #move_to to other extreme 77 | servo1.move_to(180) 78 | utime.sleep_ms(1000) 79 | 80 | #Center 81 | servo1.move_to(90) 82 | 83 | ``` 84 | 85 | Before running the code above, you may want to snap one of the servo horns ontop of the servo so you can see it's movement. 86 | ###### Servo Horn 87 | ![Servo Horns](/images/sg90-servo-horns.png) 88 | 89 | It doesn't matter which servo horn you use, just snap one on so you can more easily see when it moves. 90 | There is no need to use a screw here but they are provided in case your final use of your servo would require one to mount to whatever it is you are putting your servo on or in. 91 | 92 | The open toothed portion of the horn can easily pop onto the gear of the servo. Don't be scared. 93 | 94 | After you have the code and servo horn in place, click the PLAY button to see your servo spring to life! 95 | 96 | If everything is working right, then your servo should center itself and then move to one extreme 90 degrees and then move the opposite direction 180 degrees and then move back to its center position. 97 | 98 | ## Scanning 99 | 100 | Now that you have a simple program that shows how to set the angle of the servo, let's make it more intersting by adding some for loops to make it slowly scan back and forth. 101 | 102 | By the code above, you can see you set the angle you want the servo to move to. The library translates that to a specific duty_cycle to send out your signal pin. 103 | If you loop and slowly increase or decrease the angle, then you should see the servo move or "scan" in that one direction. 104 | 105 | The servos we are working with can move from 0 to 180 degrees. So, valid input are anything in that range. 90 degrees is the center. So, add a for loop or a few to start at 90 and then slowly scan to 180 and then go back the other direction. 106 | 107 | You will want to use a for loop. Here's Python for loop help: [Python For Loop with Range](https://www.w3schools.com/python/gloss_python_for_range.asp) 108 | 109 |
110 | To see working code for this click the arrow beside here to expand the code! 111 | 112 | 113 | ```Python 114 | import utime 115 | from sg90 import servo 116 | 117 | servo1 = servo(15) 118 | 119 | SMOOTH_TIME = 20 120 | 121 | def scan(): 122 | for i in range(90,180): 123 | servo1.move_to(i) 124 | utime.sleep_ms(SMOOTH_TIME) 125 | 126 | for i in range(180,89, -1): 127 | print(i) 128 | servo1.move_to(i) 129 | utime.sleep_ms(SMOOTH_TIME) 130 | 131 | 132 | for i in range(90,-1,-1): 133 | servo1.move_to(i) 134 | utime.sleep_ms(SMOOTH_TIME) 135 | 136 | for i in range(0,91): 137 | print(i) 138 | servo1.move_to(i) 139 | utime.sleep_ms(SMOOTH_TIME) 140 | 141 | servo1.move_to(90) 142 | 143 | while True: 144 | scan() 145 | 146 | 147 | ``` 148 | 149 |
150 | 151 | If you got this to work, scan the room for someone cool, when found go to them and say, "Hey you're smoother than zero duty cycle!" 152 | 153 | ## PWM Banks on the Pico 154 | 155 | There are less PWM channels on the PICO than there are GPIO pins. So some pins actually are tied to the same Pins. 156 | 157 | ![PWM Table](/images/GPIO_PWM-Table.webp) 158 | 159 | ## References: 160 | 161 | [Servo Explained](https://www.sparkfun.com/servos) 162 | [SG90 Specs](https://servodatabase.com/servo/towerpro/sg90) 163 | [Pico PWM Primer](https://www.codrey.com/raspberry-pi/raspberry-pi-pico-pwm-primer/) 164 | -------------------------------------------------------------------------------- /labs/13_threading.md: -------------------------------------------------------------------------------- 1 | # Threading 2 | 3 | ## Overview 4 | 5 | Now that we know how to flash LEDs and know how to move servos, what if we wanted to do them at the same time??? 6 | 7 | In this lab we will learn how to take advantage of both cores of the RP2040 microcontroller processor by running a second thread to do some work in parallel. 8 | 9 | The plan is to have one thread to make the servo continually scan, while the main thread blinks an LED. 10 | 11 | Before we get to threading let's demonstrate the issue, by trying to do both things at once without threading. That is we will attempt to move the servo back and forth and fade the LED in and out without threading. 12 | 13 | ## What to do 14 | 15 | Keep your servo hooked up and wire your LED back up to pin 16. 16 | 17 | Follow the diagram below to connect the blue LED positive leg to column 25 and the negative to column 26. Then connect the positive leg to the GP16 pin on the Pico(Column 20). Ground the other side of the LED leg. 18 | 19 | ![Servo Diagram](/images/servo_with_led_pico_bb.png) 20 | 21 | 22 | Once you have the pico wired, we need to write the code to control the servo and fade the LED in and out. This code should look familiar because it's pretty much the servo code from last lab along with a function to fade LED in and out added to it. 23 | 24 | ```Python 25 | from machine import Pin,PWM 26 | import utime 27 | from sg90 import servo 28 | 29 | # Initialize LED 30 | led = PWM(Pin(16)) 31 | led.freq(500) 32 | 33 | # Initiliaze Servo 34 | servo1 = servo(15) 35 | 36 | SMOOTH_TIME = 10 37 | 38 | def fade_led(): 39 | for duty in range(0,65535,1): 40 | led.duty_u16(duty) # 65535 is max 41 | for duty in range(65535,0,-1): 42 | led.duty_u16(duty) # 65535 is max 43 | 44 | def scan(): 45 | for i in range(90,180): 46 | servo1.move_to(i) 47 | utime.sleep_ms(SMOOTH_TIME) 48 | 49 | for i in range(180,89, -1): 50 | print(i) 51 | servo1.move_to(i) 52 | utime.sleep_ms(SMOOTH_TIME) 53 | 54 | 55 | for i in range(90,-1,-1): 56 | servo1.move_to(i) 57 | utime.sleep_ms(SMOOTH_TIME) 58 | 59 | for i in range(0,91): 60 | print(i) 61 | servo1.move_to(i) 62 | utime.sleep_ms(SMOOTH_TIME) 63 | 64 | 65 | while True: 66 | scan() 67 | fade_led() 68 | 69 | ``` 70 | 71 | In the code above, we simply define the two functions, one for the LED fade and the other to scan/move the servo back and forth. Then we call each of them while loop indefinitely. 72 | 73 | Copy and paste the code above into Thonny and run it. 74 | 75 | You should see the servo move back and forth and then the LED fade up and then down. But they will not happen at the same time. Now you could do a lot of fancy coding to make this work in a single threaded way, but with the Pico, you've got two cores, so let's use them! 76 | 77 | Now we will alter the code slightly to run the servo scan in a second thread, while the main thread handles the LED fade. 78 | 79 | Here's the code: 80 | 81 | ``` Python 82 | from machine import Pin,PWM 83 | import utime 84 | from sg90 import servo 85 | import _thread 86 | 87 | 88 | # Initialize LED 89 | led = PWM(Pin(16)) 90 | led.freq(500) 91 | 92 | # Initiliaze Servo 93 | servo1 = servo(15) 94 | SMOOTH_TIME = 10 95 | 96 | def fade_led(): 97 | for duty in range(0,65535,1): 98 | led.duty_u16(duty) # 65535 is max 99 | for duty in range(65535,0,-1): 100 | led.duty_u16(duty) # 65535 is max 101 | 102 | def scan(): 103 | for i in range(90,180): 104 | servo1.move_to(i) 105 | utime.sleep_ms(SMOOTH_TIME) 106 | 107 | for i in range(180,89, -1): 108 | servo1.move_to(i) 109 | utime.sleep_ms(SMOOTH_TIME) 110 | 111 | 112 | for i in range(90,-1,-1): 113 | servo1.move_to(i) 114 | utime.sleep_ms(SMOOTH_TIME) 115 | 116 | for i in range(0,91): 117 | servo1.move_to(i) 118 | utime.sleep_ms(SMOOTH_TIME) 119 | 120 | # define a function to execute in the second thread 121 | def second_thread_func(): 122 | while True: 123 | scan() 124 | 125 | # Start the second thread 126 | _thread.start_new_thread(second_thread_func,()) 127 | 128 | # Below executes in the main(first) thread. 129 | while True: 130 | fade_led() 131 | 132 | ``` 133 | 134 | Notice in the code above, we've added an import for `_thread`. This gives us access to the [thread libraries](https://docs.python.org/3.10/library/_thread.html#module-_thread). We then defined a new function called `second_thread_func()` to define what we want to do in our new thread, which in our case, is to loop forever while scanning. 135 | Then we use the `_thread` library's [start_new_thread()](https://docs.python.org/3.10/library/_thread.html#thread.start_new_thread) function to spawn a new thread and excute our function. In the main while loop, we just execute our `fade_led()` function over and over again. 136 | 137 | **NOTE** In Thonny when executing code with threads, it can have issues stopping both threads, so you may have to use a `CTRL + D` to do a "SOFT BOOT" to fully stop your code. This can also be found by going to the **RUN** menu and then **Send EOF / Soft reboot** option. 138 | 139 | Try running your new code and if you did everything right, then you should see the servo moving and the LED fading in and out at the same time. 140 | 141 | If you got this to work, pat your head and rub your tummy at the same time! 142 | 143 | 144 | ## Sharing Data Between Threads 145 | 146 | What if I need to pass information from one Thread to another. Well in the full blown Python ecosystem, you'd have access the [queue](module) which is a great way of asynchronously and safely passing data between threads. However, as of this time, this does not exist in MicroPython. So, to share data in MicroPython between running threads, I've only been able to succeed with [global variables](https://www.freecodecamp.org/news/python-global-variables-examples/). Probably not the best solution, but I can't find a better way within MicroPython. 147 | 148 | We are going to modify the code above now to have the main thread calculate how fast the servo should be scanning by increasing the speed(actually the step) the servo uses to rotate. 149 | I've added a function called `set_servo_speed()` which retuns the value the servo should step at... it starts at 1 and every 5 seconds it increases it by 1. 150 | 151 | Here's the whole code: 152 | ```Python 153 | from machine import Pin,PWM 154 | import utime 155 | from sg90 import servo 156 | import _thread 157 | 158 | 159 | # Initialize LED 160 | led = PWM(Pin(16)) 161 | led.freq(500) 162 | 163 | # Initiliaze Servo 164 | servo1 = servo(15) 165 | SMOOTH_TIME = 20 166 | servo_speed = 1 167 | 168 | def fade_led(): 169 | for duty in range(0,65535,1): 170 | led.duty_u16(duty) # 65535 is max 171 | for duty in range(65535,0,-1): 172 | led.duty_u16(duty) # 65535 is max 173 | 174 | def scan(): 175 | stepping = servo_speed 176 | for i in range(90,180, stepping): 177 | servo1.move_to(i) 178 | utime.sleep_ms(SMOOTH_TIME) 179 | 180 | for i in range(180,89, -stepping): 181 | servo1.move_to(i) 182 | utime.sleep_ms(SMOOTH_TIME) 183 | 184 | 185 | for i in range(90,-1,-stepping): 186 | servo1.move_to(i) 187 | utime.sleep_ms(SMOOTH_TIME) 188 | 189 | for i in range(0,91, stepping): 190 | servo1.move_to(i) 191 | utime.sleep_ms(SMOOTH_TIME) 192 | 193 | 194 | # define a function to execute in the second thread 195 | def second_thread_func(): 196 | while True: 197 | scan() 198 | print("servo_speed=", servo_speed) 199 | utime.sleep_ms(2000) 200 | # Start the second thread 201 | _thread.start_new_thread(second_thread_func,()) 202 | 203 | # every 5 second increase servo speed 204 | last_time_checked = utime.ticks_ms() 205 | def set_servo_speed(): 206 | global last_time_checked 207 | diff_time = utime.ticks_diff(utime.ticks_ms(), last_time_checked) 208 | if(diff_time > 5000): 209 | last_time_checked = utime.ticks_ms() 210 | return (servo_speed + 1) 211 | else: 212 | return servo_speed 213 | 214 | # Below executes in the main(first) thread. 215 | while True: 216 | fade_led() 217 | servo_speed = set_servo_speed() 218 | 219 | ``` 220 | 221 | Notice now the `scan()` function uses the global variable called `servo_speed` to set it's `stepping` variable which controls how fast the servo rotates back. 222 | 223 | Run the code above and you should see the servo increase in movement speed every 5 seconds. 224 | 225 | Now this is a trivial example, but if you needed to control how fast that servo is using some input in the main thread, this is the way you could do that. 226 | **Hint** This will be useful in the final game! 227 | 228 | ## References: 229 | 230 | - [Threading on the Pico Tutorial](https://www.electrosoftcloud.com/en/multithreaded-script-on-raspberry-pi-pico-and-micropython/) 231 | 232 | - [Threading MicroPython Docs](https://docs.micropython.org/en/latest/library/_thread.html) 233 | - [Threading Python Docs](https://docs.python.org/3.10/library/_thread.html#module-_thread) 234 | -------------------------------------------------------------------------------- /labs/14_adc_photoresistor.md: -------------------------------------------------------------------------------- 1 | # Reading Analog Inputs 2 | 3 | ## Overview 4 | 5 | Now we are going to switch gears and go back to working with our Photoresistor (or light-dependent resistor). So, far the only input we've worked with in our code on the Pico is with our button. A button is a simple binary type of input. That is it only has two states; it's either on or it's off. However, a lot of sensors, like our Photoresistor, are analog and not binary. Analog meaning there's a range of values that it can produce instead of a simple on or off. 6 | 7 | 8 | ## Working with Analog inputs 9 | 10 | To work with analog sensors on the Pico, we will need to use the Analog to Digital specific pins on the Pico. This is because internally the Pico deals with digital signals; therefore, to work with analong inputs, the Pico has to translate the analog signals to digital through an aptly named Analog-to-Digital Convertor(ADC). Luckily an Analog-to-Digital convertor is built into the Pico(unlike the normal RaspberryPi's). There are 3 pins that give access to the ADC on the Pico. See the image below to identify the ADC GPIO pins: 11 | 12 | ![ADC GPIO Pins](/images/adcpins.PNG) 13 | 14 | 15 | ## What to do 16 | 17 | We will now plug our Photoresistor back into the board and write some code to read values that will vary based on the amount of light hitting our light-dependent resistor. 18 | 19 | You can skip to the wiring diagram below and just follow it, but below is more descriptive instructions. 20 | 21 | Clear the board except for the wires connecting to the power rails. 22 | Then add the photoresistor with one leg into column 35 and the other leg in column 38. Connect the leg of the photoresistor in column 38 to the 3.3v power rail. 23 | 24 | Now connect the leg of the photoresistor in column 35(left leg) to the pin on the Pico in Column 7, Row I or J (this is our ADC pin). Now connect that same leg of the photoresistor in column 35 to ground with a 10K resistor. 25 | 26 | Resistors are identified by the pattern of their color bands, some have 4 bands and others have 5. For 10k resistors: 27 | | 4 Band Color Pattern | 5 Band Color Pattern | 28 | | --- | --- | 29 | | Brown-Black-Orange-Gold | Brown-Black-Black-Red-Gold | 30 | 31 |
32 | Want to read why need the 10K resistor, expand this. 33 | The 10K resistor is needed to create what's called a voltage divider. I'd like to explain exactly what that means, but I can't... I'm an electronics noob. But I think the way it works is that the voltage divider causes a disturbance in the force by disrupting the midi-chlorian flow and therefore causes the flux capacitor to emit a lesser charge through the proton pack than it normally would. If you are more confused after reading my nonsensical description, then you understand as much about voltage dividers as I do.
Seriously though, the 10K resistor in parallel with the photoresistor allows us to get a wide range of values when reading the resistance. Here's a good article that goes into more detail: Spark Fun Voltage Dividers 34 |
35 | 36 | 37 | 38 | 39 | ###### Wiring Diagram 40 | ![Servo Diagram](/images/13_adc_photoresistor_bb.png) 41 | 42 | 43 | Once everything is wired, we will write the code to work with GPIO pin #28 and configure it as an ADC input. We will read the values from it and use a simple formula to convert that to a volage reading. 44 | 45 | You can copy the simple code below to display the values read from the photoresistor. 46 | 47 | Here's the code: 48 | 49 | ``` Python 50 | from machine import Pin, ADC 51 | import utime 52 | 53 | photoresistor_value = machine.ADC(28) 54 | conversion_factor = 3.3/(65535) 55 | 56 | while True: 57 | photo_reading = photoresistor_value.read_u16() * conversion_factor 58 | print("Voltage Reading: ",photo_reading) 59 | utime.sleep(0.2) 60 | ``` 61 | 62 | The ADC class from the machine library makes is super simple to work with analong input. The **conversion_factor** allows us to take the raw 16bit integer value read from the photoresistor and change it into a voltage reading. Recall we are working with 3.3Volts. So, what we end up is seeing the voltage reading of the circuit. The more light the less resistance and the higher the reading. Less light means more resistance and therefore lower voltage. 63 | 64 | Run the code and watch the values in the terminal change as you change the amount of light hitting the resistor. Try covering it up and shining your phone's light on it. 65 | 66 | 67 | ## Optional Stretch goal 68 | 69 | There's no code given for this stretch goal. But if you'd like to have some fun, use the value read from the photoresistor to control the brightness of an LED. 70 | 71 | Use PWM to make the LED get brighter as more light enters the photoresistor and make the LED get dimmer when there's less light hitting the photoresistor. 72 | 73 | 74 | ## References: 75 | 76 | [Voltage Divider Explanation](https://learn.sparkfun.com/tutorials/voltage-dividers) 77 | 78 | [Pico ADC Explanation and Tutorial](https://microcontrollerslab.com/raspberry-pi-pico-adc-tutorial/) 79 | -------------------------------------------------------------------------------- /labs/15_seven_segment.md: -------------------------------------------------------------------------------- 1 | # 7 Segment Display 2 | 3 | ## Overview 4 | 5 | We are going to get into the exciting world of 7 segment displays. 6 | ##### TM1637 7 Segment Display 7 | ![TM1637 7 Segment Display](/images/tm1637.jpeg) 8 | 9 | 7 Segment displays are called such because each number is made up of 7 little bars or segments. These are perfect for outputting any number and even some words/letters. 10 | 11 | We are going to learn to use our 7 segment display to output the voltage level read from our photoresistor. 12 | 13 | 14 | ## TM1637 7 Segment Display 15 | 16 | The 7 segment display we are working with is the [TM1637](https://www.amazon.com/HiLetgo-Digital-Segment-Display-Arduino/dp/B01DKISMXK/ref=sr_1_1_sspa?keywords=tm1637&qid=1671206265&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEyRVUwNTVUTTQyVUEmZW5jcnlwdGVkSWQ9QTA5OTU4NDVITEZHSkYzRzBNRUQmZW5jcnlwdGVkQWRJZD1BMDU1NjUxNzI2SVNONk5XSjkzNkQmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl). The TM1637 display is actually named after the [drive control integrated circuit](https://www.makerguides.com/wp-content/uploads/2019/08/TM1637-Datasheet.pdf) that drives the LEDs. It's this circuit that makes it possible to only use 2 signal pins to control all the segments. (The other two pins are for power). 17 | 18 | ## What to do 19 | 20 | To use the TM1637 7 segment display, we are going to do what any good developer does and steal...uhmm... borrow someone else's library that makes it super simple to work with the display. 21 | 22 | We aren't stealing, **MCAUSER** on github was kind enough to make a MicroPython compatible library available for anyone to use. Go to the tm1637 library here: [TM1637 library](https://github.com/mcauser/micropython-tm1637/blob/master/tm1637.py) and copy it's contents into a new file in Thonny and save on Pico as **tm1637.py**. 23 | 24 | Now follow the diagram below to wire the 7 segment display up to the Pico. 25 | 26 | ###### Wiring Diagram 27 | ![Servo Diagram](/images/14_seven_segment_bb.png) 28 | 29 | 30 | Once everything is wired, we will write the code to work with GPIO pin #0 and #1. We are still using the same code to read the voltage from the Photoresistor, but we will add the code to use our tm1637 library to write those values out to the display. 31 | 32 | You can copy the simple code below to display the values read from the photoresistor. 33 | 34 | Here's the code: 35 | 36 | ``` Python 37 | from machine import Pin, ADC 38 | import tm1637 39 | import utime 40 | from math import modf 41 | 42 | display = tm1637.TM1637(clk=Pin(1), dio=Pin(0)) 43 | 44 | photoresistor_value = machine.ADC(28) 45 | conversion_factor = 3.3/(65535) 46 | 47 | def split_voltage(volts): 48 | voltage_rounded = round(volts, 2) 49 | print("Rounded:", voltage_rounded) 50 | dec,whole = modf(voltage_rounded) 51 | whole = int(whole) 52 | dec = int(dec * 100) 53 | return dec, whole 54 | 55 | def write_voltage_to_dispay(volts): 56 | # round voltage to 2 digits after decimal 57 | dec_num,whole_num=split_voltage(volts) 58 | print("whole", whole_num) 59 | print("dec", dec_num) 60 | display.numbers(whole_num, dec_num, True) 61 | 62 | 63 | while True: 64 | photo_reading = photoresistor_value.read_u16() * conversion_factor 65 | print("Voltage Reading: ",photo_reading) 66 | display.numbers(12,34, True) 67 | write_voltage_to_dispay(photo_reading) 68 | utime.sleep(0.2) 69 | 70 | 71 | ``` 72 | 73 | Run the code and test it! 74 | 75 | If it works, display your biggest grin on your face! 76 | 77 | ## References: 78 | 79 | [Repo for TM1637](https://github.com/mcauser/micropython-tm1637) 80 | 81 | [Test Library for TM1637 from MCAUSER](https://raw.githubusercontent.com/mcauser/micropython-tm1637/master/tm1637_test.py) 82 | -------------------------------------------------------------------------------- /labs/16_button_led_reaction_time.md: -------------------------------------------------------------------------------- 1 | # Using a button and LED to create a reaction time game 2 | 3 | ## Overview 4 | 5 | Lets use what we learned in lab 8 to create a simple game with only a button and an LED. Our goal is to light up the LED after a random amount of time and then capture how long it takes the player to press the button. Once we've captured the time, in milliseconds, print it to the screen. 6 | 7 | 8 | 9 | ## What to do 10 | 11 | Lets wire this exactly how Lab 8 is wired! 12 | 13 | Grab your BLUE LED or any LED rated for 3volts. Put the long pin into column 30 and then the short pin into column 31. 14 | 15 | Add your button back to the breadboard putting the far right pins of the button into column 40. Remember to keep the slot under the button vertical (in line with the columns). Connect the far right pin on column 40 to the positive power rail. 16 | Connect the left side of the button to the GP17 pin on the Pico which is in column 19 on the breadboard. 17 | 18 | ![Button Diagram](/images/8_button_pico_bb.png) 19 | 20 | 21 | Lets start with the code from lab 8 which will turn the LED on when the button is pressed. Obviously this won't work for this lab, but it's a great starting point. 22 | 23 | Here's the starting code: 24 | 25 | ``` Python 26 | from machine import Pin 27 | 28 | led = Pin(16, Pin.OUT) 29 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 30 | 31 | while True: 32 | if button.value()==True: 33 | print("Button Pressed!") 34 | led.value(1) 35 | else: 36 | led.value(0) 37 | 38 | 39 | ``` 40 | 41 | We will need to use the `random` library to generate a random time to wait before turning on the LED, here's how you do that 42 | 43 | ``` Python 44 | import random 45 | # Generate a random delay between 1 and 5 seconds 46 | delay = random.randint(1, 5) 47 | ``` 48 | 49 | We will need to wait that random amount of time and also calculate how long it took for the player to press the button with the `utime` library, here's how 50 | 51 | ``` Python 52 | import utime 53 | 54 | # Wait for the random delay 55 | utime.sleep(delay) 56 | 57 | # Capture the current time 58 | start_time = utime.ticks_ms() 59 | ``` 60 | 61 | Take these few hints and see if you can implement the rest of the game. 62 | 63 |
64 | Don't worry if you can't. Click here to see working code! 65 | 66 | ``` Python 67 | import utime 68 | import random 69 | from machine import Pin 70 | 71 | # Set up the LED pin 72 | led = Pin(16, Pin.OUT) 73 | 74 | # Set up the button pin 75 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 76 | 77 | # Turn off the LED incase it's already on 78 | led.off() 79 | 80 | # Generate a random delay between 1 and 5 seconds 81 | delay = random.randint(1, 5) 82 | 83 | # Wait for the random delay 84 | utime.sleep(delay) 85 | 86 | led.on() 87 | 88 | start_time = utime.ticks_ms() 89 | # Wait for the user to press the button 90 | while not button.value(): 91 | pass 92 | end_time = utime.ticks_ms() 93 | 94 | # Calculate and display the time taken to press the button 95 | duration = end_time - start_time 96 | print("Button pressed after", duration, "milliseconds!") 97 | 98 | led.off() 99 | ``` 100 |
101 | 102 | Play the game a few times and then yell out your fastest reaction time! 103 | 104 | ## Stretch Goal 105 | 106 | Change the code above so the game automatically restarts so you don't have to press Run in Thonny everytime 107 | 108 |
109 | To see working code for this click the arrow beside here to expand the code! 110 | 111 | 112 | ```Python 113 | import utime 114 | import random 115 | from machine import Pin 116 | 117 | # Set up the LED pin 118 | led = Pin(16, Pin.OUT) 119 | 120 | # Set up the button pin 121 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 122 | 123 | while True: 124 | # Turn off the LED incase it's already on 125 | led.off() 126 | 127 | # Generate a random delay between 1 and 5 seconds 128 | delay = random.randint(1, 5) 129 | 130 | # Wait for the random delay 131 | utime.sleep(delay) 132 | 133 | led.on() 134 | 135 | start_time = utime.ticks_ms() 136 | # Wait for the user to press the button 137 | while not button.value(): 138 | pass 139 | end_time = utime.ticks_ms() 140 | 141 | # Calculate and display the time taken to press the button 142 | duration = end_time - start_time 143 | print("Button pressed after", duration, "milliseconds. The game will automatically restart") 144 | 145 | led.off() 146 | utime.sleep(2) 147 | ``` 148 |
149 | -------------------------------------------------------------------------------- /labs/Joystick_intro.md: -------------------------------------------------------------------------------- 1 | # Joysticks 2 | 3 | ## How do Joysticks work? 4 | 5 | ![Joystick](https://m.media-amazon.com/images/I/71KNhxKbNBL._AC_SX425_.jpg) 6 | 7 | Joysticks are input devices that move on a base which communicates the angle to the device its controlling. 8 | Joysticks are commonly used in controllers and aviation cockpits. Joysticks detect input direction 9 | with eletronic switches, Hall effect, strain guage or potentiometers but most controllers today seem to use 10 | potentiometers. 11 | 12 | ## Getting started! 13 | 14 | The joystick for this lab uses potentiometers internally and can detect movement in the x axis, the why axis, and can detect when the joystick is pushed in like a button. 15 | The joystick will have 5 pins: 5v, ground, vrx(voltage proportional to X axis), vry(voltage proportional to y axis) and sw(switch). We will need to use the 5v on the pico to power a rail, then after that connect 16 | the ground pin. Now let's connect the vrx, switch, and vry. Vrx will go in GPIO pin 27, Switch in GPIO pin 17 and vry in GPIO pin 26 like shown in the picture. 17 | ![JoystickDiagram](https://github.com/javaplus/PicoProjects/blob/main/images/joystick%202_bb.png?raw=true) 18 | 19 | Now that we have it wired in, we can now write the code that will read the joysticks input and print out the values based on it's motion. Now let's code this puppy up! 20 | 21 | ```python 22 | #code from https://www.youtube.com/watch?v=SJr-HoCwlWg 23 | from machine import Pin, ADC 24 | import utime 25 | 26 | xAxis = ADC(Pin(27)) 27 | yAxis = ADC(Pin(26)) 28 | button = Pin(17,Pin.IN, Pin.PULL_UP) 29 | 30 | while True: 31 | xValue = xAxis.read_u16() 32 | yValue = yAxis.read_u16() 33 | buttonValue = button.value() 34 | buttonStatus = "not pressed" 35 | 36 | 37 | if buttonValue == 0: 38 | buttonStatus = "pressed" 39 | 40 | 41 | print("X: " + str(xValue) + ", Y: " + str(yValue) + " -- button value: " + str(buttonValue) + " button status: " + buttonStatus) 42 | utime.sleep(0.2) 43 | 44 | ``` 45 | Now try running the code above. You should see a steady stream of statements in the console telling you the x and y values as well as if the joystick is pressed. 46 | Increase the value passed to `utime.sleep()` if you want the print statements less frequent, but understand this will mean that the position of your joystick will be read less often. 47 | 48 | Notice the x and y values as the code runs and you move the joystick around. 49 | **NOTE** Most cheap joysticks like the one you probably have may have a dead zone around the center or even worse "freak out" when the joystick is pushed to its max range in some directions. We've noticed that most of the cheaper joysticks when pushed to the extent of their movement in one direction will often falsely show an extreme movement on the other axis as well. That is if you push the joystick full left, it will also show the the joystick is pulled down even if their is now downward movement on the joystick. So, the key understanding here is that electronics can have flaws in them and a lot of cheap electronics don't always work as advertised. So, when running the simple code above watch the values closely and understand the max ranges and sensitivity of your particular joystick. This will help you better write code to handle any peculiarities it may have. 50 | 51 | ## Detecting Direction 52 | 53 | Now let's modify the code slightly by checking the x and y values to try to determine the direction of the joystick. That is we will use the values we read to determine if the joystick is being pushed side to side or up and down. 54 | 55 | Feel free to try to write the code on your own to detect when the joystick is moved left, right, up, or down. An easy way is to just use if statement comparing the values of the x and y values read from the joystick. 56 | 57 | If you'd like to see how to code it we have some code below. 58 | Now let's make more code to further your understanding! 59 | 60 | ```python 61 | #modified code from https://www.youtube.com/watch?v=SJr-HoCwlWg 62 | from machine import Pin, ADC 63 | import utime 64 | 65 | xAxis = ADC(Pin(27)) 66 | yAxis = ADC(Pin(26)) 67 | button = Pin(17,Pin.IN, Pin.PULL_UP) 68 | # while loop to keep checking conditioning 69 | while True: 70 | xValue = xAxis.read_u16() 71 | yValue = yAxis.read_u16() 72 | buttonValue = button.value() 73 | xStatus = "middle" 74 | yStatus = "middle" 75 | buttonStatus = "not pressed" 76 | 77 | # Check the x and y Value to determine the status of the joystick 78 | if buttonValue == 0: 79 | buttonStatus = "pressed" 80 | 81 | if xValue <= 600: 82 | xStatus = "left" 83 | 84 | if xValue >= 60000: 85 | xStatus = "right" 86 | 87 | if yValue <= 600: 88 | yStatus = "up" 89 | 90 | if yValue >= 60000: 91 | yStatus = "down" 92 | 93 | 94 | #printing directions of the joystick 95 | print("X: " + xStatus + ", Y: " + yStatus + " button status: " + buttonStatus) 96 | utime.sleep(0.2) 97 | ``` 98 | 99 | the code checks the axis values to see if the joystick have passed those positions and if so will print the direction of the joystick. 100 | 101 | [you can learn more about joystick here](https://lastminuteengineers.com/joystick-interfacing-arduino-processing/) 102 | 103 | -------------------------------------------------------------------------------- /labs/f01_fire_zee_lasers.md: -------------------------------------------------------------------------------- 1 | # FIRE ZEE LASERS!!!!1!! 2 | 3 | ## Overview 4 | 5 | You are now well prepared for our final objective. What's a mad scientist pre-compiler without a little fun with lasers and target practice?? 6 | 7 | In this part 1 of 3 for our final game you will do the following: 8 | 9 | - Wire the photo resistor through the two little holes in the middle of your target and place the target end cap on one end of the ruler with the photo resistor side facing towards the rest of the ruler 10 | - Detect a button press (use various button labs as a reference)... if this happens the pico should FIRE ZEE LASER at the photoresistor (our target). 11 | - You then need to read the current value of the photoresistor to see if you scored a "hit", that is did the value of the photoresistor change dramatically when the laser was shining on it. 12 | - Once the button has been pressed we need to lock out the player from another attempt for 5 seconds (use debounce lab as a reference) 13 | 14 | 15 | ## What to do 16 | 17 | ### Build the Target: 18 | 19 | Put the photo resistor legs through the two holes in the center of the target. The legs should come out the back flat side of the target. On the backside of the target, spread the legs away from each other and then bend them towards the front of the target around the target legs as seen in the picture below. This keeps the legs from touching each other and helps hold the photoresistor snugly in the target. Connect female ends of male to female wires to the legs of the photoresistor. 20 | 21 | ![Target Pic Front](/images/target_zoom.jpg) 22 | ![Target Pic Back](/images/target_back.jpg) 23 | ![Target Pic Front](/images/target_full.jpg) 24 | 25 | 26 | Note: This is your first time playing with a laser in our lab, it hooks up just like an LED! The Red wire on the laser is positive and the blue wire is negative/ground. 27 | 28 | 29 | Here is the wiring diagram: 30 | 31 | ![Game Part 1 Diagram](/images/game_1_lab_bb.png) 32 | 33 | 34 | Once you have the pico wired, take some time to attempt to code the points outlined in the overview using the old labs. 35 | 36 | For coding the photoresistor, if you remove the **conversion_factor** we used in our lab, you will have a wide range of values. That is close to zero when there is no light, and close to 65535 under a super bright light. This will give you a wide range to detect "normal" light conditions verses when the laser is shining directly on the photoresistor. 37 | **WARNING** When working with the laser, DON'T SHOOT YOUR EYE OUT! Or anyone elses. :) 38 | 39 | If you've given that a good effort and need a little guidance check out the code solution by clicking on the link below: 40 | 41 |
Code! 42 | 43 | ```Python 44 | 45 | from machine import Pin,PWM,ADC 46 | from math import modf 47 | import utime 48 | 49 | photoresistor_value = machine.ADC(28) 50 | 51 | laser = Pin(20, Pin.OUT) 52 | laser.value(0) 53 | 54 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 55 | 56 | # debounce utime saying wait 5 seconds between button presses 57 | DEBOUNCE_utime = 5000 58 | 59 | # debounce counter is our counter from the last button press 60 | # initialize to current utime 61 | debounce_counter = utime.ticks_ms() - DEBOUNCE_utime 62 | 63 | # Function to handle when the button is pressed 64 | def button_press_detected(): 65 | global debounce_counter 66 | current_utime = utime.ticks_ms() 67 | 68 | # Calculate utime passed since last button press 69 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 70 | 71 | # print("utime passed=" + str(utime_passed)) 72 | if (utime_passed > DEBOUNCE_utime): 73 | print("Button Pressed!") 74 | # set debounce_counter to current utime 75 | debounce_counter = utime.ticks_ms() 76 | 77 | fire_the_laser() 78 | #else: 79 | #print("Not enough utime") 80 | 81 | def fire_the_laser(): 82 | print("FIRE ZEE LASERS!") 83 | enable_laser() 84 | check_target() 85 | disable_laser() 86 | 87 | def enable_laser(): 88 | laser.value(1) 89 | utime.sleep_ms(2000) 90 | 91 | def disable_laser(): 92 | utime.sleep_ms(1000) 93 | laser.value(0) 94 | 95 | def check_target(): 96 | global photo_reading 97 | photo_reading = photoresistor_value.read_u16() 98 | print("Laser Voltage Reading: ",photo_reading) 99 | 100 | # Below executes in the main(first) thread. 101 | while True: 102 | 103 | if button.value()==True: 104 | button_press_detected() 105 | 106 | 107 | ``` 108 |
109 | 110 | 111 | If you got all of this to work, do your best Dr. Evil laugh at a volume that the instructors are sure to hear! 112 | It's finally time for some sharks with some lasers on their heads. 113 | 114 | -------------------------------------------------------------------------------- /labs/f02_sharks_with_lasers.md: -------------------------------------------------------------------------------- 1 | # One Simple Request: Sharks with Frickin Laser Beams 2 | 3 | ## Overview 4 | 5 | In this part 2 of 3 for our final game you will do the following: 6 | 7 | - Setup the game stage on our trusty rulers (image below) 8 | - Mount the laser to your sharkhead 9 | - Mount the servo on the ruler end cap 10 | - Mount the shark on the servo (see below for setting "home" on your servo) 11 | - Add code that will pan our servo back and forth (in its own thread) 12 | - Add code to manage the lighting of 3 LEDs. Each LED will represent a "life" during our game. They should all be turned on by default. 13 | - Create a function that will turn off one of the remaining lit LEDs. We will use this later on in lab F03 when we determine that we missed one of our laser shots. 14 | - Within your scan method you should have a way to detect if the laser has been fired (button was pressed). The servo should stop moving when this happens. (Hint: implement a global kill_flag) 15 | 16 | ## What to do 17 | 18 | ### Set up the Shark: 19 | 20 | Install the laser into the shark head. You will have to disconnect your laser (the short wires) from the male-to-female wires to feed the laser wires down through the hole in the top of the shark head. Once the laser wires come out the bottom of the shark, reconnect them to the female ends of the male-to-female wires that go to the breadboard. 21 | 22 | Now install the servo **upside down** into the shark (image below). The wires for the laser and the wires for the servo, should go towards the front of the shark. There is a notch in the bottom of the shark model under the hole for the laser wires that should allow the laser wires and the servo wires to not get in the way of pushing the servo up into the shark. 23 | #### Bottom side of Shark: 24 | ![Shark Bottom](/images/shark_bottom.jpg) 25 | 26 | **NOTE** If the servo isn't snug in the bottom of the shark you can add some tape around the base of the servo which goes up into the shark to make it fit nice and tight. 27 | 28 | 29 | ### Setting a home direction for the laser 30 | 31 | Now connect the servo's power wire(red middle) to the 5volt rail. Connect the servo's ground wire (dark brown) to any ground(-) rail. Connect the orange/yellowish signal wire of the servo to GP15 which is Column 20 on the bottom side of the Pico. If need be, reference the [wiring diagram](#wiring-to-the-pico) further down the page. 32 | **BEFORE** snapping the servo onto the base, run the following code in the shell of Thonny to allow us to set a "home" for the shark and align the laser. 33 | 34 | ```Python 35 | from sg90 import servo 36 | 37 | servo1 = servo(15) 38 | servo.move_to(90) 39 | 40 | ``` 41 | 42 | After this code is run and your servo adjusts to 90, place the servo into the end cap on the ruler. Pointing straight towards your target at the other end. 43 | 44 | ![Shark Side](/images/shark_side.jpg) 45 | 46 | After snapping the shark servo onto the base and sliding it on the ruler, we can aim the laser. So, connect the laser back up with the red wire going to GP20 and the blue wire to ground. Once connected run this code in the terminal to turn on the laser. 47 | 48 | ```Python 49 | from machine import Pin 50 | 51 | laser = Pin(20, Pin.OUT) 52 | laser.value(1) 53 | 54 | ``` 55 | 56 | Your setup should look like this now with the laser on and hitting the target: 57 | 58 | ![Game Stage Illustration](/images/gamestage.png) 59 | 60 | With the laser on, adjust it up and down to hit the center line of the target. The laser doesn't need to hit the bullseye(photoresistor) directly at this time. The laser just needs to hit at the same height as the bullseye. For our game, the shark will rotate back and forth and you will have to stop the shark and "fire" the laser at the right time to hit the bullseye. So, at this time just make sure the laser is not hitting high or low... left and right of the bullseye is ok if it's at the same height as the bullseye. 61 | 62 | 63 | ## Wiring to the Pico 64 | 65 | Here is the wiring diagram with the additions for this lab. **NOTE** The top half of the diagram remains the same from the last lab. The additions are all on the bottom half of the breadboard with the exception of the wires connecting the 3 LEDS to the Pico cross over the top half of the breadboard to the Pico's GP pins (GP19,GP18, and GP17). 66 | 67 | ![Game Part 2 Diagram](/images/game_2_lab_bb.png) 68 | 69 | 70 | ## Get your hands dirty 71 | 72 | Once you have the pico wired and the game stage set as seen above, take some time to attempt to code the points outlined in the overview using the old labs, building on our code from the Fire Zee Lasers Lab. 73 | 74 | **Code!**
If you've given that a good effort and need a little guidance check out the code solution by clicking here. 75 | ```Python 76 | 77 | 78 | from machine import Pin,PWM,ADC 79 | from math import modf 80 | import utime, _thread, tm1637, sys 81 | from sg90 import servo 82 | 83 | photoresistor_value = machine.ADC(28) 84 | 85 | # Initialize LEDs to on at beginning 86 | # These LEDs indicate lives remaining 87 | led1 = Pin(16, Pin.OUT) 88 | led1.value(1) 89 | led1_on = True 90 | led2 = Pin(18, Pin.OUT) 91 | led2.value(1) 92 | led2_on = True 93 | led3 = Pin(19, Pin.OUT) 94 | led3.value(1) 95 | led3_on = True 96 | lives_left = True 97 | 98 | laser = Pin(20, Pin.OUT) 99 | laser.value(0) 100 | 101 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 102 | 103 | # Initialize Servo 104 | servo1 = servo(15) 105 | SMOOTH_TIME = 80 106 | servo_speed = 1 107 | 108 | # flag so the laser can interrupt the scan cycle 109 | kill_flag = False 110 | 111 | # debounce utime saying wait 5 seconds between button presses 112 | DEBOUNCE_utime = 5000 113 | 114 | # debounce counter is our counter from the last button press 115 | # initialize to current utime 116 | debounce_counter = utime.ticks_ms() - DEBOUNCE_utime 117 | 118 | def scan(current_servo): 119 | stepping = servo_speed 120 | for i in range(45,130, stepping): 121 | if (kill_flag): 122 | break 123 | current_servo.move_to(i) 124 | utime.sleep_ms(SMOOTH_TIME) 125 | 126 | for i in range(130,45, -stepping): 127 | if (kill_flag): 128 | break 129 | current_servo.move_to(i) 130 | utime.sleep_ms(SMOOTH_TIME) 131 | 132 | # define a function to execute in the second thread 133 | def second_thread_func(): 134 | while True: 135 | # fix for import failing in second thread when it's inside a function 136 | servo2 = servo1 137 | stepping = servo_speed 138 | scan(servo2) 139 | #print("servo_speed=", servo_speed) 140 | utime.sleep_ms(100) 141 | 142 | # Start the second thread 143 | _thread.start_new_thread(second_thread_func,()) 144 | 145 | # Function to handle darkening one LED 146 | def remove_led(): 147 | global led3_on, led3, led2_on, led2, led1_on, led1, lives_left 148 | if(led3_on): 149 | led3.value(0) 150 | led3_on = False 151 | else: 152 | if(led2_on): 153 | led2.value(0) 154 | led2_on = False 155 | else: 156 | led1.value(0) 157 | led1_on = False 158 | lives_left = False 159 | end_of_game_buzz() 160 | 161 | # Function to handle when the button is pressed 162 | def button_press_detected(): 163 | global debounce_counter 164 | current_utime = utime.ticks_ms() 165 | 166 | # Calculate utime passed since last button press 167 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 168 | 169 | # print("utime passed=" + str(utime_passed)) 170 | if (utime_passed > DEBOUNCE_utime): 171 | print("Button Pressed!") 172 | # set debounce_counter to current utime 173 | debounce_counter = utime.ticks_ms() 174 | 175 | fire_the_laser() 176 | #else: 177 | #print("Not enough utime") 178 | 179 | def fire_the_laser(): 180 | print("FIRE ZEE LASERS!") 181 | global servo_speed 182 | 183 | enable_laser() 184 | check_target() 185 | disable_laser() 186 | 187 | def enable_laser(): 188 | global kill_flag 189 | kill_flag = True 190 | laser.value(1) 191 | utime.sleep_ms(2000) 192 | 193 | def disable_laser(): 194 | global kill_flag 195 | utime.sleep_ms(1000) 196 | kill_flag = False 197 | laser.value(0) 198 | 199 | def check_target(): 200 | global photo_reading 201 | photo_reading = photoresistor_value.read_u16() 202 | print("Laser Voltage Reading: ",photo_reading) 203 | 204 | # Below executes in the main(first) thread. 205 | while True: 206 | if button.value()==True: 207 | button_press_detected() 208 | 209 | 210 | 211 | ``` 212 |
213 | 214 | 215 | 216 | If you made it this far, stand up, stretch, and give someone a fist bump! 217 | -------------------------------------------------------------------------------- /labs/f03_grand_finale.md: -------------------------------------------------------------------------------- 1 | # Three Lives and a Scoreboard 2 | 3 | ## Overview 4 | 5 | In this grand finale for our game you will do the following: 6 | 7 | - Add a seven segment display to keep score 8 | - Add logic for a successful target hit: 9 | - Make your buzzer buzz a happy buzz 10 | - Add one point to the hit counter (make sure it updates on your seven segment display) 11 | - Increase the step of the pwm running in the thread to speed up your shark to make each level harder to beat 12 | - Add logic for a missed laser fire: 13 | - Make your buzzer buzz a sad buzz 14 | - Darken one of the three LEDs (you start with 3 lives) 15 | - Add logic for once you run out of lives to buzz a fun little buzz indicating the game has ended. 16 | 17 | 18 | ## What to do 19 | 20 | Here is the wiring diagram for the last stage of the game. The new additions are the black buzzer in the bottom right corner of the breadboard and the 7 segment display on the far left of the diagram. Those are the only 2 new things you need to wire up. In the picture below, you will see the photoresistor has moved just to make the picture smaller, but the wiring for it has not changed. 21 | 22 | The Buzzer's positive side connects to GP9 on the Pico (column 12 on the bottom) and then the negative side to ground. The 7 segment display connects to GP0 and GP1 (column 1 and 2 on the bottom) and also connects to the 5V positive rail and ground. 23 | 24 | ![Game Finale Diagram](/images/game_3_lab_bb.png) 25 | 26 | 27 | Once you have the pico wired and the game stage set as seen above, take some time to attempt to code the points outlined in the overview using the old labs, building on our code from the Sharks With Laser Beams lab. 28 | 29 | Helpful hint: Set a baseline photores value to determine if a hit happened or not from the laser (in the code solution provided below I used a 20% variance between an initial photores reading and the reading pulled in during a laser attempt) 30 | 31 | **Code here:**
If you've given that a good effort and need a little guidance check out the code solution by clicking here. 32 | ```Python 33 | 34 | 35 | from machine import Pin,PWM,ADC 36 | from math import modf 37 | import utime, _thread, tm1637, sys 38 | from sg90 import servo 39 | 40 | photoresistor_value = machine.ADC(28) 41 | initial_photo_reading = photoresistor_value.read_u16() 42 | 43 | # Initialize LEDs to on at beginning 44 | # These LEDs indicate lives remaining 45 | led1 = Pin(16, Pin.OUT) 46 | led1.value(1) 47 | led1_on = True 48 | led2 = Pin(18, Pin.OUT) 49 | led2.value(1) 50 | led2_on = True 51 | led3 = Pin(19, Pin.OUT) 52 | led3.value(1) 53 | led3_on = True 54 | lives_left = True 55 | 56 | laser = Pin(20, Pin.OUT) 57 | laser.value(0) 58 | 59 | button = Pin(17, Pin.IN, Pin.PULL_DOWN) 60 | 61 | # Initialize Score and Display 62 | display = tm1637.TM1637(clk=Pin(1), dio=Pin(0)) 63 | score = 0 64 | display.number(score) 65 | 66 | # Initialize Servo 67 | servo1 = servo(15) 68 | SMOOTH_TIME = 80 69 | servo_speed = 1 70 | 71 | 72 | buzzer = PWM(Pin(9)) 73 | buzzer.freq(1000) 74 | 75 | # flag so the laser can interrupt the scan cycle 76 | kill_flag = False 77 | 78 | # debounce utime saying wait 5 seconds between button presses 79 | DEBOUNCE_utime = 5000 80 | 81 | # debounce counter is our counter from the last button press 82 | # initialize to current utime 83 | debounce_counter = utime.ticks_ms() - DEBOUNCE_utime 84 | 85 | print("Initial Laser Voltage Reading: ", initial_photo_reading) 86 | 87 | # target will recognize a hit when there is a 20% increase in light 88 | target_reading = initial_photo_reading * 1.2 # potentially need a different percentage based on laser and photores being used 89 | print("Target Goal Lighting: ", target_reading) 90 | 91 | def scan(current_servo): 92 | stepping = servo_speed 93 | for i in range(45,130, stepping): 94 | if (kill_flag): 95 | break 96 | current_servo.move_to(i) 97 | utime.sleep_ms(SMOOTH_TIME) 98 | 99 | for i in range(130,45, -stepping): 100 | if (kill_flag): 101 | break 102 | current_servo.move_to(i) 103 | utime.sleep_ms(SMOOTH_TIME) 104 | 105 | # define a function to execute in the second thread 106 | def second_thread_func(): 107 | while True: 108 | # fix for import failing in second thread when it's inside a function 109 | servo2 = servo1 110 | stepping = servo_speed 111 | scan(servo2) 112 | #print("servo_speed=", servo_speed) 113 | utime.sleep_ms(100) 114 | 115 | # Start the second thread 116 | _thread.start_new_thread(second_thread_func,()) 117 | 118 | # Function to handle darkening one LED 119 | def remove_led(): 120 | global led3_on, led3, led2_on, led2, led1_on, led1, lives_left 121 | if(led3_on): 122 | led3.value(0) 123 | led3_on = False 124 | else: 125 | if(led2_on): 126 | led2.value(0) 127 | led2_on = False 128 | else: 129 | led1.value(0) 130 | led1_on = False 131 | lives_left = False 132 | end_of_game_buzz() 133 | 134 | # Function to handle when the button is pressed 135 | def button_press_detected(): 136 | global debounce_counter 137 | current_utime = utime.ticks_ms() 138 | 139 | # Calculate utime passed since last button press 140 | utime_passed = utime.ticks_diff(current_utime,debounce_counter) 141 | 142 | # print("utime passed=" + str(utime_passed)) 143 | if (utime_passed > DEBOUNCE_utime): 144 | print("Button Pressed!") 145 | # set debounce_counter to current utime 146 | debounce_counter = utime.ticks_ms() 147 | 148 | fire_the_laser() 149 | #else: 150 | #print("Not enough utime") 151 | 152 | def fire_the_laser(): 153 | print("FIRE ZEE LASERS!") 154 | global servo_speed 155 | 156 | enable_laser() 157 | check_target() 158 | disable_laser() 159 | 160 | if (photo_reading > target_reading): 161 | its_a_hit() 162 | else: 163 | its_a_miss() 164 | 165 | def enable_laser(): 166 | global kill_flag 167 | kill_flag = True 168 | laser.value(1) 169 | utime.sleep_ms(2000) 170 | 171 | def disable_laser(): 172 | global kill_flag 173 | utime.sleep_ms(1000) 174 | kill_flag = False 175 | laser.value(0) 176 | 177 | def check_target(): 178 | global photo_reading 179 | photo_reading = photoresistor_value.read_u16() 180 | print("Laser Voltage Reading: ",photo_reading) 181 | 182 | def increase_difficulty(): 183 | global servo_speed 184 | servo_speed = servo_speed + 1 185 | 186 | def increase_score(): 187 | global score 188 | score = score + 1 189 | 190 | def display_score(): 191 | display.number(score) 192 | 193 | def its_a_hit(): 194 | print("Nice! - A Hit!") 195 | happy_buzz() 196 | increase_difficulty() 197 | increase_score() 198 | display_score() 199 | print("Score: ", score) 200 | 201 | def its_a_miss(): 202 | print("Ouch - A Miss!") 203 | sad_buzz() 204 | remove_led() 205 | 206 | def happy_buzz(): 207 | print("Happy buzz!") 208 | 209 | buzzer.freq(100000) 210 | for count in range(1,3,1): 211 | buzzer.duty_u16(20000) 212 | utime.sleep_ms(500) 213 | buzzer.duty_u16(0) 214 | 215 | def sad_buzz(): 216 | print("Sad buzz!") 217 | 218 | buzzer.freq(1000) 219 | for count in range(1,3,1): 220 | buzzer.duty_u16(10000) 221 | utime.sleep_ms(500) 222 | buzzer.duty_u16(0) 223 | 224 | def end_of_game_buzz(): 225 | print("End of game jingle buzz!") 226 | for count in range(1,10,1): 227 | buzzer.duty_u16(10000) 228 | buzzer.freq(1000 * count) 229 | utime.sleep_ms(100) 230 | 231 | for count in range(10,1,-1): 232 | buzzer.duty_u16(10000) 233 | buzzer.freq(1000 * count) 234 | utime.sleep_ms(100) 235 | 236 | buzzer.duty_u16(0) 237 | 238 | 239 | 240 | 241 | # Below executes in the main(first) thread. 242 | while True: 243 | if (lives_left): 244 | if button.value()==True: 245 | button_press_detected() 246 | else: 247 | print("Game Over!") 248 | kill_flag = True 249 | sys.exit() 250 | 251 | 252 | 253 | ``` 254 |
255 | 256 | 257 | 258 | 259 | If you got all of this to work, then go for a new high score! and then another! and then another! and then another! 260 | Also if you're still reading this be sure to go find the hidden easter egg image of our first sketch of the shark game. :) 261 | -------------------------------------------------------------------------------- /labs/turret.md: -------------------------------------------------------------------------------- 1 | # Turret! 2 | 3 | Now that you know the basics of a joystick, we will make it control a turret made of servos! 4 | 5 | Before we start with the code, we have to wire our turret in. 6 | 7 | ![turretDiagram](https://github.com/javaplus/PicoProjects/blob/main/images/turret6_bb.png?raw=true) 8 | 9 | 10 | 11 | We will then import a library for it to function. Let's will name it turret.py 12 | 13 | ```python 14 | from machine import Pin, ADC 15 | import machine 16 | import utime 17 | from sg90 import servo 18 | 19 | 20 | class turret: 21 | 22 | 23 | def __init__(self, horizontal_servo_pin, vertical_servo_pin): 24 | self.servo_horiz = servo(horizontal_servo_pin) 25 | self.servo_vert = servo(vertical_servo_pin) 26 | 27 | def center(self): 28 | self.servo_horiz.move_to(90) 29 | self.servo_vert.move_to(90) 30 | 31 | # positive speed moves one direction and negative moves the other 32 | def move_left(self, speed): 33 | if (self.servo_horiz.position + speed) >= 0: 34 | self.servo_horiz.move_to(self.servo_horiz.position - speed) 35 | 36 | def move_right(self, speed): 37 | if (self.servo_horiz.position + speed) <= 180: 38 | self.servo_horiz.move_to(self.servo_horiz.position + speed) 39 | 40 | def move_up(self, speed): 41 | if (self.servo_vert.position + speed) <= 180: 42 | self.servo_vert.move_to(self.servo_vert.position + speed) 43 | 44 | def move_down(self, speed): 45 | if (self.servo_vert.position + speed) >= 0: 46 | self.servo_vert.move_to(self.servo_vert.position - speed) 47 | ``` 48 | 49 | In this library we are making a class and functions for servo movement. This will help us easily move the servos without much knowledge about servos and joysticks. Defining the servos in our main code will give tell the library what servos to use. Now that we have our library, let's make the code. If you don't have the [SG90 Library](https://raw.githubusercontent.com/javaplus/PicoProjects/main/servos/sg90.py) already, go ahead and add it to a seperate file and name it sg90. 50 | Now that you have the sg90 library, it will allow us to control the servo. Now we can start! 51 | 52 | ```python 53 | from machine import Pin, ADC 54 | import utime 55 | from turret import turret 56 | 57 | SMOOTH_TIME = (60) 58 | 59 | xAxis = ADC(Pin(27)) 60 | yAxis = ADC(Pin(26)) 61 | button = Pin(17,Pin.IN, Pin.PULL_UP) 62 | 63 | #turret(servoXpin, servoYpin) 64 | myturret = turret(15,14) 65 | 66 | while True: 67 | xValue = xAxis.read_u16() 68 | yValue = yAxis.read_u16() 69 | buttonValue = button.value() 70 | 71 | #recenters both servos 72 | if buttonValue == 0: 73 | myturret.center() 74 | 75 | #Adjust x and y values based on sensitivity of your joystick 76 | #myturret.move_(direction)(movement_speed) 77 | if xValue <= 48000: 78 | myturret.move_right(5) 79 | 80 | if xValue >= 54000: 81 | myturret.move_left(5) 82 | 83 | if yValue <=46500: 84 | myturret.move_up(5) 85 | 86 | if yValue >= 54000: 87 | myturret.move_down(5) 88 | 89 | utime.sleep_ms(SMOOTH_TIME) 90 | ``` 91 | 92 | What we're doing here is calling functions in the turret library to make the turrets move. 93 | 94 | #### Cool Game for Reference 95 | 96 | Here's a link to a simple game that uses the joystick, turret, laser, and photoresistor. You use the joystick to move the turret which holds the laser and try to get it to hit the photoresistor. If the laser hits the photoresistor, then the LED will light up. 97 | [Game Code](../game/turret_laser_target.py) 98 | -------------------------------------------------------------------------------- /leds/pwmfade.py: -------------------------------------------------------------------------------- 1 | import machine 2 | import utime 3 | 4 | led = machine.PWM(machine.Pin(15)) 5 | led.freq(1000) 6 | 7 | while True: 8 | 9 | # Fade up in brightness 10 | for i in range(0,65535): 11 | #print(i) 12 | led.duty_u16(i) 13 | utime.sleep(.0001) 14 | 15 | # Fade down in brightness 16 | for x in range(65535,0,-1): 17 | #print(x) 18 | led.duty_u16(x) 19 | utime.sleep(.0001) 20 | 21 | -------------------------------------------------------------------------------- /models/madscishark.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/madscishark.3mf -------------------------------------------------------------------------------- /models/picoin_v1.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/picoin_v1.3mf -------------------------------------------------------------------------------- /models/servocap.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/servocap.stl -------------------------------------------------------------------------------- /models/shark.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/shark.3mf -------------------------------------------------------------------------------- /models/targetcap.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/targetcap.3mf -------------------------------------------------------------------------------- /models/turret/Readme.md: -------------------------------------------------------------------------------- 1 | # 3D Models for Turret 2 | 3 | You can use these models to 3D Print parts to assemble turrets that allow X movement (right and left ) and Y movement(up and down) with SG9(Sg90) servos. 4 | -------------------------------------------------------------------------------- /models/turret/TurretFinal-bottomCap.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/turret/TurretFinal-bottomCap.stl -------------------------------------------------------------------------------- /models/turret/TurretFinal-screwPegs.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/turret/TurretFinal-screwPegs.stl -------------------------------------------------------------------------------- /models/turret/TurretFinal-topArm.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/turret/TurretFinal-topArm.stl -------------------------------------------------------------------------------- /models/turret/TurretFinal-topServoMount.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/turret/TurretFinal-topServoMount.stl -------------------------------------------------------------------------------- /models/turret/TurretFinal_baseBottomServoMount.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaplus/PicoProjects/79c1792442a2e393f9bffd0320f18fe0f57f9656/models/turret/TurretFinal_baseBottomServoMount.stl -------------------------------------------------------------------------------- /reference/breadboards.md: -------------------------------------------------------------------------------- 1 | # Breadboards 2 | 3 | 4 | Breadboards are typically used for prototyping electronic circuits. 5 | We will be using a Breadboard for each lab. So, understanding how they work is critical. 6 | 7 | Here is a great link explaining how breadboards work: 8 | [What is a Breadboard and How Do You Use One](https://www.makeuseof.com/tag/what-is-breadboard/) 9 | 10 | #### This illustrates how the different rows of pins are connected: 11 | ![Breadboard](https://static1.makeuseofimages.com/wordpress/wp-content/uploads/2018/06/breadboard_annotated_670-1.jpg?q=50&fit=crop&w=1500&dpr=1.5) 12 | 13 | #### Image from underneath the Breadboard showing the physical connections: 14 | ![Breadboard From Underneath](https://static1.makeuseofimages.com/wordpress/wp-content/uploads/2018/06/breadboard_back_peel_670.jpg?q=50&fit=crop&w=1500&dpr=1.5) 15 | This picture above makes it more clear how each row/column is connected. The metal rows you see above have little teeth that allow the pins of our electronics to go down into them to connect them with other holes in the breadboard. 16 | 17 | Here's a view of what the metal teeth look like in the breadboard: 18 | ![metal teeth](https://cdn-learn.adafruit.com/assets/assets/000/035/421/original/components_ledclip.jpg?1472966647) 19 | 20 | This is a longer and historical look at breadboards, but goes into more depth about how they function: 21 | [Breadboards for Beginners](https://learn.adafruit.com/breadboards-for-beginners/breadboards) 22 | -------------------------------------------------------------------------------- /reference/hackathon.md: -------------------------------------------------------------------------------- 1 | ## Goal 2 | You've been provided with hardware kits and instructions to learn how to use the different components in your kits. 3 | 4 | You will follow the labs to learn about the different components and how to control them through code on the RaspberryPi Pico. 5 | Your goal is to take what you learn to build a game. The final 3 labs will walk you through building our prototype laser shark game. 6 | 7 | If possible, the ultimate goal would be to build on what you learn to create your own unique game. 8 | 9 | You can add new features in code or hardware to our prototype game or come up with something brand new. 10 | 11 | 12 | ## General Tips 13 | 1) In your kits, you may have several strands of colored wires stuck together. You can strip wires apart by gently grabbing two different colored wires next to each other and pulling them apart. 14 | 1) The colors of the wires or their length don't really matter. Typically black or white wires go to the negative terminal, also known as ground, and the red wires usually go to positive voltage. But the colors are only for human readability and so it doesn't matter if you replace a red wire with a blue wire from the standpoint of making it work. 15 | 1) Reconfiguring the wires is ok to make things easier to reach or access buttons, but probably won't get you extra points. 16 | 17 | 18 | ## Judging 19 | 1) You will be judged on team work, working prototypes of our games, innovations on the prototype, and presentations. 20 | 2) The largest amount of points available are in the working prototypes and working innovated features with a total of 10 points in each section. 21 | 3) Team work is worth up to 3 points and Presenations are a max of 5 points for awesome presentations. 22 | 4) Your work on the prototype will be judged as you get parts of it completed. So after completing each of the final labs, reach out to a judge to have them check your work and give you credit for what you've done. 23 | 5) On the scorecard for innovation, the last item mentions adding a previously unused hardware component to the final solution. You should be given one point for **each** additional hardware component added. For example, adding two new buttons that provide new features, could gain you two points. If those buttons also required feature providing code for them to work, that could be additional points for added code module/function/feature. 24 | -------------------------------------------------------------------------------- /reference/part_description.md: -------------------------------------------------------------------------------- 1 | # Parts Description 2 | 3 | 4 | ## Raspberry Pi Pico 5 | 6 | Raspberry Pi Pico 7 | Use it as the brain of your game. Program it in [MicroPython](https://micropython.org/) to handle game logic, input/output, and communication with other components. 8 | The Raspberry Pi Pico is a simple [microcontroller](https://www.geeksforgeeks.org/microcontroller-and-its-types) that allows the running of code to interact with many different electronic devices. 9 | To learn more including other labs and exercises for the Pico check out the **Free Book:**[Introduction to Raspberry Pi Pico](https://hackspace.raspberrypi.com/books/micropython-pico/pdf/download) 10 | 11 | ## LED 12 | Red LED 13 | LEDs are the most simple components in your kit that simply turn electricity into light. You should have access to several different colors of LEDs. LEDs can indicate game status (health, power-ups, etc.). Use different colors for visual feedback. 14 | **LED Labs:** [Basic Circuit](/labs/01_first_circuit.md) : [Basic with Resistors](/labs/02_resistor_intro.md) : [With Pico](/labs/07_blink_led.md) : [Fade LED with PWM](/labs/11_PWM_LED.md) 15 | 16 | ## Laser 17 | Red LED 18 | The Laser in the kit is just a simple LED that can focus a beam of light to a tiny spot and has more range. It is simply a specialized LED and is controlled exactly the same way as a typical LED. Great for pairing with a photo resistor to use as a trip wire or "shoot" a target. 19 | **Laser Labs** Laser is just an LED, see LED Labs. 20 | 21 | ## Photo Resistor 22 | Photo Resistor 23 | Photo Resistors are variable resistors that allow you to detect changes in light. This can be used as a trip wire or target for a laser. It can also be used to control the resistence based on light levels and could be used as a "dimmer" of sorts if used in conjunction with LEDs to adjust the brightness of LEDs based on the amount of light hitting the photo resistor. 24 | **Photo Resisotor Labs**: [Basic Circuit](/labs/03_photo_resistor.md) : [Reading With Pico](/labs/14_adc_photoresistor.md) 25 | 26 | ## Potentiometer 27 | Potentiometer 28 | Potentiometers act as analog knobs. They are another type of variable resistor used to adjust the amount of resistence in a circuit. Potentiometers are often used to adjust things like volume, speed, frequency, etc. 29 | **Potentiometer Labs**: [Basic Circuit](/labs/04_potentiometer.md) : No Pico Lab with Potentiometer, but would be same as [Photo Resistor](/labs/14_adc_photoresistor.md) code wise. 30 | 31 | ## Buttons 32 | Buttons 33 | A button is a simple input device that can be used for all types of applications. Through code on the Pico you can detect whether the button is pressed or unpressed. 34 | **Button Labs**: [Basic Circuit](/labs/05_button_circuit.md) : [Pico Basic](/labs/08_button_control.md) : [Debounce](/labs/09_button_debounce.md) : [Mini Game](/labs/16_button_led_reaction_time.md) : [Interrupt](/labs/10_button_interrupt.md) 35 | 36 | ## Servos 37 | Servos 38 | Servos are simple motors that allows you to tell it a position to move to and hold. Servos are commonly used in robotics as well as R/C planes and cars. Servos are good at providing simple movement or articulation into your project. 39 | **Servo Labs**: [Control with Pico](/labs/12_servo_control.md) 40 | 41 | ## Joysticks 42 | Joystick 43 | Joysticks are a useful input device to detect movent in at least two directions. Joysticks are great for controlling direction of servo movement or any kind of proportional movement. 44 | **Joystick Labs**: [Pico Basic](/labs/Joystick_intro.md) : [Turret Lab](/labs/turret.md) 45 | ## Buzzer 46 | Buzzer 47 | Add sound effects! Buzzers can create beeps, alarms, or musical tones. When used with PWM, you can adjust the frequency or pitch to change the sound that they make. Trigger buzzers during specific game events (e.g., scoring points, time running out, or winning). 48 | **Buzzer Labs**: [With Pico and PWM](/labs/11b_Buzzer.md) 49 | 50 | ## Seven Segment Displays 51 | Seven Segment Display 52 | Seven segment displays are great output device to display numbers or values. Good for showing score, lives left, or any other numeric information. If you are creative, you can even display some words or letters. 53 | **Seven Segment Display Labs**: [With Pico](/labs/15_seven_segment.md) 54 | 55 | 56 | ## Creativity 57 | 58 | Remember, the key to a successful game is creativity! Combine these components, experiment, and have fun building your unique game. 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /reference/pico_gpio.md: -------------------------------------------------------------------------------- 1 | ## Raspberry Pi Pico Pins 2 | 3 | 4 | The Raspberry Pi Pico has 40 pins. A majority of these are General Purpose Input/Output(GPIO) Pins. 5 | These GPIO pins allow you to send or receive signals with the Pico. A smaller number of the pins that are NOT GPIO pins, are used for Ground or Power. 6 | Ground pins are the 3rd pin from each end on each side. There are also two other ground pins on each side spaced 5 pins from the first ground pins. 7 | 8 | **NOTE**: While the pins have a physical numbering from 1 to 40. In the code you never use the logical numbering of the pins, but instead use the GP# for each pin. 9 | 10 | So, use the image below as a reference to know the GPIO pin numbers. In the code you will use the number after the "GP" label. 11 | 12 | ![Pico Pinout](https://www.circuitgeeks.com/wp-content/uploads/2021/06/Raspberry-Pi-Pico-Pinout.png) 13 | 14 | 15 | ### This image is rotated in the orientation of all the labs. 16 | ![Pico Sideways](/images/Rasbnerry-Pi-Pico-Pinout-1-sideways.png) -------------------------------------------------------------------------------- /servos/scan.py: -------------------------------------------------------------------------------- 1 | import utime 2 | import sg90 3 | 4 | sg90.servo_pin(15) 5 | 6 | 7 | SMOOTH_TIME = 20 8 | 9 | 10 | 11 | def scan(): 12 | for i in range(90,180): 13 | sg90.move_to(i) 14 | utime.sleep_ms(SMOOTH_TIME) 15 | 16 | for i in range(180,89, -1): 17 | print(i) 18 | sg90.move_to(i) 19 | utime.sleep_ms(SMOOTH_TIME) 20 | 21 | 22 | for i in range(90,-1,-1): 23 | sg90.move_to(i) 24 | utime.sleep_ms(SMOOTH_TIME) 25 | 26 | for i in range(0,91): 27 | print(i) 28 | sg90.move_to(i) 29 | utime.sleep_ms(SMOOTH_TIME) 30 | 31 | sg90.move_to(90) 32 | 33 | while True: 34 | scan() 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /servos/servo_class_sample.py: -------------------------------------------------------------------------------- 1 | from sg90_class import SG90 2 | import time 3 | 4 | servo = SG90(15) 5 | 6 | 7 | servo.move_to(90) 8 | time.sleep(1) 9 | 10 | 11 | 12 | servo.move_to(40) 13 | time.sleep(1) 14 | 15 | 16 | servo.move_to(130) 17 | time.sleep(1) 18 | 19 | 20 | servo.move_to(90) 21 | time.sleep(1) 22 | 23 | 24 | servo.move_to(40) 25 | time.sleep(1) 26 | 27 | servo.move_to(130) 28 | time.sleep(1) 29 | 30 | 31 | servo.move_to(90) 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /servos/servosampleFull.py: -------------------------------------------------------------------------------- 1 | import machine 2 | import utime 3 | 4 | servo = machine.PWM(machine.Pin(1)) 5 | servo.freq(50) 6 | 7 | #Original method I stole from engineering dude. https://peppe8o.com/sg90-servo-motor-with-raspberry-pi-pico-and-micropython/ 8 | def interval_mapping(x, in_min, in_max, out_min, out_max): 9 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min 10 | 11 | 12 | ## according to this: https://microcontrollerslab.com/servo-motor-raspberry-pi-pico-micropython/ 13 | ## The duty cycle maxes at 65535 for the 14 | ## Raspberry Pi Pico has 12 bit resolution but in MicroPython it is scaled to 16 bits. 15 | ## Hence the duty cycle is set from 0-65535 which corresponds to 0-100%. (min duty cycle for Pico to Max duty cycle for Pico) 16 | ## However, for SG-90 servo motor we will pass values between 1000-9000 microseconds 17 | ## which corresponds to 0-180 degree position movement of the arm inside the PWM.duty_u16() method. 18 | 19 | ## Barry's notes: But this calculation seems to indicate max duty cycle for SG90 is actually 8,191.875, not 9000 20 | ## This method takes the SG90 calculated pulse width in ms and converts it to the right duty cycle 21 | def calc_duty_cycle(pulse_width): 22 | return (pulse_width) * (65535) / (20) 23 | 24 | ## according to this: https://microcontrollerslab.com/servo-motor-raspberry-pi-pico-micropython/ 25 | ## Position 1000 to 9000 represents 0 to 180 26 | ## Specs on SG90 servo say Pulse Width of 0.5 is 0 and 1.5ms is mid point and 2.5ms is max. 27 | ## This formula works to get the pulse width for the sg90 servo based on the angle. 28 | def calc_pulse_width(angle): 29 | return (angle * 2.0) / 180 + 0.5 30 | 31 | 32 | def move_servo_to_angle(pin,angle): 33 | print("===== New Write ==== ") 34 | print("angle=" + str(angle)) 35 | # pulse_width=interval_mapping(angle, 0, 180, 0.5,2.5) 36 | pulse_width=calc_pulse_width(angle) 37 | #duty=int(interval_mapping(pulse_width, 0, 20, 0,65535)) 38 | duty=int(calc_duty_cycle(pulse_width)) 39 | print("pulse width=" + str(pulse_width)) 40 | print("duty=" + str(duty)) 41 | 42 | pin.duty_u16(duty) 43 | 44 | 45 | move_servo_to_angle(servo, 90) 46 | utime.sleep_ms(1000) 47 | 48 | move_servo_to_angle(servo, 45) 49 | utime.sleep_ms(1000) 50 | 51 | move_servo_to_angle(servo, 0) 52 | utime.sleep_ms(1000) 53 | 54 | move_servo_to_angle(servo, 45) 55 | utime.sleep_ms(1000) 56 | 57 | move_servo_to_angle(servo, 90) 58 | utime.sleep_ms(1000) 59 | 60 | move_servo_to_angle(servo, 130) 61 | utime.sleep_ms(1000) 62 | 63 | move_servo_to_angle(servo, 180) 64 | utime.sleep_ms(1000) 65 | 66 | move_servo_to_angle(servo, 130) 67 | utime.sleep_ms(1000) 68 | 69 | move_servo_to_angle(servo, 90) 70 | utime.sleep_ms(1000) 71 | 72 | 73 | -------------------------------------------------------------------------------- /servos/sg90.py: -------------------------------------------------------------------------------- 1 | import machine 2 | class servo: 3 | 4 | DEBUG = False 5 | 6 | def __init__(self, pin): 7 | self.servo = machine.PWM(machine.Pin(pin)) 8 | self.servo.freq(50) 9 | self.position = 90 #new 10 | self.move_to(self.position) #new 11 | 12 | ## Barry's notes: But this calculation seems to indicate max duty cycle for SG90 is actually 8,191.875, not 9000 13 | ## This method takes the SG90 calculated pulse width in ms and converts it to the right duty cycle 14 | def __calc_duty_cycle(self, pulse_width): 15 | return (pulse_width) * (65535) / (20) 16 | 17 | ## according to this: https://microcontrollerslab.com/servo-motor-raspberry-pi-pico-micropython/ 18 | ## Position 1000 to 9000 represents 0 to 180 19 | ## Specs on SG90 servo say Pulse Width of 0.5 is 0 and 1.5ms is mid point and 2.5ms is max. 20 | ## This formula works to get the pulse width for the sg90 servo based on the angle. 21 | def __calc_pulse_width(self, angle): 22 | return (angle * 2.0) / 180 + 0.5 23 | 24 | 25 | def duty_cycle_for_angle(self, angle): 26 | if self.DEBUG: 27 | print("===== Calcing Duty Cycle for Angle ==== ") 28 | print("angle=" + str(angle)) 29 | # pulse_width=interval_mapping(angle, 0, 180, 0.5,2.5) 30 | pulse_width=self.__calc_pulse_width(angle) 31 | #duty=int(interval_mapping(pulse_width, 0, 20, 0,65535)) 32 | duty=int(self.__calc_duty_cycle(pulse_width)) 33 | if self.DEBUG: 34 | print("pulse width=" + str(pulse_width)) 35 | print("duty=" + str(duty)) 36 | 37 | return duty 38 | def move_to(self, angle): 39 | duty_cycle=self.duty_cycle_for_angle(angle) 40 | self.servo.duty_u16(duty_cycle) 41 | self.position = angle #new 42 | -------------------------------------------------------------------------------- /servos/sg90_class.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, PWM 2 | 3 | class SG90: 4 | 5 | def __init__(self, pin, debug=False) -> None: 6 | self.servo = PWM(Pin(pin)) 7 | self.servo.freq(50) 8 | self.DEBUG = debug 9 | 10 | ## according to this: https://microcontrollerslab.com/servo-motor-raspberry-pi-pico-micropython/ 11 | ## The duty cycle maxes at 65535 for the 12 | ## Raspberry Pi Pico has 12 bit resolution but in MicroPython it is scaled to 16 bits. 13 | ## Hence the duty cycle is set from 0-65535 which corresponds to 0-100%. (min duty cycle for Pico to Max duty cycle for Pico) 14 | ## However, for SG-90 servo motor we will pass values between 1000-9000 microseconds 15 | ## which corresponds to 0-180 degree position movement of the arm inside the PWM.duty_u16() method. 16 | 17 | ## Barry's notes: But this calculation seems to indicate max duty cycle for SG90 is actually 8,191.875, not 9000 18 | ## This method takes the SG90 calculated pulse width in ms and converts it to the right duty cycle 19 | def _calc_duty_cycle(self,pulse_width): 20 | return (pulse_width) * (65535) / (20) 21 | 22 | ## according to this: https://microcontrollerslab.com/servo-motor-raspberry-pi-pico-micropython/ 23 | ## Position 1000 to 9000 represents 0 to 180 24 | ## Specs on SG90 servo say Pulse Width of 0.5 is 0 and 1.5ms is mid point and 2.5ms is max. 25 | ## This formula works to get the pulse width for the sg90 servo based on the angle. 26 | def _calc_pulse_width(self,angle): 27 | return (angle * 2.0) / 180 + 0.5 28 | 29 | 30 | def duty_cycle_for_angle(self,angle): 31 | if self.DEBUG: 32 | print("===== Calcing Duty Cycle for Angle ==== ") 33 | print("angle=" + str(angle)) 34 | # pulse_width=interval_mapping(angle, 0, 180, 0.5,2.5) 35 | pulse_width=self._calc_pulse_width(angle) 36 | #duty=int(interval_mapping(pulse_width, 0, 20, 0,65535)) 37 | duty=int(self._calc_duty_cycle(pulse_width)) 38 | if self.DEBUG: 39 | print("pulse width=" + str(pulse_width)) 40 | print("duty=" + str(duty)) 41 | 42 | return duty 43 | 44 | def move_to(self,angle): 45 | duty_cycle=self.duty_cycle_for_angle(angle) 46 | self.servo.duty_u16(duty_cycle) 47 | -------------------------------------------------------------------------------- /servos/sg90sample.py: -------------------------------------------------------------------------------- 1 | import sg90 2 | import utime 3 | 4 | sg90.servo_pin(15) 5 | 6 | #Center 7 | sg90.move_to(90) 8 | utime.sleep_ms(1000) 9 | 10 | #move_to to one extreme 11 | sg90.move_to(0) 12 | utime.sleep_ms(1000) 13 | 14 | #move_to to other extreme 15 | sg90.move_to(180) 16 | utime.sleep_ms(1000) 17 | 18 | #Center 19 | sg90.move_to(90) 20 | --------------------------------------------------------------------------------