- Table of Contents
- Hello_CircuitPython
- CircuitPython_Servo
- Ultrasonic Sensor
- CircuitPython Photointerrupter
- CircuitPython_LCD
- Classes, Objects, and Modules
The code makes the Neopixel on the Metro Express flash a random color from a list of rainbow colors. It's looped so that every 0.1 seconds it chooses a different color from the same list.
# Write your code here :-)
#This is Josie's pride and joy
import board
import neopixel
import time
import random
dot = neopixel.NeoPixel(board.NEOPIXEL, 1)
red = [204, 0, 0]
orange = [255, 50, 0]
yellow = [200, 100, 0]
green = [0, 230, 0]
blue = [0, 0, 255]
purple = [146, 0, 199]
color_list = [red, orange, yellow, green, blue, purple]
print("Make it disco!!!")
dot.brightness = 0.1
while True:
random_color = random.choice(color_list)
dot.fill((random_color))
time.sleep(0.1)
Look at it go!! So many random colors...
No wiring, all you need is and Adafruit Metro Express
- Semi-colons are not needed at the end of every line
- 'while True:' goes at the beginning of what you want looped
- You can create lists to have the 'random.choice' function to pull from if you want to create a random sequence
This one worked well, and was pretty easy once I figured out the basic Cicuit Python commands, which are somewhat similar to those used by Arduino, though there all some differences (for instance, you don't need semicolons at the end of each line, and different commands vary; "While True:" statements are loops). I then went through and decided to switch from just the required LED color change to experimenting with lists in order to achieve the final product.
This servo is powered via capacitive touch! (If you touch one wire, it turns one way, and if you touch the other the servo spins the other way!)
# Write your code here :-)
import board
import time
import pwmio
import servo
import touchio
touch_a4 = touchio.TouchIn(board.A4) #your basic capacitive touch command!
touch_a0 = touchio.TouchIn(board.A0)
pwm = pwmio.PWMOut(board.A2, duty_cycle=2**15, frequency=200) #sets the servo rotation frequency
super_snazzy_servo = servo.Servo(pwm) #simplifies servo function by setting it equal to the desired frequency
super_snazzy_servo.angle = 90 #sets your starting servo angle
angle = 90 #Sets your starting value for angle
while True:
if touch_a4.value: #If function for the first capacitive touch value, this one will control fowards motion
print("Going fowards!")
if angle in range(0, 175): #Making sure that the angle is in a viable range to continue moving
angle += 5 #Adds value to the initial angle value (Set on the first line above the while true statement)
super_snazzy_servo.angle = angle #Sets servo angle to our new angle value
print(angle) #Tells us our new angle value on the serial monitor
time.sleep(0.05) #Sets a rest interval before continuing the loop
if touch_a0.value: #If function for the second capacitive touch value, this one will control backwards motion
print("Coming back!")
if angle in range(5, 180):#Making sure that the angle is in a viable range to continue moving
angle -= 5 #Subtracts value from the initial angle value (Set on the first line above the while true statement)
super_snazzy_servo.angle = angle #Sets servo angle to our new angle value
print(angle) #Tells us our new angle value on the serial monitor
time.sleep(0.05) #Sets a rest interval before continuing the loop
if not touch_a4.value and not touch_a0.value: #Checks if no wires are touched so that code doesn't go into a paniced
print("I'm no longer moving (help!)") #Lets us know via the serial monitor that the servo is not moving (that the capcitive touch isn't recieving input)
time.sleep(.05) #Sets a rest interval before continuing the loop
time.sleep(.05) #Sets a rest interval before continuing the loop
The servo itself working with capacitive touch...
...And the serial moniter showing its rotations!
Simple servo wiring!
- As opposed to the 'servo.read' and 'servo.write' functions used with Arduino, Circuit Python uses the 'pwmio' function
- 'pwmio' functions use frequency cycles to control the servo
- A cycle length of '2 * * 15' and a frequency of 200
- Capacitive touch is controlled by touching different wires with your finger
- Touching one wire printed a message to the serial moniter while touching the other printed a different message
- Multiple 'if' statements can cause conflicts in the code
- The 'if' statement or the servo rotation needs to be inside the 'if' statement for the capacitive touch code
- You need one more 'if' statement for if no wires are touched so that the servo only moves if a wire is touched
This one was a lot more challenging. It turns out that the code for a servo is a lot different in Circuit Python as opposed to Arduino. This was my first time using the "pwmio" funtion. The "pwmio" function controls the servo and uses frequency cycles. When using this function, I found out that I should use a cycle of "2* * 15" and a frequency of 200. I had never coded capcitive touch before, so I started out with a search for what it is. My original code for capacitive touch was controled by plugging the wire in and out, whereas capacitive touch is meant to be controlled by touching different wires with your finger. When I found that out, I did a bit more research and adjusted the code a bit until I could get the capcitive touch code to work on it's own (Touching one wire printed a message to the serial moniter, and touching the other printed a different message). Although I was able to get the servo code and capacitive touch code to work well independently, actually combining the two parts proved to be diffiucult. After a lot of trouble shooting and more research, I found out that the problem came from my syntax and conflicting "if" statements. In order for the code to work, you need to make sure that you put the "if" statement for servo rotation inside the corresponding "If" loop for the capacitive touch code. You also need to make a third "If" statement for if no wire is touched, so that the servo only turns if it's triggered by the touch of a wire.
This code powers an HCSR04 ultrasonic sensor. As the distance changes, the built in LED (the neopixel) on a Metro Express gradually shifts in colors in a range from red to green.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import time
import board
import neopixel
import adafruit_hcsr04 #imports ultrasonic sensor
import simpleio #imports map function library
dot = neopixel.NeoPixel(board.NEOPIXEL, 1)
sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.D8, echo_pin=board.D9) #sets ultrasonic sensor pins
distance = 0
dot.brightness = 0.1
while True:
try:
distance = sonar.distance #sets the variable "distance" to equal the number the ultrasonic sends back
print((distance,)) #prints the numeric value of distance
except RuntimeError: #Use if the ultrasonic does not recieve input
print("Retrying!") #report error message to the serial monitor
time.sleep(0.1)
if distance >= 5 and distance < 20: #Sets a range for the distance
blue = int(simpleio.map_range(distance, 5, 20, 0, 255)) #Maps out the values of blue that the led moves between
green = int(simpleio.map_range(distance, 5, 20, 0, 0)) #Maps out the values of green that the led moves between
red = int(simpleio.map_range(distance, 5, 20, 255, 0)) #Maps out the values of red that the led moves between
dot.fill((red, green, blue)) #Changes the led color to equal the new values for red,green and blue
if distance >= 20 and distance < 35: #Sets a range for the distance
blue = int(simpleio.map_range(distance, 20, 35, 255, 0)) #Maps out the values of blue that the led moves between
green = int(simpleio.map_range(distance, 20, 35, 0, 255)) #Maps out the values of green that the led moves between
red = int(simpleio.map_range(distance, 20, 35, 0, 0)) #Maps out the values of red that the led moves between
dot.fill((red, green, blue)) #Changes the led color to equal the new values for red,green and blue
It works!
Image credit goes to Ian Novotne
Ultrasonic sensor wiring!
Image credit goes to Benton House
- Ultrasonic sensors can break fairly easily, so make sure that it's not broken, otherwise you'll end up facing a lot of frustration when trying to figure out why your code isn't working
- Trying to code an LED light that gradually shifts through colors using math is extremely challenging, so I'd recommend using color mapping, which is a method that does the math for you
- Color mapping is used by providing it with two values and a time cycle, and from there it shifts the numbers as needed
- If you're confused, this document is an extremely helpful resource
This one was a lot more challenging. It was a struggle to get my ultrasonic sensor code to work on its own, though I eventually figured out that that problem was being caused purely because the sensor I was using was broken. Once I switched it out to a working sensor, the code worked well. The next challenge came with coding the light. While I originally attempted coding the gradually color shifting LED using math, that strategy didn't work in the end and proved to be extremely difficult. As such, I switched to using a new method known as color mapping. I had to do some research on it before using it, but I found that color mapping does the math for you. You simply give it two values and a time cycle, and it will do the work of shifting the numbers as needed! Once I figured out how this worked, the LED worked well.
This code utilises a photointerrupter. The serial moniter prints out the number of times the photointerrupter is interrupted, and it resets back to 0 interrupts every four seconds.
import board
import time
import digitalio
interrupter_pin = digitalio.DigitalInOut(board.D8)
interrupter_pin.switch_to_input
interrupter_pin.pull = digitalio.Pull.UP
initial_time = time.monotonic()
photo = False
state = False
counter = 0
max = 4
while True:
photo = interrupter_pin.value
if photo and not state:
counter += 1
print(str(counter))
state = photo
new_time = max - time.monotonic()
if new_time <= 0:
print(str(counter))
max = time.monotonic() + 4
counter = 0
The photointerrupter itself being triggered...
...And the serial moniter showing the number of interruptions!
Photointerrupter wiring!
- The photointerrupter is controlled by setting a time frequency and a counter
- The counter counts the number of time the signal has been interrupted
- Photointerrupters are also contrtolled using the 'photo' command, and the Arduino website as some great resources and examples for how to use this command
- The photointerrupter also uses the 'time.monotonic' function instead of 'time.sleep'
- Whereas 'time.sleep' adds a pause before running the rest of the code, 'time.monotonic' does not and it also compares the current time to an unknown start time
- The counter needs to reset back to 0 every four seconds, since we want to measure the number of times the signal is interrupted over the course of four seconds
- To do this, it's important that you use 'time.monotonic' and string functions
- A new 'if' atstement is needed that says that if the internal time that 'time.monotonic' records is greater than or equal to four, both the counter and timer will both reset to zero
I ran into some challenges originally, since I had never worked with a photointerrupters before. You can use the photointerrupter by setting a time frequency and a counter, and I figured out how to operate the "Photo" command through the Arduino website This code also utilises time.monotonic instead of time.sleep, which I had never used before. However, I found that both functions are fairly similar, with only slight differnces in command sentences. A quick Google search showed me the correct phrasing (Which I used in my code above!). Once I got the photointerrupter to successfully record the number of interrupts, the next challenge came from trying to get it to not only reset back to 0 interrupts every four seconds, but also to have it print out that number every second. I figured out that this is where the counter, time.monotonic, and string statements came in handy, and created a new if statement that said that if the internal time recorded by time.monotonic was greater than or equal to 4, both the timer and the counter would reset to zero. Once I got it to work and did some research on photointerrupters and the time.monotonic function, the code made a lot of sense.
Two wires use capacitive touch, with one determining whether it was counting up or down and the other registering and recording/counting the number of touches. The LCD screen displays what number the counter is at.
import board
from lcd.lcd import LCD
from lcd.i2c_pcf8574_interface import I2CPCF8574Interface
import touchio
touch_a4 = touchio.TouchIn(board.A4)
touch_a1 = touchio.TouchIn(board.A1)
jeff = 1
# jeff is just what I named my variable that controls whether its counting up or down
counter = 0
# The number of touches registered
joe = 0
# A boolean that registers one prolonged
# touch of the wire as just a single touch as opposed to mulitple
frank = 0
# A boolean that registers one prolonged
# touch of the wire as just a single touch as opposed to mulitple
# get and i2c object
i2c = board.I2C()
# some LCDs are 0x3f... some are 0x27.
lcd = LCD(I2CPCF8574Interface(i2c, 0x3f), num_rows=2, num_cols=16)
lcd.print("I have gained sentience!! :)")
while True:
if touch_a1.value and frank == 0:
# If frank is not zero, it will register as multiple touches instead of just one
print("touch a1") # prints to serial moniter
jeff = -jeff
# reverse the sign of jeff; changes from counting up to counting down or vice versa
frank = touch_a1.value
# resets frank so that it doesn't register as multiple touches
if jeff <= 0 and touch_a4.value and joe == 0:
# If joe is not zero, it will register as multiple touches instead of just one
# If jeff is less than or equal to zero, that means that it's counting down
print("touch a4") # prints to the serial moniter
lcd.set_cursor_pos(0, 0) # clears the LCD screen
counter += jeff # Adds the value of jeff (In this case -1) to the counter
lcd.print("Counting down!:P")
# Prints to the LCD screen a message that it's counting down
lcd.print("Value:")
# Prints a message to the LCD screen on a seperate line
lcd.print(str(counter))
# Prints the current value of the counter to the LCD screen
lcd.print(str(" "))
# Prints an extra space to the LCD screen
joe = touch_a4.value
# resets joe so that it doesn't register as multiple touches
if jeff >= 0 and touch_a4.value and joe == 0:
# If joe is not zero, it will register as multiple touches instead of just one
# If jeff is greater than or equal to zero, that means that it's counting up
print("touch a4") # prints to the serial moniter
lcd.clear() # clears the LCD screen
counter += jeff # Adds the value of jeff (In this case 1) to the counter
lcd.print("Counting up! >_<")
# Prints to the LCD screen a message that it's counting up
lcd.print("Value:")
# Prints a message to the LCD screen on a seperate line
lcd.print(str(counter))
# Prints the current value of the counter to the LCD screen
joe = touch_a4.value
# resets joe so that it doesn't register as multiple touches
It works!
LCD screen wiring!
- One wire needs to control the counting itself, while the other controls whether it's counting up or down
- In order to make sure it counts one long touch only once as opposed to a series of rapid touches, you need to use 'booleans' which work similarly to true-false statements (which is demonstrated in my code above)
- In addition to the boolean used to regulate the counting, another is needed to control whether it's counting up or down by determining whether the next numbers are positive or negative
- A slow clear time for the LCD screen can also cause problems, though the clear time can be fixed with the command 'lcd.set_cursor_pos(0, 0)'
I had some trouble getting the screen to clear quickly enough, and for all the text to fit and still be fast. At first, I did the assignment wrong so that one wire counted up and the other counted down. In addition, when I touched and held one wire, it continued to count, registering it as many rapid touches instead of one long one. I had to do some research on what was causing the issue, and I managed to find out that something called "Booleans" (which work similar to true-false statements) would help to fix the issue. I'm still not the most sure about how booleans work, but I have a better understanding of it now that I've finished this assignment. Once I got the hang of booleans, the correct effect was easier to accomplish. However, the assignment was to have one wire control whether it was counting up or down, and then other would change the numbers/register and record each touch. Getting the wire that controlled whether it was counting up or down was hard, and I had to employ yet another boolean that determined whether the following numbers were positive or negative. Another challenge came from faulty wires and a slow clear time on the LCD screen, but I was able to fix the clear time issue with the command "lcd.set_cursor_pos(0, 0) ".
A code library is created to store the functions that make the LED fade. A second file is opened to run the functions for as many LEDs as you want.
Main LED Code:
import time
import board
from rgb import LED
redPin = board.D7
bluePin = board.D5
greedPin = board.D6
redPin2 = board.D4
greedPin2 = board.D3
bluePin2 = board.D8
red = LED(redPin)
blue = LED(bluePin)
greed = LED(greedPin)
red2 = LED(redPin2)
greed2 = LED(greedPin2)
blue2 = LED(bluePin2)
while True:
red.on(35000)
greed.fade()
blue.off()
red2.on(15000)
greed2.off()
blue2.fade()
LED Library Code:
import time
import board
import pwmio
class LED:
def __init__(self, Pin):
self.LED = pwmio.PWMOut(Pin, frequency=5000, duty_cycle=0)
def fade(self):
for i in range(100):
if i < 50:
self.LED.duty_cycle = int(i * 2 * 65535 / 100) # Up
else:
self.LED.duty_cycle = 65535 - int((i - 50) * 2 * 65535 / 100) # Down
print(self.LED.duty_cycle)
time.sleep(0.03)
def on(self, brightness=65535):
self.LED.duty_cycle = 65535 - brightness
def off(self):
self.LED.duty_cycle = 65535
It works! Look at those colors fade!
RGB wiring!