Last week, my middle schoolers did a set of experiments on electricity and magnetism. They answered the questions:
How does the voltage across each light bulb change as you add more and more bulbs to a parallel circuit?
How does the voltage across each light bulb change as you add more and more bulbs to a series circuit?
How does the number of coils of wire wrapped around a nail affect it’s magnetism (as measured by the number of paperclips it can pick up)?
How does the amount of salt mixed into water affect its conductivity?
Each question is designed so that students have something to measure and will be able to use those measurements to make predictions. For example, once they’ve measured the voltage across four bulbs in series, they should be able to predict the voltage across the bulbs in a series of ten.
Some of the experiments, like the nail electromagnet, should have simple linear trends, with students choosing the advanced option having to find an equation to fit their data for the predictions. And I’ll challenge the students in Algebra II to find the equations for the inverse relationships–I’ve already asked their math teacher (Mr. Schmidt) to help them out if they need it.
This has also provided the opportunity for them to apply what they’ve just learned about drawing circuit diagrams (we use this set of symbols).
While steam distillation is the recommended method for extracting oils from herbs, we’re trying a quick an dirty method of simply heating up the lavender leaves in water (up to 40 ºC) and seeing if any of the oils float to the top. If this does not work, we’ll still have produced some lavender scented water for our soapmaking.
The lavender leaves came from the large bushes out by the preschool that the outddoor group trimmed for Ms. Dicker.
Ms. Mertz’s class is studying DNA–replication, translation, transcription, etc.–and she gave them the option of making a model or creating a game to test each others knowledge. There were some interesting projects:
Last weekend was not the optimum time for transplanting berry bushes. The top five centimeters of the soil was still frozen, and the air temperature was below zero Celsius with a cold breeze on top of it. However, we needed to get fourteen blueberry bushes moved, and, with a lot of help from some parents and a couple students, we were able to get the bushes and enough soil laid out to give them a good chance of success when the soil warms up.
I’ve slapped together this simple VPython program to introduce sinusoidal functions to my pre-Calculus students.
Left and right arrow keys increase and decrease the frequency;
Up and down arrow keys increase and decrease the amplitude;
“a” and “s” keys increase and decrease the phase.
The specific functions shown on the graph are based on the general function:
where:
A — amplitude
F — frequency
P — phase
When I first introduce sinusoidal functions to my pre-Calculus students I have them make tables of the functions (from -2π to 2π with an interval of π/8) and then plot the functions. Then I’ll have them draw sets of sine functions so they can observe different frequencies, amplitudes, and phases.
from visual import *
class sin_func:
def __init__(self, x, amp=1., freq=1., phase=0.0):
self.x = x
self.amp = amp
self.freq = freq
self.phase = phase
self.curve = curve(color=color.red, x=self.x, y=self.f(x), radius=0.05)
self.label = label(pos=(xmin/2.0,ymin), text="Hi",box=False, height=30)
def f(self, x):
y = self.amp * sin(self.freq*x+self.phase)
return y
def update(self, amp, freq, phase):
self.amp = amp
self.freq = freq
self.phase = phase
self.curve.y = self.f(x)
self.label.text = self.get_eqn()
def get_eqn(self):
if self.phase == 0.0:
tphase = ""
elif (self.phase > 0):
tphase = u" + %i\u03C0/8" % int(self.phase*8.0/pi)
else:
tphase = u" - %i\u03C0/8" % int(abs(self.phase*8.0/pi))
print self.phase*8.0/pi
txt = "y = %ssin(%sx %s)" % (simplify_num(self.amp), simplify_num(self.freq), tphase)
return txt
def simplify_num(num):
if (num == 1):
snum = ""
elif (num == -1):
snum = "-"
else:
snum = str(num).split(".")[0]+" "
return snum
amp = 1.0
freq = 1.0
damp = 1.0
dfreq = 1.0
phase = 0.0
dphase = pi/8.0
xmin = -2*pi
xmax = 2*pi
dx = 0.1
ymin = -3
ymax = 3
scene.width=640
scene.height=480
xaxis = curve(pos=[(xmin,0),(xmax,0)])
yaxis = curve(pos=[(0,ymin),(0,ymax)])
x = arange(xmin, xmax, dx)
#y = f(x)
func = sin_func(x=x)
func.update(amp, freq, phase)
while 1: #theta <= 2*pi:
rate(60)
if scene.kb.keys: # is there an event waiting to be processed?
s = scene.kb.getkey() # obtain keyboard information
#print s
if s == "up":
amp += damp
if s == "down":
amp -= damp
if s == "right":
freq += dfreq
if s == "left":
freq -= dfreq
if s == "s":
phase += dphase
if s == "a":
phase -= dphase
func.update(amp, freq, phase)
#update_curve(func, y)
Although it took us a day to figure out how to get the Raspberry Pi to work–a faulty SD card turned out to be a major delay–we still had most of a week of the Creativity Interim for students to get some projects done.
That is, until it started to snow. We lost more two days.
Still, we had a small cadre of determined students, one of whom (N.D.) decided that she wanted to make the Pi play sounds to go with the blinking LED lights.
To do this she needed to:
Learn how to use the LINIX command line to connect to the Pi and execute programs.
Learn how to write programs in Python to operate the Pi’s GPIO (input/output) pins.
Learn how to make circuits on a breadboard connected to the Pi.
A Quick and Incomplete Introduction to the Command Line: Basic Navigation
We started by using the Terminal program on my Mac to learn basic navigation.
To see a list of what’s in a folder use ls:
> ls
For more details on the items in the folder, use the -l option:
> ls -l
To see all the options available for the ls command you can lookup the manual using man:
> man ls
To create a new directory (e.g. Pi) use mkdir:
> mkdir Pi
To change directories (say to go into the Pi directory) use cd:
> cd Pi
Connecting to the Pi
I detail how to connect to a Pi that’s plugged into the wall via the local network here, but to summarize:
Use ifconfig to find the local IP address (under eth1).
> ifconfig
Use nmap to identify where the Pi is on the network. E.g.:
> sudo nmap -sP 191.163.3.0/24
Finally, connect to the Pi using the secure shell program ssh:
> ssh pi@191.163.3.214
(the default password is “raspberry”)
Wiring an LED Light Circuit
We created an initial circuit going from the #17 General Purpose Input/Output (GPIO) pin to a red LED then through a resistor then back into one of the ground pins of the Pi. We’ll turn the current going through GPIO #17 on and off via our program on the Pi. The resistor is needed to reduce the amount of current flowing through the LED, otherwise it would likely get blown out. The circuit is shown in the picture where I’ve taken the wire ribbon out for the sake of visibility.
Wiring on a breadboard is quite simple if you remember a few rules.
First, the columns of holes on the sides are connected vertically, so the right end of the yellow wire (in the + column) is connected to the resistor.
Secondly, the holes in the middle are connected horizontally, but not across the gap in the middle. That’s why the GPIO pin #17 is connected to the lower end of the black wire, and the left end of the resistor is connected to the ground (GND) pin. The LED light reaches across the two gap to connect the two rows with the upper end of the black wire and the left end of the yellow wire. Without something to bridge the gap, the circuit would not be complete.
The resistor has a resistance of 420 Ohms. You can tell by the color bands. In the sequence–yellow, red, brown–the first two bars represent numbers (yellow=4; red=2) and the third number represents a multiplier (in this case brown represents 10x).
Light: Programming the Pi in Python
Once you ssh to the Pi you can start programming. We used the command line text editor Nano. A simple text editor is all you need to write simple Python programs. We’ll create a program called flash.py (Note: it’s important to include the .py at the end of the file’s name, otherwise it becomes hard to figure out what type of file something is, and the extension also clues Nano in to allow it to color-code the keywords used in Python, making it a lot easier to write code.
pi> nano flash.py
You can then type in your program. The basic code for making a single light flash on and off ten times (see here) is:
flash.py
#!/usr/bin/env python
from time import sleep
import RPi.GPIO as GPIO
cpr = 17 ## The GPIO Pin output number
GPIO.setmode(GPIO.BCM) ## Use board pin numbering
GPIO.setup(cpr, GPIO.OUT) ## Setup GPIO Pin 7 to OUT
for i in range(10):
GPIO.output(cpr, True)
sleep(0.5)
GPIO.output(cpr, False)
sleep(0.5)
GPIO.cleanup()
This requires wiring a circuit to the GPIO pin #17. The circuit has a LED and a resistor in series, and circles back to the Pi via a grounding pin.
Run the program flash.py using:
pi> sudo python flash.py
Finally, let’s tell the program how many times to flash the light. We could create a variable in the Python code with a number, but it’s more flexible to set Python to take the number from the command line as a command line argument. Any words you put after the python in the command to run your program are automatically stored in an array called sys.argv if you import the sys module into your program. So we rewrite our flash.py program as:
flash2.py
#!/usr/bin/env python
from time import sleep
import RPi.GPIO as GPIO
import sys
cpr = 17 ## The GPIO Pin output number
GPIO.setmode(GPIO.BCM) ## Use board pin numbering
GPIO.setup(cpr, GPIO.OUT) ## Setup GPIO Pin 7 to OUT
for i in range(int(sys.argv[1])):
GPIO.output(cpr, True)
sleep(0.5)
GPIO.output(cpr, False)
sleep(0.5)
GPIO.cleanup()
So to flash the light 8 times use:
pi> sudo python flash2.py 8
Note that in your Python code you use int(sys.argv[1]) to get the number of times to flash:
sys.argv[1] refers to the first word on the command line after the name of the python file. sys.argv[0] would give you the name of the python file itself (flash.py in this case).
the int function converts strings (letters and words) into numbers that Python can understand. When Python reads in the “8” from the command line it treats it like the character “8” rather than the number 8. You need to tell Python that “8” is a number.
Sound: Using SOX
You can do a lot with sound–record, play files, synthesize notes–on the Pi using the command line program SOX. Install SOS (and mplayer and ffmpeg which are necessary as well) using:
pi> sudo apt-get install sox mplayer ffmpeg
Installation may take a while, but when it’s done, if you plug in speakers or headphones–the Pi has no onboard speakers–you can test by synthesizing an E4 note, which has a frequency of 329.63 Hz (via Physics of Music Notes), that lasts for half a second using:
pi> play -n synth .5 sin 329.63
Now play is a command line program that’s part of sox, so to use it in your Python program you have to tell Python to import the module that lets Python talk to the command line: it’s called os. Then you make a Python program to play the note using os.system like so:
test_sound.py
import os
os.system('play -n synth .5 sin 329.63')
And run the program with:
pi> sudo python test_sound.py
Combining light and sound
Now we bring the light and sound together a the Python program:
flash-note.py
#!/usr/bin/env python
from time import sleep
import RPi.GPIO as GPIO
import sys
import os
cpr = 17 ## The GPIO Pin output number
GPIO.setmode(GPIO.BCM) ## Use board pin numbering
GPIO.setup(cpr, GPIO.OUT) ## Setup GPIO Pin 7 to OUT
for i in range(int(sys.argv[1])):
GPIO.output(cpr, True)
os.system('play -n synth .5 sin 329.63')
GPIO.output(cpr, False)
sleep(0.5)
GPIO.cleanup()
which you run (repeating the note and light 5 times) with:
pi> sudo python flash-note.py 5
Notice that we’ve replaced the middle sleep(0.5) line with the call to play the note because we don’t need the delay since the note plays for 0.5 seconds.
Playing a Tune
The student, N.D., spent some time working through this programming and adding wiring to the Pi breadboard in order to play the first few notes of Mary Had A Little Lamb. By the time we ran out of time, and she had to do her presentation to the rest of the upper-school, she’d come up with this:
red-light-flash.py
#!/usr/bin/env python
from time import sleep
import os
import sys
import RPi.GPIO as GPIO
os.system('play -n synth 2 sin 543.21')
cpy = 22
cpr = 17
cpw = 23
GPIO.setmode(GPIO.BCM) ## Use board pin numbering
GPIO.setup(cpy, GPIO.OUT) ## Setup GPIO Pin 0 to OUT
GPIO.setup(cpr, GPIO.OUT)
GPIO.setup(cpw, GPIO.OUT)
for i in range(int(sys.argv[1])):
GPIO.output(cpy, True)
GPIO.output(cpr, False)
GPIO.output(cpw, False)
os.system('play -n synth 1 sin 578.00')
GPIO.output(cpy, False)
GPIO.output(cpr, True)
GPIO.output(cpw, False)
os.system('play -n synth 2 sin 440.00')
GPIO.output(cpy, False)
GPIO.output(cpr, False)
GPIO.output(cpw, True)
os.system('play -n synth 1 sin 400.00')
GPIO.cleanup()
which is run (5 times) using:
pi> sudo python red-light-flash.py 5
Creating User-Defined Functions
(As a note to N.D., because we ran out of time before we could get to it.)
You’ll notice it takes four lines to turn a light on, turn the other lights off, and play the note. You’ll also note that you have to repeat the exact same code every time you want to play a specific note and it becomes a pain having to repeat all this every time, especially if you want to play something with more notes. This is the ideal time to define a function to do all the repetitive stuff.
So we’ll create a separate function for each note. Mary has a little lamb uses the notes E4, D4, and C4. So we get their frequencies from Physics of Music Notes and create the functions:
Another interesting project that came out of the Creativity Interim was a VPython program that uses the DNA Writer translation table to convert text into a DNA sequence that is represented as a series of colored spheres in a helix.
The code, by R.M. with some help from myself, is below. It’s pretty rough but works.
dna_translator.py
from visual import *
import string
xaxis = curve(pos=[(0,0),(10,0)])
inp = raw_input("enter text: ")
inp = inp.upper()
t_table={}
t_table['0']="ATA"
t_table['1']="TCT"
t_table['2']="GCG"
t_table['3']="GTG"
t_table['4']="AGA"
t_table['5']="CGC"
t_table['6']="ATT"
t_table['7']="ACC"
t_table['8']="AGG"
t_table['9']="CAA"
t_table['start']="TTG"
t_table['stop']="TAA"
t_table['A']="ACT"
t_table['B']="CAT"
t_table['C']="TCA"
t_table['D']="TAC"
t_table['E']="CTA"
t_table['F']="GCT"
t_table['G']="GTC"
t_table['H']="CGT"
t_table['I']="CTG"
t_table['J']="TGC"
t_table['K']="TCG"
t_table['L']="ATC"
t_table['M']="ACA"
t_table['N']="CTC"
t_table['O']="TGT"
t_table['P']="GAG"
t_table['Q']="TAT"
t_table['R']="CAC"
t_table['S']="TGA"
t_table['T']="TAG"
t_table['U']="GAT"
t_table['V']="GTA"
t_table['W']="ATG"
t_table['X']="AGT"
t_table['Y']="GAC"
t_table['Z']="GCA"
t_table[' ']="AGC"
t_table['.']="ACG"
dna=""
for i in inp:
dna=dna+t_table[i]
print dna
m=0
r=3.0
f=0.5
n=0.0
dn=1.5
start_pos = 1
for i in dna:
rate(10)
n+=dn
m+=1
x = n
y=r*sin(f*n)
z=r*cos(f*n)
a=sphere(pos=(x,y,z))
#print x, y, z
if (i == "A"):
a.color=color.blue
elif (i== "G"):
a.color=color.red
elif (i== "C"):
a.color=color.green