LiPo batteries are a great power source for projects but they require care during use and charging. LiPo batteries can be a fire hazard if not handled properly.
Please read these guidelines on battery handling before you use them!
In this project, students will prototype a bike helmet that has motion-activated turn signals. They get to make a model of a device that serves a practical function. Designing the helmet and then deciding on the best coding strategy and light patterns provide great problem-solving challenges. You can pair students up to interview each other on the requirements for an ideal bicycle helmet and work those features into their designs.
Note: This project is meant as a prototyping exercise only. The cardboard prototype should not be worn while bicycling, and the light system should not be attached to a real helmet for cycling use.
Hours |
---|
About 1.5 hours
See the Maker Tools and Techniques chapter for more details on materials.
There are different ways to make a bike helmet prototype out of cardboard. One idea is to review images of bike helmets as a class. The instructor may want to specify how closely the prototype should resemble an actual helmet. Making something that looks more like a crown or top hat is more immediately intuitive to middle school students, so the instructor should decide in advance what the parameters are.
To make this helmet prototype, think about the directions of the corrugations of your cardboard. The length of these pieces should be perpendicular to the corrugations in order to let them bend easily (see images).
First, either cut a long strip of cardboard that is 2-2.5 inches in width, or else measure someone’s head with a string, then cut a length of cardboard that is at least two inches longer than that – on average, this is about 22 + 2 inches long for adults. This will serve as the base of the helmet. Again, cut so that the corrugations help you bend the cardboard. Wrap tape several times around the ends of the cardboard to secure it at the proper circumference.
Second, cut three 13-inch lengths of 2-3”-wide cardboard perpendicular to the corrugations.
These pieces of cardboard will form the shell of the helmet. Note the orientation of the corrugations of the cardboard. They are perpendicular to the length, which will allow the cardboard to bend more easily.
Third, continue using tape to secure the strips onto the base to form the shell of the helmet.
The cardboard strips should overlap each other to form the shell. Have your students iterate on the design by doing user testing along the way – try fitting the helmet prototype on different students’ heads to refine the design and make adjustments.
Fourth, use clear tape to attach the NeoPixel strip to the base of the helmet prototype. Three pieces of tape are sufficient. Take care to center the strip on the back of the base.
Fifth, use a piece of tape to attach a battery pack to the top of the helmet, and a piece of double-sided or looped tape to attach the Circuit Playground Express to the front of the helmet. Be sure to orient the A1 pin on the Circuit Playground Express toward the alligator clips of the NeoPixel strip, and orient the JST battery connector upward. Pictured is a LiPo battery, but any battery pack works well.
See Coding the Circuit Playground Express chapter for more information.
||loops:LOOPS||
Toolbox drawer and drag out an ||loops:on start||
block to the workspace.||light:NEOPIXEL||
drawer, find the ||light:set strip||
block, and place it inside the ||loops:on start||
block. This will create a NeoPixel strip in our program.let strip: light.NeoPixelStrip = null
strip = light.createStrip(pins.A1, 0)
||light:with 0 pixels||
, enter the number of pixels your LED strip has. In the example, the NeoPixel strip has 30 lights.let strip: light.NeoPixelStrip = null
strip = light.createStrip(pins.A1, 30)
With this code, we are telling the Circuit Playground Express that it has a strip of 30 lights connected on pin A1.
||variables:VARIABLES||
drawer and make two variables: right
and left
. The automatically created variable strip
will control the behavior of the entire strip, and left
and right
will help you control the left and right halves of the strip.Now, let’s define the lights you’ll use for the left and right turns.
||variables:VARIABLES||
Toolbox drawer, pull out two ||variables:set||
variable blocks into the ||loops:on start||
block, and change them to the right
and left
variables.let strip: light.NeoPixelStrip = null
strip = light.createStrip(pins.A1, 30)
let left = 0
let right = 0
||light:strip range||
lozenges inside each of the ||variables:set right||
and ||variables:set left||
blocks. These blocks will represent a range of lights from our NeoPixel strip.
In our example there are 30 total pixels, so the two sides will each have 15 pixels. The ||variables:set right||
block has a range that starts at zero (remember that the strips are zero-indexed, so the first 15 pixels will be from 0-14), and the ||variables:set right||
block has a range that starts at 15
.||light:range||
block, type 0
into the first slot and 15
into the second slot.||light:range||
block, type 15
into the first slot and 15
into the second slot.let left: light.NeoPixelStrip = null
let right: light.NeoPixelStrip = null
let strip: light.NeoPixelStrip = null
strip = light.createStrip(pins.A1, 30)
right = strip.range(0, 15)
left = strip.range(15, 15)
Now let’s set all the lights on the Circuit Playground Express to yellow, and turn the NeoPixel strip lights to blue to serve as running lights.
||light:LIGHT||
Toolbox drawer, drag a ||light:set all pixels||
block into the ||loops:on start||
block, and from the drop-down menu select the yellow color.||light:strip set all pixels||
block to the end of our program, and from the drop-down menu select the light blue color.let left: light.NeoPixelStrip = null
let right: light.NeoPixelStrip = null
let strip: light.NeoPixelStrip = null
strip = light.createStrip(pins.A1, 30)
right = strip.range(0, 15)
left = strip.range(15, 15)
light.setAll(0xffff00)
strip.setAll(0x00ffff)
It’s time to code the motion-activated light responses. When we tilt our head to the left, we want the left side of the strip to flash indicator lights, and when we tilt our head to the right, we want the right side of the strip to flash.
||input:INPUT||
Toolbox drawer, drag out 2 ||input:on shake||
blocks onto the Workspace.||input:on shake||
block, change one to tilt right
, and the other to tilt left
.||loops:LOOPS||
Toolbox drawer, drag out a ||loops:repeat||
loop and drop into the ||input:on tilt right||
block. Change the default number of times to repeat from4
to 15
.||light:strip set all pixels||
block and drop into the ||loops:repeat||
loop. In the ||light:set all pixels||
block, use the drop-down menu to select the right
variable.let right: light.NeoPixelStrip = null
input.onGesture(Gesture.TiltRight, function () {
for (let i = 0; i < 15; i++) {
right.setAll(0xff0000)
}
})
||light:set all pixels||
block, and select Duplicate to make a copy of this block.||loops:LOOPS||
Toolbox drawer, drag out 2 ||loops:pause||
blocks and drop them in between the ||light:set all pixels||
blocks – this will give the lights enough time to flash.let right: light.NeoPixelStrip = null
input.onGesture(Gesture.TiltRight, function () {
for (let i = 0; i < 15; i++) {
right.setAll(0xff0000)
pause(100)
right.setAll(0x007fff)
pause(100)
}
})
After we’re done flashing, we want to set all the lights back to light blue.
||light:set all pixels||
blocks and select Duplicate again to make another copy.||loops:repeat||
loop, and click on the color picker to select light blue.let right: light.NeoPixelStrip = null
input.onGesture(Gesture.TiltRight, function () {
for (let i = 0; i < 15; i++) {
right.setAll(0xff0000)
pause(100)
right.setAll(0x007fff)
pause(100)
}
right.setAll(0x00ffff)
})
We’ll do the same thing for the tilt left
. Copy the blocks from the ||input:on tilt right||
block over to the ||input:on tilt left||
block. Use the variable drop-down menu to select the left
variable this time.
let left: light.NeoPixelStrip = null
input.onGesture(Gesture.TiltLeft, function () {
for (let i = 0; i < 15; i++) {
left.setAll(0xff0000)
pause(100)
left.setAll(0x007fff)
pause(100)
}
left.setAll(0x00ffff)
})
Here is what your final code should look like:
let left: light.NeoPixelStrip = null
let right: light.NeoPixelStrip = null
let strip: light.NeoPixelStrip = null
input.onGesture(Gesture.TiltRight, function () {
for (let i = 0; i < 15; i++) {
right.setAll(0xff0000)
pause(100)
right.setAll(0x007fff)
pause(100)
}
right.setAll(0x00ffff)
})
input.onGesture(Gesture.TiltLeft, function () {
for (let i = 0; i < 15; i++) {
left.setAll(0xff0000)
pause(100)
left.setAll(0x007fff)
pause(100)
}
left.setAll(0x00ffff)
})
strip = light.createStrip(pins.A1, 30)
right = strip.range(0, 15)
left = strip.range(15, 15)
light.setAll(0xffff00)
strip.setAll(0x00ffff)
Here are some ideas for how you can create some additional challenges or variations on this bicycle helmet prototype:
||logic:if then else||
logic block can let you specify how far of a head tilt is needed to trigger the turn signal. (This gives good practice in more advanced computational thinking as well.) In the sample below, a tilt of greater than 500 mg (milligravities) turns on the left side, and a tilt of less than -500 mg turns on the right. Play with those two values until you find a tilt angle that works for you.