Skip to content

jmuss07/Circuit-Python

Repository files navigation

CircuitPython

Table of Contents


Hello_CircuitPython

Description & Code

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)

Evidence

Look at it go!! So many random colors...

Look at it go!! So many random colors...

Wiring

No wiring, all you need is and Adafruit Metro Express

Reflection

  • 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.

CircuitPython_Servo

Description & Code

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

Evidence

The servo itself working with capacitive touch...

The servo itself working with capacitive touch...

...And the serial moniter showing its rotations!

...And the serial moniter showing its rotations!

Wiring

Simple servo wiring!

Simple servo wiring!

Reflection

  • 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.

Ultrasonic_Sensor

Description & Code

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

Evidence

It works!

It works!

Image credit goes to Ian Novotne

Wiring

Ultrasonic sensor wiring!

Ultrasonic sensor wiring!

Image credit goes to Benton House

Reflection

  • 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.

CircuitPython_Photointerrupter

Description & Code

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

Evidence

The photointerrupter itself being triggered...

The photointerrupter itself being triggered...

...And the serial moniter showing the number of interruptions!

...And the serial moniter showing the number of interruptions!

Wiring

Photointerrupter wiring!

Photointerrupter wiring!

Reflection

  • 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.

CircuitPython_LCD

Description & Code

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

Evidence

It works!

It works!

Wiring

LCD screen wiring!

LCD screen wiring!

Reflection

  • 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) ".

Classes_Objects_Modules

Description & Code

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

Evidence

It works! Look at those colors fade!

It works! Look at those colors fade!

Wiring

RGB wiring!

RGB screen wiring!

Reflection

About

A GitHub repository for my Circuit Python code!

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages