Quantcast
Channel: SparkFun Tutorials
Viewing all 1123 articles
Browse latest View live

Addressable RGB LED Music and Sound Visualizer

$
0
0

Addressable RGB LED Music and Sound Visualizer a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t470

Introduction

Let’s face it: nowadays, most musical performances are complimented by some fancy light shows. Go to any concert, festival, club – they all have a corresponding visual performance or effects. Why not add your own home to that list? Here’s a simple yet effective project to make your very own son et lumière!

All palettes work with every visualization, but, for timeliness, not every combination is shown.

Required Materials

To follow along with this tutorial, you’ll need the following:

Any microcontroller with 3.3V and 5V pins will suffice, any analog potentiometer should work, and any resistor between 300–500 Ω can be used. The resistor and capacitor are not required, but they will help prevent possible damage to the LEDs.

If you’re compiling from the Arduino IDE or similar, you’ll want to snag the the NeoPixel Library since the code used is heavily based on it. If you’re using codebender, it will link the library for you.

Depending on your intent, the trimpot and buttons may not be necessary. The trimpot is only used to adjust the brightness threshold, so, if you want maximum brightness, you don’t have to worry about incorporating it. The three buttons cycle visualizations, color schemes, and shuffle mode respectively, so, if you want to do without those features (and just use shuffle mode all the time), that’s also a possibility.

It is also suggested that you use an Arduino and Breadboard Holder to simplify wiring and to mount the LED strip:

Full Visualizer

A small notch was cut in the BReadboard Holder to hold a piece of MDF, on which the LEDs are attached.

Recommended Reading

Before embarking upon this tutorial, you may find the following links useful:

Since we’re using the NeoPixel library, it may also be a good idea to get familiar with the NeoPixel Documentation.

Assembly

This project requires virtually no soldering! The few exceptions will probably be soldering some pins to the sound detector, and, if you’ve cut a roll of addressable LEDs in the middle, you’ll have to solder some wires to the starting LED’s pins. If you’ve never soldered before, I highly suggest taking a look at this guide.

Below is also a general chart for how the pin(s) on each component should be routed and an accompanying diagram. Before you begin, here are some things to keep in mind:

  • Be conscious of the orientation you think would allow the sound detector to take optimal readings for your intentions. Bending the pins to hold the sound detector perpendicular to the breadboard is a recommended option.
  • Electrolytic capacitors are polarized, so how they are oriented is important. Make sure to place the side with a white stripe and a negative symbol into a negative current (ground) and the other into positive current.
  • Resistors and pushbuttons are not polarized.
  • Trimpots are not polarized either, however their middle pin is the analog output, so don’t power that directly.

The pins used in the diagram and the code are in parentheses. If you use a different pin, don’t forget to change it in the code as well:

Sound DetectorAddressable LED stripTrimpotPushbutton1 mF (1000 µF) Capacitor300–500 Ω Resistor
Envelope → Analog (A0)Digital/Analog (A5) → Resistor → DIN5V → left or right pinGND → Either sideBetween ground and 5VBetween Digital/Analog (A5) and DIN on LED strip
3.3V → VCC5V →5V>Middle pin → Analog (A1)Other side → Digital (4, 5, 6)
GND → GND
GND → GND
Remaining left or right pin → GND

alt text

Sound Detector Notes: The microphone used is not a sophisticated, logarithmic sound receiver like your ear; it is only measuring compressional waves in the air. Consequently, the microphone is more likely to detect and/or prioritize lower-frequency sounds since they require more energy to propagat, and therefore oscillate the air more intensely. Also, a resistor can be placed in the “GAIN” slots to modify the gain. Standard gain should be sufficient for our purposes, but, for more info, visit this tutorial.

The entire circuit should look something like the diagram below.

alt text

Fritzing diagram for the circuit as described above. Click the image for a closer look.

Programming

Below is a small sample program to test if everything is connected properly. It only contains one visualizer and one color palette to keep things concise. It doesn’t need buttons since there’s nothing to toggle, but you can still use it to test your potentiometer.

The complete program featured in the video can be found at this GitHub repository.

Things to remember before you compile:

  • If you didn’t use a potentiometer, don’t forget to remove all references to the variable knob in the code (ctrl+F will come in handy for that). Otherwise, the program will think you still have a potentiometer that is set to a very low value (i.e. everything will be very dim).
  • If you didn’t use buttons, change the initialization bool shuffle = false; to bool shuffle = true;. The code should compile and run properly, but for good practice you should remove all blocks the code says to delete since they reference the BUTTON constants.
NOTE: For this example, we're hosting the code on codebender, which not only features code-sharing, but also allows anyone to upload and debug Arduino sketches from within a web browser. Plus, it works on lower-tech machines, like Chromebooks!

There are codebender plugins for Chrome, Chromium, and Firefox. Visit the codebender plugin page for help installing the codebender plugin.

Final Touches

With the electronics and the code working, you can now add your visualizer to a variety of enclosures or art pieces. For the final touches on this project, an elk was laser etched on a piece of acrylic. The LED strip was then wrapped around the outer perimeter of the piece.

Elk

Add some music, and you have yourself a beautiful piece of interactive art.

Resources and Going Further

To see all the code used int his project, visit the GitHub repository.

Need more inspiration? Check out these other SparkFun tutorials:

MiniGen Hookup Guide

Using the MiniGen, SparkFun's Arduino Pro Mini signal generator shield

Interactive Hanging LED Array

Learn how we converted 72 lightbulbs into an interactive LED array for our conference room.

Hackers in Residence - The ElectricBone

Drum machines and keyboards have been the standard for making digital music, but how do you make electronic music if you're trained to play the trombone? One of our Hackers in Residence, Carlos Mello, took it upon himself to find a solution to that very question.

Sound Reactive EL Wire Costume

Learn how to make your EL wire costumes sound reactive in this project tutorial.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado


Beefcake Relay Control Hookup Guide

$
0
0

Beefcake Relay Control Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t522

Introduction

The Beefcake Relay Control Kit is a way to switch loads that could not normally be driven with a microcontroller, such as AC lights, motors, batteries, solenoids, pumps, and more!

alt text

The Beefcake Relay Control Kit

This hookup guide talks about safety, takes you through the assembly process of the Beefcake Relay Control kit and shows how to test it using the most basic Arduino sketch.

Suggested Reading

Saftey and Insulation

This product will potentially be used for mains wiring, so please read this section discussing how much space is required to prevent arcing.

There are a lot of standards out there, like the IEC standards, the UL standards, and the IEEE standards. These cover anything from test techniques, communication interfaces and of course safety. Each country requires a different set of standards for commercially released products, which is an experienced full time position just to make sense of.

The Beefcake Relay Control is a prototyping or component type thing and abides by no standards, but it was designed with safety in mind. Because it’s not a full product though, there is no guarantee that it will be used safely by you, the customer, so please be careful.

Making standards is good for business and compatibility but is also a business itself, so the standards can’t be found for free. However, creative Google searches can reveal the pertinent tables which have obviously come from the standards. Information from the standards have been boiled down to creepage and clearance calculatators for PCBs such as www.creepage.com. These can be used to come up with safe distances.

Play around with the creepage.com calculator, and see how the distances change. This section is intended to inform and not to scare. The terminology is a little odd so here’s a few terms that my demystify the calculator settings.

Functional insulation

Functional insulation is intended to meet the lowest level of isolation for a given voltage. 250VAC is about 1mm.

Basic insulation

This provides a level above nominal to allow surges and other common line disturbances to not cause a breakdown. For 250VAC, 2mm is required.

Double insulation

To make things safe for people to come in contact with, most standards require a second layer so that one can be damaged, and the isolation characteristic is maintained. Of course, this would be twice basic, or 4mm for 250VAC.

Reinforced insulation

Reinforced insulation has the same insulative properties as double, but it is rated to be robust enough to not get cracks and pinholes such that it can be used in place of proper grounding.

Creepage and Clearance

Creepage is defined as the shortest distance between conductive surfaces along the surface of the PCB. It’s easier to conduct along the surface of an object than in free space, so this measure is the distance electrons would have to crawl to get from one conductive thing to another, along the surfaces in between. This will be farther than the clearance requirements.

Clearance is defined as the shortest distance between conductive things (like pads). Or, if there were an arc between the two things, what would the most likely path be?

What this means for the Beefcake Relay Control

Take a look at the PCB with strong lighting through it. The raw fiberglass of the board lets the light through but the copper doesn’t. It’s easy to see the traces and spacing this way.

alt text

There is a lot of distance between the high voltage and low voltage sides. There’s enough that you should be able to safely touch anything on the low voltage side, but please don’t. It’s good practice to avoid working with any circuit that is connected to mains.

Peeking inside the relay we can see a good distance between the low voltage windings and the high voltage contacts. This relay is rated to 2500VAC isolation between the coil and contacts, but manufacturing has statistical failure rates, and the user should always be wary of the dangers.

alt text

Assembly

The Beefcake Relay Control kit is relatively straight forward to assemble. This section outlines what tools will be needed and shows the assembly process.

Materials

The kit contains the following parts:

alt text

  • An electromechanical Relay
  • 2x Terminal blocks, light gauge for signal and heavy for output
  • Coil-active LED
  • Bipolar junction transistor (BJT)
  • 2x Current limiting resistors
  • Flyback arrestor diode
  • Zener diode for discharge

Tools

The following tools are recommended.

Building The Beefcake Relay Control

The Beefcake uses standard through-hole techniques. Components will be passed through the holes, soldered, and the leads trimmed. It’s best to start with the shortest components working up to the taller ones. This is so they stay pressed in place while the board is upside down against a work surface.

Start with the resistors. Bend the leads so they form 90 degree angles as close to the resistor body as possible.

alt text

Feed them into the place marked 1k. They will sit over the silkscreen box.

alt text

Next, bend the diode leads. The diode bodies are shorter, so it’s not necessary to get the bends right close. They should be the same widths as the resistors after bending.

alt text

Insert the diodes. The fat diode is the 9.1V zener, and should be marked 4739. Place it over the silkscreen box labled “Zener” with the black band towards the white silkscreen stripe. The smaller diode should be labled 4148 and is a standard high-speed diode. Place it over the box labled N4148 with the black stripe towards the silk stripe.

alt text

Now, flip the board, and solder those components forming nice shiny cones around the leads. A weight, like the solder stand, can be used to hold the board, or it can be placed in a vice.

alt text

Clip the component leads right at the top of the solder cones.

alt text

Next, prepare the BJT. Leave the outer two legs straight. Bend the inner leg in an ’S' curve so that it is spaced evenly from the other two legs in an equilateral triangle.

alt text

Fit the BJT and LED into the board, minding that the flat side of the LED matches the flat part of the silkscreen circle.

Solder them in place, and trim the leads.

alt text

Attach the screw terminals. Orient them so the apertures face outward. These will stay in pretty well, so flip it and solder in place.

alt text

The last component is the relay. The relay has thick leads for current capacity, so they may need a little work getting inserted. Once they are all positioned, it should sit flush with the PCB.

alt text

Inserting the relay

The extra copper involved in carrying the current means it can take extra heat to get the solder to flow, but it is very important. A cold solder joint will cause extra resistance. With the recommended Hakko iron set to 700 degrees, there should be no problem, but the iron will have to be held on longer than normal. Feed extra solder if the joint is looking dirty, the flux will come out, and you can scoop away the extra solder with the iron right after.

alt text

Notice that the iron touches both the post and the plated through hole heating them up together.

Congratulations! You now have a completed Beefcake Relay Control circuit. Here’s what the final product will look like.

alt text

alt text

Example: Arduino Control

Now, it’s time to make the relay sing the song of its people. Connect the 5V terminal to 5V power capable of supplying 150mA, the ground to ground, and a signal wire from a digital output to the control pin (CTRL).

alt text

A basic example is the blink.ino sketch. Connect the signal pin to digital out 13, which is the same as the LED. Connect Ground to the GND terminal and 5 volts to the 5V terminal as shown below.

alt text

Now, as the LED on the microcontroller board blinks, the relay will energize, and the Beefcake’s LED will illuminate. You should hear a pleasant clicking sound every second.

alt text

Ahh, so satisfying. But, really this should be used to switch a load. Here I’ve attached 12 gauge solid house wiring into the terminals, which was a pretty tight fit. The terminals are only specified to 14 gauge wire.

alt text

If you would like a more permanent installation, go ahead and solder to the large lugs on the edge of the board. This will take even more heat with the large solid copper wires, so be patient.

alt text

Here the solder is kinda sticking but really, it’s just blobing up. More heat is needed.

A technique for getting a bit of extra heat in there is to warm up a second iron, blob up a bunch of solder first, the heat with both irons.

alt text

Conclusion and Resources

You should now have a relay capable of switching loads from a microcontroller. But what to switch? Motors? Floor lamps? Other relays? It’s up to you!

Here’s a few tutorials to inspire you. They use the Beefcake to switch some fun stuff, including fire.

ESP8266 Powered Propane Poofer

Learn how Nick Poole built a WiFi controlled fire-cannon using the ESP8266 Thing Dev Board!

Blynk Board Bridge Widget Demo

A Blynk project that demonstrates how to use the Bridge widget to get two (or more) Blynk Boards to communicate.
New!

How to Build a Remote Kill Switch

Learn how to build a wireless controller to kill power when things go... sentient.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Photon Remote Water Level Sensor

$
0
0

Photon Remote Water Level Sensor a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t138

Introduction

With the advent of cheap Microcontrollers (MCUs), and especially WiFi-MCUs of late, custom DIY automation of many monotonous tasks and telemetry (remote data collection) is now easily possible.

In this tutorial, we are going to automate a pump for a well based on a remote measurements of a water tank and send weather warnings based on atmospheric pressure readings, as well as collect a bunch of other data. This same type of system could easily be adapted for automated farm/garden watering or other things that need to be turned on and off when some condition is met (like lights in a warehouse/greenhouse at certain times), measured via remote telemetry.

The Problem

My friend, Andre, owns a CSA farm in Boulder, CO called Jacob Springs Farm. They make some tasty meat, milk, and eggs, so, if you’re local, check them out.

jsf sign and water tank

The farm sign on 75th and Arapahoe in Boulder, CO and the water tank behind it. You can see the water level is nearly empty, as is typical without any automation/telemetry system in place.

They aren’t legally allowed to run a city water line to the property, so they use a well and their own storage tanks. The pump for the well is manually turned on or off using a twist timer (which is actually only rated for 50% of the pump’s current load), and typically they have no idea how much water is in the tanks (unless they’re empty). I’ve heard hilariously tragic stories of people being in the shower and having the water run out during winter. They have to run out to the barn, all soaped up and in their towel, turn on the water, and wait for the water heater to fill up and heat so they can finish their shower. Other times the water runs out while preparing dinner or doing dishes, and the low water pressure makes for slow going.

jsf existing setup and barn

The barn with the pump control, and the existing pump control timer.

The water tanks are on one corner of the property (the highest elevation), far from any power outlets, and the pump for the well is at the other end. In order to manage the water system for the farm, I’ve developed this system that measures the water height with an ultrasonic sensor and controls the pump from that data. While I was at it, I added some extra environmental sensors.

Required Materials

This project is two-fold: remote telemetry (measurements) coupled with automated weather warnings, and remote control/automation of a hefty (2 hp) pump. To follow along with this tutorial, you’ll need the following products and tools:

Pump Remote Control Box

For the automation of the pump, you will need:

  • 1 contactor to turn on/off the pump, rated for the pump load (3hp, 2200W in this case, but choose the contactor with an appropriate horsepower rating for your application), or a relay if the load is light enough
  • 10A relay to control the contactor
  • Particle Photon WiFi MCU to control the relay
  • Photon ProtoShield
  • female headers
  • male-male jumper wires
  • 5 V power supply for the photon
  • box to hold the photon and relay
  • PIR sensor to check if someone is near the control box/contactor
  • 10 k resistor for the PIR
  • a few mounting screws (5), I used #8 1-¼" drywall screws, a DIN rail is more professional
  • appropriate wiring for your loads (check here for max amperage for different wire gauges) – I used about 2 ft of 18 AWG for control of the contactor, and about 5ft of 10 AWG for wiring leading to the pump

control box supplies

Some of the supplies used for the pump control box. Not shown here: 10 k resistor, jumper wires, headers, screws, relay, contactor.

Remote Telemetry Box (water height, etc)

The other half of the project is remote data collection. For this, you will need:

telemetry supplies

Most all of the supplies used for the telemetry box.

Here’s a wish list containing all the SparkFun parts used in this project:

Tools

  • Drill
  • drill bits: ¾", 5/8", ½", 1/8"
  • soldering iron, solder, optional: third hand, copper sponge (for cleaning soldering iron tip)
  • wire strippers
  • hot glue gun and hot glue
  • heat gun for shrink wrap (can use hair dryer in a pinch)
  • screw driver
  • two pairs needle-nosed pliers
  • exacto knife
  • tape measure
  • sledge hammer for driving a grounding rod into the ground

tools

Here’s most of the tools I used (not pictured: copper sponge).

more tools

Here’s some other tools I used, and the tools used to cut the headers to size (right).

Other Supplies

  • Gore-Tex® repair patch kit (I sourced locally at REI, but also available here)
  • acetone or other solvent to remove adhesive from Gore-Tex® patch (may not need this for the Simms patches)
  • 2 PG-7 cable glands
  • silicone
  • small glass piece, I got mine from Hobby Lobby
  • AC cord with bare leads for testing contactor
  • aluminum foil (for shielding the ultrasonic sensor from static from the plastic water tank)
  • grounding rod for grounding the aluminum foil housing (I used ½" 10' EMT conduit)

other supplies

Other supplies that were used.

Suggested Reading

Before embarking upon this tutorial, you may find the following links useful:

Photon Development Guide

August 20, 2015

A guide to the online and offline Particle IDE's to help aid you in your Photon development.

Photon Battery Shield Hookup Guide

July 2, 2015

The Photon Battery Shield has everything your Photon needs to run off, charge, and monitor a LiPo battery. Read through this hookup guide to get started using it.

Prepping the Photons

The first thing is to get your Photons prepped and ready to accept firmware over WiFi.

If you have never used the Particle Photon before, you will need to visit the Particle website to learn how to setup a Photon for first time use. You will need to connect it to your local network, pair the device with your free Particle cloud account, and possibly update firmware before you will be ready to upload your first program. All of that information can be found at the following link:

Getting Started with the Photon

Once your Photon setup, you will also need to install the Particle Command Line Interface (CLI) on your computer. This will allow us to watch the serial output from the Photon in our terminal/command console.

Install the Particle CLI

Build the Pump Controller

The contactor/relay idea is used here to control a pump for a well, but could also be used to control a solenoid for a sprinkler/watering system (you’d probably only need a relay in that case), or to switch on lights, motors, or pumps in a structure (greenhouse, warehouse, etc), heavy-duty heaters, or other remote control needs you might have.

Triacs, Contactors, and Relays – Oh My

To begin, let’s discuss the various ways to control AC power.

To switch lighter, resistive AC loads (like a small electric heater), a relay can be used. However, once you need to switch a pump on or off, or another inductive load, a different kind of switch is usually needed. Why? It’s because when inductive loads start up, they exert a huge load–but only temporarily. See this stackexchange question. Using an undersized relay with an inductive load like a pump can be a dangerous proposition; the heat from the start up of an inductive load could eventually fuse the relay contacts together, leaving your pump constantly on and you not even knowing it.

inrush current from various sources

Inrush currents from various electrical things. Source: here.

Here is a video of the contactor I installed in operation and the kWh meter. You can clearly see that when the pump turns on, there’s a huge inrush of current. After that, the current subsides.

A triac is another way to control AC with silent operation, though I won’t go into any details as this project didn’t use any.

For a beefy motor, like a well pump or other industrial sized applications (like turning on the lights in an entire warehouse, etc), you want to use a contactor. These are rated by UL for certain motor loads, like 1 hp (~750 W), 2 hp (~1500 W), etc. In our case, we have a motor that I measured at 1500 W – about 2 hp. Oversizing electrical components is usually the safest bet, so I picked a 3 hp contactor from US Breaker Inc., which had some of the best prices I could find. The datasheet tells us it can handle 3 hp at 120 V. The coil, which controls the contactor, takes about 2 A at startup and about 0.2 A thereafter, so a 10 A relay is more than enough to handle this, plus we can then easily control this from a MCU. The coil runs off of straight-up 120 V, so we don’t need another power supply to control the contactor, just a relay that can switch up to 2 A at 120 V.

the beefy 3 hp contactor

The beefy 3 hp contactor I used. This thing is hefty, and should be reliable long-term.

The breaker is rated for 800,000 cycles, which should last about 91 years if the breaker is switched every hour (and it will probably be switched much less often). US Breaker has other contactors that can handle up to 7.5 hp inductive loads (5600 W) at 120 V in case you need more beef.

Electrical Setup

If you’re new to soldering check out this tutorial and practice on some scrap parts before trying the real thing. Solder the relay together, if you’re using the SparkFun Kit. You can find assembly instructions for the relay kit in this hookup guide.

Cut 2 sets of female headers to the correct size (20 units) by first scoring with an exacto knife (I do it on all sides of the headers), then use two pairs of needle-nosed pliers to make a clean break. Score each side a few times to get a deep cut. It will probably take you a few tries to get the hang of it, so don’t get discouraged when the first few don’t work out.

cutting headers

Break headers to the correct size by first scoring with an exacto knife around the perimeter, then using two needle-nosed pliers to make a clean break.

Assemble 3 male-to-male jumpers into a connector for the PIR and relay. There should be a 10kΩ resistor between the 5V (Vin) and dataline for the PIR. The 5V line should be split, one to go to the relay and one to the PIR. Before soldering things together, put some heatshrink on the wires so it is easy to cover up bare wires. After soldering, heat the heatshrink with the heat gun until they tightly grip the wires (don’t heat for more than 5-8 seconds).

jumper setup

I used my third hand tool to help me hold everything in place while I soldered.

Solder the headers to the ProtoShield. Solder the PIR data header to the D7 hole, the Vcc header to the Vin hole, and the GND header to one of the GND holes. Solder another jumper to the other GND hole and one more jumper to the D0 hole for the relay.

protoboard

Here’s a top view of the completed protoboard. Make sure to plug the Photon in the right direction (use the white guidelines on the board).

Next, test the relay and contactor to make sure everyone’s riding on the gravy train. Connect the GND, Vin, and D0 jumpers to the GND, 5V, and CTRL of the relay board, respectively. Upload the code below (via build.particle.io) to your Photon to test the relay (listen for the clicking every few seconds to make sure it works and watch the LED. You can also test the resistance between the ‘load’ and ‘normally open’ screw terminals on the relay to make sure it goes between 0 and infinity if you wish.

language:c
void setup() {
    pinMode(0, OUTPUT);
}

void loop() {
    digitalWrite(0, HIGH);
    delay(2000);
    digitalWrite(0, LOW);
    delay(2000);
}

Next is the contactor. Hook up some wire from an AC plug to the relay terminal, then from the other relay terminal to the contactor A1 connector, and last the other end of the AC wire to the contactor A2 terminal. Run the relay test again and make sure the contactor is switching. You will definitely notice when the contactor is working, as it clicks on and off with authoritah. You can again use a multimeter to watch the resistance between some of the ’T' and ‘L’ terminals if you wish; it should drop from 1 to 0 when the relay is on.

contactor relay hookup

Circuit diagram of the contactor and relay.

contactor relay hookup

My action shot of the contactor and relay.

Not surprisingly, the beefy contactor is much louder than the relatively cutesy little relay.

Connect the PIR sensor to the Photon: connect the D7 jumper to the signal line (black wire), the Vin to the red wire, and the white wire to GND. There’s a tutorial here explaining more about this sensor, but it’s pretty simple – when motion is detected, the output pin from the sensor pulls low. Power up the Photon, and upload this code:

language:c
void setup() {
    pinMode(7, INPUT);
}

void loop() {
    int pirVal = digitalRead(7);
    if(pirVal == LOW){
        Serial.println("Motion Detected");
        delay(2000);
    }
}

Check to make sure the PIR sets off the alarm when you wave your hand in front of it. You can tell if it’s working because the D7 LED will light up when the alarm is triggered. Additionally, you can type ‘particle serial monitor’ in your terminal/command console (with the Photon plugged into your computer via USB) to watch the serial output from the device, which should print ‘Motion Detected’ when you wave your hand in front of it.

contactor relay hookup

The full circuit diagram of the pump controller. Caution: the colors on your PIR sensor wires may differ form the one in the diagram.

Physical Construction

First, drill a hole in the front of the case for the PIR sensor. The PIR sensor used here has a diameter of about 0.85", or 21.5 mm, so I used a ¾" drill bit and widened the hole with the ½" drill bit. I hot-glued the PIR in there. Add some hot glue on the corners of the board to hold it to the red box. For a more secure job, drill holes, and use 2mm screws and nuts to secure the board to the case.

PIR sensor hole

The hole for the PIR sensor should measure about 0.85".

Next, drill a ½" hole in the side of the case. Drill some 1/8" holes for mounting the ProtoShield and relay, if you want to secure the board with 6-32 screws or a similar size. For ease and quickness, I just hotglued the boards to the box.

String the 5V power supply cord through the ½" hole we drilled in the side of the enclosure, and plug the micro-USB power cord into the Photon. If you want to be more professional, use a PG-7 cable gland to string the wires through. Attach some wires to the relay, leaving enough length to connect to the AC leads in your field installation (I used 18-gauge wire, since this will only be carrying about 0.2A at steady-state). If you drilled mounting holes for the relay and protoboard earlier, secure the boards using screws. Otherwise, use a hot glue gun to attach the boards to the case. Finally, hot glue the wires through the hole for strain relief and to prevent pull-out of the wires from the relay.

completed control box

Complete setup of the control box and strain relief of the pass-through wires.

Finally, screw the box together with the six screws on top.

Field Installation

Use some screws to attach the box to a wall near your pump and AC leads and some screws as mounting for the contactor, if you’re not going with a DIN rail. I used some extra screws we had laying around, they seem like #8 1-¼" drywall screws, and I drilled shallow 1/8" pilot holes before screwing them in.

pump control fully installed

The control box and contactor completely mounted.

Once the contactor screws are in, hang the contactor on them, and tighten the screws so that the contactor won’t be rattling around much. Take the contactor back off, attach your wires to the terminals L1, T1, A1, A2, and the GND terminal (you will ideally want a small bolt/nut for this GND connection, seems like 6-32 with ½" length would work). If you’re going to be in a dusty area (for example, we’re in a wood shop) use protection and cover the contactor with plastic, etc. Finally, hook up the wires correctly to the pump and power cord, as shown in the full circuit diagram below.

contactor relay hookup

The full circuit diagram of the pump controller.

Run the relay test program from earlier to verify everything is working.

We’ll come back to data collection and automation of the pump control after installing the remote sensor.

Build the Remote Telemetry Box

Energy Considerations – Battery and Solar Cell Sizing

The plan is to periodically wake up the Photon to take a measurement, then put it into deep sleep if the battery level is not very full. The Photon energy use specs are here. The maximum average WiFi operating current is 100mA, and the maximum deep sleep operating current is 0.1mA. Assuming an on time of 60 seconds and an off time of 5 minutes, we use about 400mAh per day. If we want to have the Photon last for three days without any sunlight (sometimes it can blizzard here for a day or two), we need at least 1200mAh of battery capacity. The nearest battery size available from SparkFun, rounding up, is 2000mAh. However, you can play with the sleep cycle time by copying this spreadsheet and get down to a pretty small battery size. Also, by sleeping the Photon longer at night when there’s less water usage, we can extend the battery life dramatically.

Pin LabelPin Description
1Switch contact 1
2Switch contact 2
+LED anode
-LED cathode

A Watt = V * A, so our 3.5W solar cell providing power at 5V is pushing 0.7A. We should be able to charge our 2000mAh battery pretty quickly (about 3h) under ideal conditions. However, the cell will get dusty, days will be cloudy, etc, so it’s best to oversize when in doubt. If you want to save some bucks, the 2W solar cell should push about 0.4A under ideal conditions.

Physical Construction

Drill ½" holes for the cable gland and pressure/humidity hole on the side of the box you expect to get the least rainfall/water exposure, and a ¼" hole for the antenna on the same side. Drill another ½" hole in the lid of the box for the photocell window. I accidentally installed the antenna on the top of the box, where rain will hit it directly. If you want to mount the battery shield with 6-32 screws, drill some 1/8" holes as well on the bottom of the box. Put silicone around the photocell hole on the cover and press the glass on the outside of the hole. Put silicone around the cable gland hole and the antenna hole, and install both of them.

holes in telemetry box

Drill four holes in the telemetry box: one for the antenna, one for the photocell, one for pressure/humidity equilibration, and one feedthrough for the wires. You will want to put the hole for the antenna on the same side as the cable gland and humidity equilibration hole.

Waterproof Holes

We need a hole to let humidity, pressure, and temperature equilibrate with our BME280 sensor, but we don’t want to let rain water in. The solution I came up with is to use a GoreTex repair patch pad and to use a solvent to get rid of the adhesive on the area that lets humidity through. Most solvents you’ve got laying around should be fine (acetone, mineral spirits, goof-off, ethanol–such as Everclear), but check with this chart before trying any solvents not mentioned here. Take a rag, paper towel or napkin, douse it with some acetone, and rub off the adhesive on the back of the repair patch. This will dissolve the adhesive after a bit of work. When you can touch the spot you’ve treated and don’t feel the sticky adhesive, you’re probably good. I’m not sure if the adhesive lets moisture and pressure through very well or not, as I haven’t tested, but, once the adhesive is removed, it works well.

acetone_treatment

Use a rag or napkin, etc to remove the adhesive from the center of the Gore-Tex® patch.

Put a bit of silicone around the hole just to make sure it gets sealed well, and apply the patch.

Electrical Hookup

Battery Shield

Solder the four legs of the SMD barrel jack plug to the board, as described here.

the SMD barrel jack soldered onto the battery shield

Solder the four legs of the barrel jack onto the battery shield. Source: here.

You can test it with the MAX17043 library. Details on using the battery shield are beyond the scope of this project tutorial, as that information can be found in the Battery Shield Hookup Guide.

BME 280 Pressure, Humidity, Temperature

The BME280 can read pressure, humidity, and temperature, so it makes a nice mini weather station. Changes in air pressure are an easy way to predict incoming storms (unless you’re in a more tropical climate, like the gulf coast). We can use some guidelines to classify pressure changes on the hour timescale, and we’ll post that information to a Twitter account. Basically, if pressure is dropping, the rate of the drop indicates how soon a storm is likely on the way. Dropping air pressure usually also means rising wind speeds; rising pressure usually means good weather.

Here’s a table of pressure drop over three hours that we’re going to use to classify our data, referenced from here:

Classificationmin pressure rate (inHg/min * 10^6)max pressure (inHg/min *10^6)lower limit % change over 3 hours
Steady0160
Changing slowly162460.01
Changing moderately2465740.15
Changing rapidly5749840.35
Changing very rapidly9840.59

Essentially, if we have a 0.6% change in pressure in three hours, the pressure is changing very rapidly and bad weather may be on the way. We’ll post to a Twitter account and set up text alerts for when pressure is dropping very rapidly. The spreadsheet for the calculations is here, in case you want copy it and mess with it.

Solder some M-M jumpers to the BME280 board, and solder the other ends to GND, 3.3V, and D0/D1 (SDA/SCL) pins on the battery shield, respectively.

the BME280 fritzing diagram

The circuit diagram for hooking up the BME280 to the Particle Photon. Note the SDA/SCL pins are D0/D1 on the Photon.

the BME280 sensor board soldered to the photon battery shield

Male-male jumpers have been soldered betwixt the BME280 and the Photon battery shield (I had accidentally soldered to the A4/A5 pins at this point, which are SDA/SCL on Arduino UNO).

Start a new Photon project on www.build.particle.io, include the library “SPARKFUNBME280” (click the ‘Libraries’ icon on the left, search in the box for BME280, click the SPARKFUNBME280 library, click ‘Include in App’, click the name of your app, click ‘Add to App’) and upload this code to your photon to test the sensor:

language:c
/******************************************************************************
I2C_and_SPI_Multisensor.ino
BME280 Particle Photon example

Sensor A is I2C and connected through D0/D1 (SDA/SCL)
******************************************************************************/

#include "SparkFunBME280/SparkFunBME280.h"

BME280 mySensorA;

void setup()
{
    // set up sensor
    mySensorA.settings.commInterface = I2C_MODE;
    mySensorA.settings.I2CAddress = 0x77;
    mySensorA.settings.runMode = 3; //  3, Normal mode
    mySensorA.settings.tStandby = 0; //  0, 0.5ms
    mySensorA.settings.filter = 0; //  0, filter off
    //tempOverSample can be:
    //  0, skipped
    //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
    mySensorA.settings.tempOverSample = 1;
    //pressOverSample can be:
    //  0, skipped
    //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
    mySensorA.settings.pressOverSample = 1;
    //humidOverSample can be:
    //  0, skipped
    //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
    mySensorA.settings.humidOverSample = 1;


    delay(6000); // so you have time to start the serial monitor and see the initial output
    Serial.print("Program Started\n");
    Serial.println("Starting BME280s... result of .begin():");
    delay(10);  //Make sure sensor had enough time to turn on. BME280 requires 2ms to start up.
    //Calling .begin() causes the settings to be loaded
    Serial.print("Sensor A: 0x");
    Serial.println(mySensorA.begin(), HEX);
}

void loop()
{
    //Start with temperature, as that data is needed for accurate compensation.
    //Reading the temperature updates the compensators of the other functions
    //in the background.
    Serial.print("Tempferature: ");
    Serial.print(mySensorA.readTempC(), 2);
    Serial.println(" degrees C");

    Serial.print("Temperature: ");
    Serial.print(mySensorA.readTempF(), 2);
    Serial.println(" degrees F");

    Serial.print("Pressure: ");
    Serial.print(mySensorA.readFloatPressure(), 2);
    Serial.println(" Pa");

    Serial.print("Pressure: ");
    Serial.print(mySensorA.readFloatPressure()*29.529983/100000, 2);
    Serial.println(" inHg");

    Serial.print("Altitude: ");
    Serial.print(mySensorA.readFloatAltitudeMeters(), 2);
    Serial.println("m");

    Serial.print("Altitude: ");
    Serial.print(mySensorA.readFloatAltitudeFeet(), 2);
    Serial.println("ft");

    Serial.print("%RH: ");
    Serial.print(mySensorA.readFloatHumidity(), 2);
    Serial.println(" %");

    Serial.println();

    delay(2000);

}

Type ‘particle serial monitor’ in your command prompt/terminal, and check to make sure the output is reasonable and working.

CdS Photocell

To measure light levels, we’ll use a CdS photocell. We’re going to use a 1 k resistor as a pull-down. Information on how to use a photocell can be found here. Solder the connections as so:

Photon to CdS circuit schematic, with BME280

The circuit diagram for hooking up the BME280 and CdS photocell to the Particle Photon. Note the SDA/SCL pins are D0/D1 on the Photon.

all connections soldered to the battery shield; the CdS before shrinkwrapping

The CdS photocell hookup is pretty simple, just 3.3V, GND, and A1.

It ended up being tough for me to place the CdS cell in the glass window because my wires were too short, so leave yourself some extra room with at least eight inches of wiring between the battery shield and the CdS cell.

Test the reading of the photocell with a flashlight, using this code:

language:c
void setup() {
    pinMode(A1, INPUT);
}

void loop() {
    float lightIntensity = analogRead(A1);
    Serial.println(lightIntensity);
    delay(1000);
}

Check the serial output with ‘particle serial monitor’, and make sure the number goes up when you shine a bright light on it. The number should read in the thousands; the range of the Photon analog signal is from 0 to 4095, so make sure the reading isn’t near 4095 unless you’re in broad daylight or close to a bright LED. There’s a nice classification of voltage output levels for different lighting conditions here.

Sensing Distance (Water Height) with an Ultrasonic Sensor

Because air and water have different densities, the water reflects some of the ultrasonic waves sent at it, for example, by something like the MaxSonar-EZ3 sensor (manufacturer’s page here). Again, I recommend the waterproof version for reliability.

To add this part to the telemetry box, first measure the distance from where you will put the telemetry box to where the ultrasonic sensor will go, and cut three sufficient lengths of wire. I used 22 AWG hookup wire and ended up with about 8 to 10 ft of wire. Solder the wires to the GND, +5, and PW holes on the device, by soldering the ends of the wires. Pass the wires through the cable gland, and solder the other ends of the wires to the battery shield: GND, 3.3V (or Vin), and A0.

Photon to CdS, BME280, and ultrasonic circuit schematic

The circuit diagram for hooking up the MaxSonic ultrasonic sensor, BME280 and CdS photocell to the Particle Photon battery shield. Note the SDA/SCL pins are D0/D1 on the Photon.

soldered connections to the ultrasonic sensor

The soldered connection between the ultrasonic PW, GND, and 5V (can take 2.5-5V), and the Photon Battery Shield.

cables passed through the cable gland to the battery shield

Make sure to pass the wires through the cable gland before soldering to the Battery Shield.

Test the device by uploading this code to your Photon:

language:c
float uSperInch = 147; // from datasheet
float distance;
unsigned long duration;

void setup() {
    pinMode(A0, INPUT);
}

void loop() {
    duration = pulseIn(A0, HIGH);
    Serial.print("pulse length: ");
    Serial.println(duration);
    distance = duration / uSperInch;
    Serial.print(distance);
    Serial.println(" in");
    delay(1000);
}

The datasheet from the manufacturer’s page says the pulse width is 147uS/inch, and it seemed to be right around there for me. Double check the readings with a measuring tape though.

Finishing the Telemetry Box

The few last things to do are pass through the solar cell barrel jack, stuff everything in the box (maybe with a little hot glue), and make sure all the external holes look well sealed up.

We have to cut the solar cell wire in two, and, using your wire strippers, strip each wire down. Then pass the wires through the cable gland and solder them back together. I used heat shrink to make the connections clean. The solar cell cable length is very short, so you might want to add some extensions. You could also add enough of an extension so that the box is in the shade (so it doesn’t get too hot, especially if you’re in the desert).

solar cell cables passed through the cable gland to the battery shield

Chop the solar cell cable, put it through the cable gland, and re-attach it.

Finally, connect the battery and the solar cell to the Battery Shield, and put everything in the box as best you can. I hot-glued most things down, but in the sun, things get pretty hot (as we’ll see from the measurements), so the glue tends to un-stick. I did hot-glue the CdS cell to the glass window, and even after it un-stuck (and I reopened the box), it was still pretty easy to put back in the window due to the shape of the glue. Lastly, tighten the six screws down on the top of the box, tighten the cable gland, and maybe put some silicone on the cable gland to make sure it’s good and waterproof.

all the telemetry pieces in the box

Here’s everything in the altered box. The extra loops of wire are from the ultrasonic sensor wires.

Field Installation

Put the box and solar cell in a place that’s going to get some sun. String the wires from the box through to the water tank. This is where things get tricky. If you have giant plastic water tanks, like we do, you’ll likely get static electricity buildup that will interfere with the measurements. As long as the sensor isn’t touching the tank (I also covered the sensor in aluminum foil and grounded it with a ground rod), it should be ok. If the tank isn’t plastic, you can drill a 5/8" hole somewhere in the tank. I covered most of the ultrasonic sensor with black electrical tape as a bit of protection.

If your tank is outside, you will probably be getting condensation at times. The waterproof sensor may fix this problem, otherwise, mount the non-waterproof sensor above the tank (with a hole to let the ultrasound pass into the tank) so that condensation won’t be happening on the sensor.

the ultrasonic sensor protected by tape and the hole it goes into

I put black electrical tape on the sensor for some protection and shoved it into the 5/8" hole on top of the water tank.

The water tanks on the property where this was installed are gigantic plastic (polyethylene, probably) tanks. The pump is about a half mile away, and the whole distance is bridged by PVC pipe. Possibly due to this, there seems to some static buildup in the system. As evidence, I’ve felt a massive static field (6-12 inches above the tank) before while climbing on top of the tanks. This appeared to be effecting the ultrasonic sensor, as it would perform great in lab tests, but out in the field it would get wonky after a few measurements (reading values smaller than the minimum distance), and correct measurements would come and go during the day and night. Things seemed to go haywire after the water started flowing for an hour or two–in either direction, in or out.

The other strange thing about this whole deal is when I would plug the photon into my computer, the readings would be OK again, and when I unplugged it, they would go back to being very small and incorrect.

the effects of static electricity on the ultrasonic measurements

About an hour after the pump was turned on, the ultrasonic measurement went a bit crazy. Then, a few hours later, it settled back down to the accurate reading. The same thing happened the next morning after the water had been flowing out of the tanks for a few hours.

To combat this, I drove a 10ft ½" EMT conduit rod about nine feet into the ground with a sledge hammer. I took a wire and connected one end to the EMT conduit. On the other end, I tied a stainless steel bolt to it and dropped it in the water tank. I also tied a wire around the ultrasonic sensor’s plastic housing and connected it to the EMT rod. It seemed to help somewhat, but still didn’t completely fix the problem.

DIY grounding rod

The DIY grounding rod: before pounding (left) and after (right).

The only way I was able to get the sensor to reliably read water height was to suspend it above the tank, without the plastic housing touching the water tanks. I wrapped the sensor in aluminum foil (except the front face) and attached the ground wire to the foil. I then drilled some holes in a 1.5" aluminum flat bar, attached the bar to the water tank, and attached a grounding wire to the bar. After that, the readings were stable.

However, after a few days, the readings started going haywire. I found there was condensation on the sensor that caused this. If your water tank is outside, mount the sensor above the tank (using something like the metal plate I used), and put a hole in the tank (larger than the sensor diameter), directly below the sensor.

the aluminum bar after drilling holes

I drilled two 5/8" holes for the two ultrasonic sensors I’m using, a few holes for bolts to hold it to the water tank, and a hole for a grounding wire.

suspension of the sensor

The aluminum bar suspended from the water tank with the sensor in place.

Some people claim plastic can’t be grounded, and they may be right. However, adding a grounding lug at the inlet to the tank may work, although I haven’t tried this.

alt text

My installation of the out-of-tank waterproof ultrasonic sensor. The sensor is mounted slightly above the tank, with a hole drilled in the tank. This prevents condensation from interfering with the sensor (only necessary if the tank is outdoors).

alt text

Final installation of the telemetry box. I ended up using a yagi antenna (bought from Ebay) to be able to get wifi reception reliably.

Using the waterproof HRXL sensor may completely bypass the static electricity problem; I’m not sure. In any case, it would be a better idea for long-term robustness to use the waterproof sensor.

Finally, you need to know the distance from the bottom of the tank to the front of the sensor, so get out your measuring tape and check that now, and make a note of it. To get the water height, we simply take the total water tank height and subtract the distance read from the ultrasonic sensor.

The Code

The code for this project lives on GitHub. You can find all the latest by following the link below.

Photon Remote Water Level Sensor Code

Minimum Viable Product

In the startup world, a minimum viable product (MVP) is something that gets the job done and nothing more. I’ll give you an example of the MVP for the setup we’ve built here.

Particle Publish and Subscribe

Using the function Particle.Publish(), we can quickly toss up a variable online so other Photons or devices can use it. In this example it will be used to send the water height and let our pump control box know the water height sensor is still online, and it can also be used to send commands, like ‘turn on the pump’, or ‘don’t deep sleep our telemetry Photon quite yet’.

The format of a publish is MQTT-like. A subscription works like a prefix filter. If you subscribe to “foo”, you will receive any event whose name begins with “foo”, including “foo”, “fool”, “foobar”, and “food/indian/sweet-curry-beans”.

I set up my prefix organization and subscribes as so:

language:c
Particle.subscribe("jsf/waterSystem/", eventHandler, MY_DEVICES);

If I want the water height sensor to tell the control box that it’s still online, I would do:

language:c
Particle.publish("jsf/waterSystem/waterTankSensor/online", "true");

You can also use the ‘private’ flag with your publishes, and use the ‘MY_DEVICES’ flag with your subscribes, if you want to improve security.

Depending on your situation, you may be sleeping the telemetry Photon for a long time and only have it on for a few minutes or seconds. In this case, it makes updating the software tough. For that, I created a Python script that senses when the Photon comes online and tells it to wait a bit for a software update. If you want to use it, install Python – I like using Python(x,y) for Windows, and run this script (first install sseclient, requests, and json using pip or easy_install; type ‘easy_install sseclient’ or ‘pip install sseclient’ in your command prompt or terminal for sseclient, requests, and json):

language:python
from sseclient import SSEClient
import requests, re, json

access_token = "YOUR ACCESS TOKEN HERE"
publish_prefix_head = "myFarm" # for subscribing to incoming messages, e.g. myFarm
publish_prefix = "myFarm/waterSystem" # e.g. myFarm/waterSystem
messages = SSEClient('https://api.spark.io/v1/events/' + publish_prefix_head + '?access_token=' + access_token)
r = requests.post('https://api.particle.io/v1/devices/events', data = {"name":publish_prefix + "/waterTankSensor/update", "data":"true", "private":"false", "ttl":"60", "access_token":access_token})
if r.json()['ok']==True:
    print 'successfully sent update request'


with open('recorded messages.txt', 'w') as record:
    for msg in messages:
        event = str(msg.event).encode('utf-8')
        data = str(msg.data).encode('utf-8')
        if re.search('jsf', event):
            dataJson = json.loads(data)
            if event == publish_prefix + '/waterTankSensor/online' and dataJson['data'] == "true":
                r = requests.post('https://api.particle.io/v1/devices/events', data = {"name":publish_prefix + "/waterTankSensor/update", "data":"true", "private":"false", "ttl":"60", "access_token":access_token})
                if r.json()['ok']==True:
                    print 'successfully sent update request'
            if event == publish_prefix + '/waterTankSensor/updateConfirm':
                if dataJson['data'] == 'waiting for update':
                    print 'device waiting for update...'
                if dataJson['data'] == 'not waiting for update':
                    print 'device no longer waiting for update.'

Save the code in a file called ‘updatefirmware.py’, and, once you type ‘python updatefirmware.py’ (from the same directory the file is located in, of course), it will print some messages out. When the device is waiting for an update, it will print ‘device waiting for update…’. Then you can head to build.particle.io, and flash your device.

Telemetry Box

Create a new Photon app on build.particle.io, and include the ThingSpeak library in it (make sure it’s the “ThingSpeak” library, and not the “thingspeak” library–note the capitalization). Right now it shows up as the first result from searching for ‘things’. Also include the SPARKFUNMAX17043 and SPARKFUNBME280 libraries. Here is the full code:

language:c
#include "SparkFunBME280/SparkFunBME280.h"
BME280 mySensorA;
float tempF;
float pressure;
float RH;

#include "SparkFunMAX17043/SparkFunMAX17043.h"
// MAX17043 battery manager IC settings
float batteryVoltage;
float batterySOC;
bool batteryAlert;

#include "ThingSpeak/ThingSpeak.h"
//################### update these vars ###################
unsigned long myChannelNumber = your channel number here;  //e.g. 101992
const char * myWriteAPIKey = "your api key here"; // write key here, e.g. ZQV7CRQ8PLKO5QXF
//################### update these vars ###################
TCPClient client;
unsigned long lastMeasureTime = 0;
unsigned long measureInterval = 60000; // can send data to thingspeak every 15s, but give the matlab analysis a chance to add data too

// ultrasonic distance sensor for water height measurement
float uSperInch = 147; // from datasheet
float distance;
unsigned long duration;
float waterHeight;
//################### update these vars ###################
float totalDistance = 64; // the distance from the sensor to the bottom of the water tank
//################### update these vars ###################

// photocell
float lightIntensity;

// connection settings
STARTUP(WiFi.selectAntenna(ANT_EXTERNAL)); // use the u.FL antenna, get rid of this if not using an antenna
float batterySOCmin = 40.0; // minimum battery state of charge needed for short wakeup time
unsigned long wakeUpTimeoutShort = 300; // wake up every 5 mins when battery SOC > batterySOCmin
unsigned long wakeUpTimeoutLong = 900; // wake up every 15 mins during long sleep, when battery is lower
unsigned long connectedTime; // millis() at the time we actually get connected, used to see how long it takes to connect
unsigned long connectionTime; // difference between connectedTime and startTime

// for updating software
bool waitForUpdate = false; // for updating software
unsigned long updateTimeout = 600000; // 10 min timeout for waiting for software update
unsigned long communicationTimeout = 300000; // wait 5 mins before sleeping
unsigned long bootupStartTime;

// for publish and subscribe events
//################### update these vars ###################
String eventPrefix = "your prefix"; // e.g. myFarm/waterSystem
//################### update these vars ###################

bool pumpOn;

void setup() {
    // Set up the MAX17043 LiPo fuel gauge:
    lipo.begin(); // Initialize the MAX17043 LiPo fuel gauge

    // Quick start restarts the MAX17043 in hopes of getting a more accurate
    // guess for the SOC.
    lipo.quickStart();

    // We can set an interrupt to alert when the battery SoC gets too low.
    // We can alert at anywhere between 1% - 32%:
    lipo.setThreshold(20); // Set alert threshold to 20%.
    // use this to measure how long it takes to connect the Photon to the internet if you're in spotty wifi coverage
    pinMode(A0, INPUT); // ultrasonic distance sensor

    // set up BME280 sensor
    mySensorA.settings.commInterface = I2C_MODE;
    mySensorA.settings.I2CAddress = 0x77;
    mySensorA.settings.runMode = 3; //  3, Normal mode
    mySensorA.settings.tStandby = 0; //  0, 0.5ms
    mySensorA.settings.filter = 0; //  0, filter off
    //tempOverSample can be:
    //  0, skipped
    //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
    mySensorA.settings.tempOverSample = 1;
    //pressOverSample can be:
    //  0, skipped
    //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
    mySensorA.settings.pressOverSample = 1;
    //humidOverSample can be:
    //  0, skipped
    //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
    mySensorA.settings.humidOverSample = 1;
    mySensorA.begin();

    ThingSpeak.begin(client);

    Particle.subscribe(eventPrefix, eventHandler);
    Particle.publish(eventPrefix + "/waterTankSensor/online", "true"); // subscribe to this with the API like: curl https://api.particle.io/v1/devices/events/temp?access_token=1234
    bootupStartTime = millis();
    doTelemetry(); // always take the measurements at least once
}

void loop() {
    if (waitForUpdate || millis() - bootupStartTime > communicationTimeout || batterySOC > 75.0 || pumpOn) {
        // The Photon will stay on unless the battery is less than 75% full, or if the pump is running.
        // If the battery is low, it will stay on if we've told it we want to update the firmware, until that times out (updateTimeout)
        // It will stay on no matter what for a time we set, stored in the variable communicationTimeout
        if (millis() - lastMeasureTime > measureInterval) {
            doTelemetry();
        }
            if ((millis() - bootupStartTime) > updateTimeout) {
                waitForUpdate = false;
            }
    } else {
            if (batterySOC < batterySOCmin) {
                System.sleep(SLEEP_MODE_DEEP, wakeUpTimeoutLong);
            } else {
                System.sleep(SLEEP_MODE_DEEP, wakeUpTimeoutShort);
            }
    }
}

void eventHandler(String event, String data)
{
  // to publish update: curl https://api.particle.io/v1/devices/events -d "name=update" -d "data=true" -d "private=true" -d "ttl=60" -d access_token=1234
  if (event == eventPrefix + "/waterTankSensor/update") {
      (data == "true") ? waitForUpdate = true : waitForUpdate = false;
      if (waitForUpdate) {
        Serial.println("wating for update");
        Particle.publish(eventPrefix + "/waterTankSensor/updateConfirm", "waiting for update");
      } else {
        Serial.println("not wating for update");
        Particle.publish(eventPrefix + "/waterTankSensor/updateConfirm", "not waiting for update");
      }
  } else if (event == eventPrefix + "/waterTankPump/pumpOn") {
      (data == "true") ? pumpOn = true : pumpOn = false;
  }
  Serial.print(event);
  Serial.print(", data: ");
  Serial.println(data);
}

void doTelemetry() {
    // let the pump controller know we're still here
    Particle.publish(eventPrefix + "/waterTankSensor/online", "true");

    // water height
    duration = pulseIn(A0, HIGH);
    distance = duration / uSperInch; // in inches
    waterHeight = totalDistance - distance;
    ThingSpeak.setField(1, waterHeight);

    Particle.publish(eventPrefix + "/waterTankSensor/waterHeight", String(waterHeight));

    // BME280
    pressure = mySensorA.readFloatPressure()*29.529983/100000.0;
    ThingSpeak.setField(2, pressure);
    tempF = mySensorA.readTempF();
    ThingSpeak.setField(4, tempF);
    RH = mySensorA.readFloatHumidity();
    ThingSpeak.setField(5, RH);

    // photocell
    lightIntensity = analogRead(A1);
    ThingSpeak.setField(6, lightIntensity);

    // read battery states
    batteryVoltage = lipo.getVoltage();
    ThingSpeak.setField(7, batteryVoltage);
    // lipo.getSOC() returns the estimated state of charge (e.g. 79%)
    batterySOC = lipo.getSOC();
    ThingSpeak.setField(8, batterySOC);
    // lipo.getAlert() returns a 0 or 1 (0=alert not triggered)
    //batteryAlert = lipo.getAlert();

    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
    lastMeasureTime = millis();
}

Variables you should change when you do this:

  • eventPrefix (e.g. myFarm/waterSystem; for publish/subscribe events)
  • myWriteAPIKey (grab from your ThingSpeak telemetry channel)
  • myChannelNumber (from ThingSpeak telemetry channel)
  • totalDistance (the distance from the sensor to the bottom of the water tank

I’ve bracketed these variables with:

language:c
//################### update these vars ###################

so you know what you have to change.

Additionally, you can adjust the batterySOCmin and wakeupTimeout variables if you use a different sized battery.

Control Box

Again, include the ThingSpeak library. Use this code, changing variables where applicable:

language:c
#include "ThingSpeak/ThingSpeak.h"
// channel we're writing to
//################### update these vars ###################
unsigned long myWriteChannelNumber = your channel number; // e.g 101223
const char * myWriteAPIKey = "your write API key for the pump controller channel";
//################### update these vars ###################
TCPClient client;
unsigned long lastMeasureTime = 0;
unsigned long measureInterval = 60000; // can send data to thingspeak every 15s, but once a minute is fine

bool pumpOn = false;
float waterHeight = 1000; // we want to make sure the relay isn't falsely triggered on from the get-go
//################### update these vars ###################
float lowerCutoff = 20; // lowest acceptable water height, in inches
float higherCutoff = 42; // highest acceptable water height, in inches
float totalDistance = 64; // the distance from the sensor to the bottom of the water tank
//################### update these vars ###################
int success;
unsigned long relayStartTime;
unsigned long lastSignal = millis();
unsigned long pumpTimeout = 900000; // turn off the pump if haven't heard from sensor in 15 mins
unsigned long pumpOffTime = 3600000; // make sure we don't turn on the pump more than once per hour
long pumpOffTimeStart = -pumpOffTime; // so we can turn on pump when we startup if we need to

// PIR motion sensor
int relayPin = 0;
int PIRpin = 7;
int PIRval;

// for publish and subscribe events
//################### update these vars ###################
String eventPrefix = "myFarm/waterSystem"; // e.g. myFarm/waterSystem
//################### update these vars ###################

void setup() {
    pinMode(relayPin, OUTPUT);
    pinMode(PIRpin, INPUT_PULLUP);
    digitalWrite(relayPin, LOW);

    Particle.subscribe(eventPrefix, eventHandler);

    ThingSpeak.begin(client);
}

void loop() {
    autoPumpControl();
    checkPIR();
    recordThingSpeakData();
}

int relayControl(String relayState)
{
    if (relayState == "on") {
        pumpOn = true;
        digitalWrite(relayPin, HIGH);
        relayStartTime = millis();
        ThingSpeak.setField(1, 1); // our "pump on" field
        return 1;
    }
    else if (relayState == "off") {
        pumpOn = false;
        digitalWrite(relayPin, LOW);
        ThingSpeak.setField(1, 0); // our "pump on" field
        return 1;
    }
    else {
        return 0;
    }
}

void autoPumpControl() {
    if (pumpOn) {
        if (millis() - lastSignal > pumpTimeout) { // if we haven't heard from the water tanks in a while, turn off the pump
            relayControl("off");
        }
    }
    if (waterHeight < lowerCutoff) {
        success = relayControl("on");
    } else if (waterHeight > higherCutoff) {
        success = relayControl("off");
    } else {
        ThingSpeak.setField(1, boolToNum(pumpOn)); // our "pump on" field
    }
}

void checkPIR() {
    PIRval = digitalRead(PIRpin);
    if(PIRval == LOW){
        ThingSpeak.setField(2, 1); // 1 = motion detected, 0 = no motion
    }
}

void recordThingSpeakData() {
    if (millis() - lastMeasureTime > measureInterval) {
        ThingSpeak.writeFields(myWriteChannelNumber, myWriteAPIKey);
        ThingSpeak.setField(2,0); // reset PIR motion sensor field to 'no motion detected'
        lastMeasureTime = millis();
        Particle.publish(eventPrefix + "/waterTankPump/pumpOn", boolToText(pumpOn));
    }
}

String boolToText(bool thing)
{
    String result;
    thing ? result = "true" : result = "false";
    return result;
}

int boolToNum(bool thing)
{
    int result;
    thing ? result = 1 : result = 0;
    return result;
}

void eventHandler(String event, String data)
{
  if (event == eventPrefix + "/waterTankSensor/online") {
      Particle.publish(eventPrefix + "/waterTankPump/pumpOn", boolToText(pumpOn));
  } else if (event == eventPrefix + "/waterTankSensor/online") {
      (data == "true") ? lastSignal = millis() : Serial.println(data);
  } else if (event == eventPrefix + "/waterTankSensor/waterHeight") {
      waterHeight = data.toFloat();
  }
}

Variables you should change when you do this:

  • eventPrefix (e.g. myFarm/waterSystem; for publish/subscribe events)
  • myWriteAPIKey (grab from your ThingSpeak pump controller channel)
  • myWriteChannelNumber (from ThingSpeak pump controller channel)
  • lowerCutoff (lowest acceptable water height, in inches)
  • higherCutoff (highest acceptable water height, in inches)
  • totalDistance (distance from ultrasonic sensor face to bottom of water tank)

I’ve bracketed these variables with:

language:c
//################### update these vars ###################

so you know what you have to change.

Some of the code may be confusing, especially something like

language:c
thing ? result = 1 : result = 0;

This is shorthand for an if-else statement. It’s the equivalent of

language:c
if (thing) {
    result = 1;
} else {
    result = 0;
}

Default Firmware Feature/Bug

There are a few challenges when working with the Photon and its development environment. One of the biggest problems is that sometimes new firmware versions break old code. For example, from the time I developed this original system (Oct 2015) to the time this tutorial was written (Mar 2016), a new firmware version came out (0.4.9), which is incompatible with my old code. The worst part about it is, the Photon sits there blinking a red error message on the LED and is impossible to flash without physically accessing the device. Kind of a pain when it’s on top of a roof and in a watertight enclosure held together by 6 screws (and there’s a bunch of melting snow everywhere).

I think what ended up being broken with the new firmware was the WiFi.selectAntenna() function, which was silly and tiny. Regardless, we want to disable automatic firmware updates for our devices running important tasks like this, so it can keep running for years. To do this, click the ‘Devices’ icon on the left of build.particle.io, click the star (left) and the arrow (right) next to the device we’re going to flash, then choose the 0.4.9 firmware (without Default). Re-flash your device, and it’s good to go. Do this for both the telemetry and control box Photons.

just say 'no' to default firmware

Leaving the firmware on ‘default’ will auto-upgrade and can break your system. Just say ‘no’ to default firmware, and set it to 0.4.9 for this tutorial’s code.

Setting Up the ThingSpeak Channels

The Telemetry Channel

There are many sites out there for storing your IoT data: SparkFun’s phant.io, dweet.io, and my personal favorite, The Mathworks' ThingSpeak. ThingSpeak already has some nice built-in features, like Google visualization plugins, Twitter interfacing, React (which can do something like post a tweet when data meets a threshhold), MATLAB analysis, and more. It’s also open-source.

First, sign up for a ThingSpeak account if you don’t already have one. Next, create a channel by going to Channels->My Channels->New Channel. Click the checkboxes next to each field (1 through 8) and label them:

  • Water Height (inches)
  • P (inHg)
  • pressure change rate (inHg/min)*106
  • T (F)
  • RH %
  • light intensity
  • battery V
  • battery SOC

Check the box next to ‘Make Public’ if you want other people to be able to view it without needing the read API key. To finish, click ‘Save Channel’.

Now, click “API Keys” in the menu bar that should be around the middle of your screen. Copy the “Write API” key, and put that in your Photon telemetry box code as the myWriteAPIKey variable. Also copy the “Channel ID” number from your ThingSpeak channel page, and set that as the myChannelNumber variable in your Photon telemetry code.

ThingSpeak API key location

Click on ‘API Keys’ and your keys (that you need in your Photon code) should be right there.

Once you power up your telemetry Photon, you should see the data start getting populated (your ThingSpeak page will auto-refresh every 15-ish seconds).

Now, we’ll set up a Twitter feed to post info on our data, which can be used to send alerts on rapidly dropping pressure (which can signal bad weather). Create a Twitter account, sign in, and go back to your ThingSpeak page. Click on “Apps” on the top menu bar. Click “ThingTweet”, and then “Link Twitter Account”.

Once you’ve linked your Twitter account, go back to the ‘Apps’ page and click on MATLAB analysis. Use this code, changing the API keys and channel ID for your channel:

language:MATLAB
% Calcuclates the pressure difference over the last 3 hours
% writes to channel as long as the time difference between
% the two points is at least 2 hours

% Channel ID to read data from
ChannelID = 101982;
% Pressure Field IDs
PressureFieldID = 2;
PressureChangeID = 3;

% TODO - Put your API keys here:
writeAPIKey = 'your write API key';
readAPIKey = 'your read API key'; % this is only necessary if the channel is private

% Get humidity data for the last 60 minutes from the MathWorks Weather
% Station Channel. Learn more about the THINGSPEAKREAD function by going to
% the Documentation tab on the right side pane of this page.

[pressure, timestamps, chInfo] = thingSpeakRead(ChannelID, 'ReadKey', readAPIKey,  'Fields', PressureFieldID, 'NumMinutes', 180);

[m,n]=size(pressure)
display(m)

if m > 1 % we need at least 2 points to do the calculation
    % Calculate the pressure change
    pressureChange = pressure(end)-pressure([1]);
    % pressure(end) gets us the most recent pressure reading, which is last in the pressure variable (a Matlab matrix)
    display(pressureChange, 'pressure change (inHg)'); % this shows up below when you hit run
    timeDiff = minutes(diff([timestamps([1]), timestamps(end)])); % difference in minutes between the first and last readings
    display(timeDiff);
    pressureChangeRate = pressureChange/timeDiff * 1000000;
    display(pressureChangeRate, 'pressure change rate (inHg/min)*10^6');


    % Write the average humidity to another channel specified by the
    % 'writeChannelID' variable

    % Learn more about the THINGSPEAKWRITE function by going to the Documentation tab on
    % the right side pane of this page.
    if timeDiff > 60.0 % make sure the time difference is at least 1 hour between the points
        for n=1:8 % quite a bit of a hack, but it works
            pause(2); % they don't allow more than 2s pauses (delays) here, and I didn't take the time
            % to figure out how to do a callback, etc
        end
        thingSpeakWrite(ChannelID, pressureChangeRate, 'Fields', PressureChangeID, 'writekey', writeAPIKey);
        display('writing to channel')
    end
else
    display('not enough data in channel yet')
end

Make sure to hit ‘save and run’, and you can check the output below the code area to see it working. Scroll down a bit, click “React”, then set up a react to run on new data insertion. The picture below shows the details for the react, which are:

Option nameValue
React namecalculate pressure rate of change
Condition typeNumeric
Test frequencyOn Data Insertion
Condition: If channel(your telemetry channel name)
Conditionfield: 2 (P (inHg)); Is greater than; 0
ActionMATLAB analysis
Code to executeCalculate Pressure Change
OptionsRun each time condition is met

ThingSpeak reacts for pressure drop

Screenshots of the Reacts for pressure drop (bad weather approaching) alerts. I actually ended up having the pressure rate of change test frequency being ‘on data insertion’, and the tweets happen every 60 minutes.

Finally, go back to ‘Apps’ one more time to set up some Twitter alerts. Click on ‘React’ and then ‘New React’. Set the values as shown in the picture above, and the table below:

Option nameValue
React namepressure drop
Condition typeNumeric
Test frequencyOn every 60 minutes
Condition: If channel(your telemetry channel name)
Conditionfield: 3 (pressure change rate (inHg/min*10^6); Is greater than; 984
ActionThingTweet
then tweet#rapid_pressure_drop Pressure dropping %%trigger%% inHg/min*10^6, storm could be on the way.
Using Twitter account(your twitter account here)
OptionsRun each time condition is met

The %%trigger%% is replaced by the value of the field. Hit ‘Save React,’ and you’re good to go.

The Control Box Channel

Set up another ThingSpeak channel, with just two fields set as:

  • pump on
  • motion detected

The API keys from this will be used in the control box Photon code.

ThingSpeak Google Gauges

Another nice feature of ThingSpeak is the ease with which nice looking graphics can be made (once you get the hang of it). For example, a Google Gauge can be embedded in your ThingSpeak channel (or anywhere else with JavaScript). Unfortunately, ThingSpeak recently disabled JavaScript apps from being on public pages, so this will only work on private views or other custom applications.

Google Gauge example

The Google Gauge provides a quick way to take in information.

To get this gauge going for the water tank fullness, go to ThingSpeak.com, click Apps->Plugins->New->Google Gauge->Create, and use this code for the JavaScript:

language:javascript<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'></script><script type='text/javascript' src='https://www.google.com/jsapi'></script><script type='text/javascript'>

  // set your channel id here
  var channel_id = channel ID here; // eg 101992
  // set your channel's read api key here
  var api_key = 'your readAPI key here';
  // maximum value for the gauge
  var max_gauge_value = 42; // this is the maximum water height from your telemetry code
  // name of the gauge
  var gauge_name = 'Water tank level (%)';

  // global variables
  var chart, charts, data;

  // load the google gauge visualization
  google.load('visualization', '1', {packages:['gauge']});
  google.setOnLoadCallback(initChart);

  // display the data
  function displayData(point) {
    data.setValue(0, 0, gauge_name);
    data.setValue(0, 1, point);
    chart.draw(data, options);
  }

  // load the data
  function loadData() {
    // variable for the data point
    var p;

    // get the data from thingspeak
    $.getJSON('https://api.thingspeak.com/channels/' + channel_id + '/feed/last.json?api_key=' + api_key, function(data) {

      // get the data point
      p = data.field1;

      // if there is a data point display it
      if (p) {
        p = Math.round((p / max_gauge_value) * 100);
        displayData(p);
      }

    });
  }

  // initialize the chart
  function initChart() {

    data = new google.visualization.DataTable();
    data.addColumn('string', 'Label');
    data.addColumn('number', 'Value');
    data.addRows(1);

    chart = new google.visualization.Gauge(document.getElementById('gauge_div'));
    options = {width: 200, height: 200, redFrom: 0, redTo: 20, yellowFrom:20, yellowTo: 50, greenFrom: 50, greenTo: 100, minorTicks: 5}; // customize the red, yellow, and green levels if you want

    loadData();

    // load new data every 15 seconds
    setInterval('loadData()', 15000);
  }

</script>

Don’t forget to change the <title> in the HTML section. Then simply click checkboxes on the channels for which you want the Gauge to be visible. You can drag and drop the Gauge (while viewing the channel) to be anywhere on the page.

Setting Up Text Alerts

If you want to get an alert via text or email when the pressure drops rapidly (or for other data events), it can be done with ifttt.com. Head over there and setup an account, and connect your phone to IFTTT. Click ‘My Recipes’ on the top menu, click ‘Create a Recipe’, then click ‘this’. Search for ‘twitter,’ and click on the Twitter icon. Unfortunately, IFTTT’s “tweet from search” feature seems to be broken, hopefully it’s fixed soon. For now, the best we can do is send a text every time we post a new tweet. This unfortunately means we can’t tweet more mundane things right now, since it would be annoying getting that many texts.

ThingSpeak reacts for pressure drop

Click on ‘Create a Recipe’ to get started.

Click ‘New tweet by a specific user’, then enter your username after the “@” symbol, similar to “@JSF_auto_farm”. Next, click ‘that’, search for SMS, and click ‘Send an SMS’. I just left the message as the default. Click ‘Create Action’ and ‘Create Recipe’, and that’s it! If you had to create and link accounts for everything to get to this point, it will be much faster next time you want a text alert for some remote measurement.

When IFTTT does eventually get their Twitter search feature fixed, we can use a hashtag to filter our results. After clicking ‘this’, search for ‘twitter’, then choose ‘New tweet from search’. Use this as the search:

“@your_twitter_username” “#rapid_pressure_drop”

replacing your_twitter_username with the one you picked previously.

Alternate: Use Gmail to Send Texts

For the ‘that’ portion, you can also choose Gmail (you will have to link a Gmail account for this step), and click ‘Send an email’. If you want to send a text, you can do it as so:

1234567890@vtext.com

Instructions for using email to send a text with any carrier can be found here. I was having trouble getting the texts to consistently go through via Gmail with IFTTT, so I switched to the straight IFTTT SMS feature.

There are many other ways to set up SMS alerts, such as Twilio, SendGrid, or IOBridge. None of these methods have been tested with this setup yet.

Final Data Analysis

Here’s some data from field testing:

light values during the day

Full Colorado sunlight is bright.

temperature during the day

The temp inside the box got up to about 95…when it was 60 out. May have to move this into the shade after all. There were also some strange gyrations going on.

battery SOC during the day

The battery never dropped below 40% over one night. I’m also running two ultrasonic sensors, which draws a bit more power.

pressure change during the day

The pressure was dropping in the ‘moderate’ regime this day.

Resources and Going Further

For better system reliability (to keep running during Internet outages) you could run the particle cloud locally (which would require more processing to log data on ThingSpeak), use long-range serial radio transceivers (like this one to communicate directly between the Photons), or eventually, just communicate directly between the photons. Don’t forget you can use long-range antennas like yagi antennas to boost your connection range.

If you want to take this further, you can always:

  • use an Photon Internet button to remote control the pump
  • build an aluminum light-shield (with a hole for the photocell) to keep the box from getting too hot in the summer
  • log the humidity and temperature in the tank using this sensor (or others)
  • log the water temperature with a sensor
  • log water pressure near the pump with a sensor
  • log water flow rates with a flowmeters
  • alerts for too high or low of temperature (ideal charging temperatures are 32-113 F, and the electrolyte in the batteries starts to decompose at about 160 F) – if you’re in the desert, you might want to get a text if the box is getting hot so you can cover it with a wet shadecloth, or permanantly shade the box with aluminum
  • analysis of pump flowrate/water usage using MATLAB processing in ThingSpeak
  • analysis of energy use/pump on time with MATLAB processing
  • analysis of pump hours run, and alerts when it’s time for maintenance or nearing the pump’s end-of-life
  • uptime of photons
  • motion sensor alarms late at night with ThingSpeak reacts
  • web interface for controlling the pump
  • remote control button for pump control
  • remote monitoring in the house, etc (OLED, TFT, WS2812 LEDs) for telemetry data

I’ve already created a simple web form that can be used to remotely control the pump, and switch it between manual and auto mode, but it requires a little more coding of the Photons, and serving a web page. Perhaps in a future tutorial I’ll show you how to do these things.

Again, all the code for this project can be found on GitHub.

Photon Remote Water Level Sensor Code

For more Photon fun, check out these other great SparkFun tutorials:

SparkFun Inventor's Kit for Photon Experiment Guide

Dive into the world of the Internet of Things with the SparkFun Inventor's Kit for Photon.

Photon IMU Shield Hookup Guide

Learn how to use the SparkFun Photon IMU Shield for your Photon device which houses an on-board LSM9DS1 system-in-a-chip that houses a 3-axis accelerometer, 3-axis gyroscope, and 3-axis magnetometer.

Photon Weather Shield Hookup Guide

Create Internet-connected weather projects with the SparkFun Weather Shield for the Photon.

Photon Remote Temperature Sensor

Learn how to build your own Internet-connect, solar-powered temperature collection station using the Photon from Particle.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

ASCII

$
0
0

ASCII a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t539

Introduction

If computers operate in binary, then how are we able to store letters and words? To do this, we assign numbers to characters. This is known as character encoding.

Example of ASCII encoding

Looking at the internals of a simple text document

To understand how character encoding works, let’s create a simple example. First, assign the numbers 1-26 to the English alphabet:

1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z

To write a simple encoded message, we substitute the numbers for the letters. For example, 8 5 12 12 15. By using numbers, we have constructed the word h e l l o.

But to completely capture the English alphabet – including upper and lower-case letters, numbers, and punctuation – we needed more than 26 characters. As a result, the American Standard Code for Information Interchange (ASCII) was created as one of the first character encoding standards for computers.

What You Will Learn

The following topics will be covered in this tutorial:

  • A brief history of ASCII
  • How to translate decimal, binary, and hexadecimal numbers to ASCII

Suggested Reading

There are a few concepts that you might want to be familiar with before starting to read this guide:

  • Binary - Knowing how a computer stores numbers is useful to translating those numbers to characters.
  • Hexadecimal - Hexadecimal is often used to express binary numbers in groups of 4 bits.
  • Installing Arduino IDE - Arduino is a good way to try printing ASCII characters.

History

The American Standards Association (ASA), now the American National Standards Institute (ANSI), began work on ASCII on October 6, 1960. The encoding scheme had origins in the 5-bit telegraph codes invented by Émile Baudot. The committee eventually decided on a 7-bit code for ASCII.

7 bits allow for 128 characters. While only American English characters and symbols were chosen for this encoding set, 7 bits meant minimized costs associated with transmitting this data (as opposed to say, 8 bits).

The first 32 characters of ASCII were reserved control characters. These characters were used to relay special instructions to other devices, like printers. For example, a user could advance a line, delete a character, and on some devices, ring a bell (such as on the Teletype Model 33 ASR).

ASA published the first version of ASCII in 1963 and revised it in 1967. The last major update to the standard occurred in 1986. ASCII first saw commercial use in the American Telephone & Telegraph (AT&T) TeletypeWriter Exchange (TWX) network.

Teletype Model 33 ASR

Teleprinters, like this Teletype Model 33 ASR, were used to send typed messages to one or more other teleprinters across various communication channels (Image courtesy of Arnold Reinhold of Wikimedia Commons)

On March 11, 1968 President Lyndon B. Johnson mandated that all US federal government computers must support ASCII, thus cementing ASCII’s place in American computing history.

Other encoding schemes existed at the time, such as the International Telegraph Alphabet No. 2 (ITA2), but ASCII quickly became the standard for American English encoding. ASCII was the most common encoding found on the Internet until it was surpassed by UTF-8 in 2007.

ASCII Table

To identify a character’s ASCII value, it is common to look it up on an ASCII table. The ASCII table pairs each character to its assigned value between 0 and 127.

Control Characters

Control characters make up the first 32 characters of the ASCII table. These characters are not intended to be printed, instead they are used to send command instructions to another device, such as a printer. Note that we have included the octal representation of the ASCII characters in the off chance that you might be working with a particularly old system (such as the 12-bit PDP-8).

DecBinOctHexCharDescription
00000 000000000NULnull
10000 000100101SOHstart of heading
20000 001000202STXstart of text
30000 001100303ETXend of text
40000 010000404EOTend of transmission
50000 010100505ENQenquiry
60000 011000606ACKacknowledge
70000 011100707BELbell
80000 100001008BSbackspace
90000 100101109TABhorizontal tab
100000 10100120ALFline feed, new line
110000 10110130BVTvertical tab
120000 11000140CFFform feed, new page
130000 11010150DCRcarriage return
140000 11100160ESOshift out
150000 11110170FSIshift in
160001 000002010DLEdata link escape
170001 000102111DC1device control 1
180001 001002212DC2device control 2
190001 001102313DC3device control 3
200001 010002414DC4device control 4
210001 010102515NAKnegative acknowledge
220001 011002616SYNsynchronous idle
230001 011102717ETBend of transmission block
240001 100003018CANcancel
250001 100103119EMend of medium
260001 10100321ASUBsubstitute
270001 10110331BESCescape
280001 11000341CFSfile separator
290001 11010351DGSgroup separator
300001 11100361ERSrecord separator
310001 11110371FUSunit separator
1270111 11111777FDELdelete

Printable Characters

There are 95 printable characters in the ASCII encoding scheme. Note that the “space” character denotes a printable space (“ ”).

DecBinOctHexChar
320010 000004020space
330010 000104121!
340010 001004222"
350010 001104323#
360010 010004424$
370010 010104525%
380010 011004626&
390010 011104727'
400010 100005028(
410010 100105129)
420010 10100522A*
430010 10110532B+
440010 11000542C,
450010 11010552D-
460010 11100562E.
470010 11110572F/
480011 0000060300
490011 0001061311
500011 0010062322
510011 0011063333
520011 0100064344
530011 0101065355
540011 0110066366
550011 0111067377
560011 1000070388
570011 1001071399
580011 10100723A:
590011 10110733B;
600011 11000743C<
610011 11010753D=
620011 11100763E>
630011 11110773F?
DecBinOctHexChar
640100 000010040@
650100 000110141A
660100 001010242B
670100 001110343C
680100 010010444D
690100 010110545E
700100 011010646F
710100 011110747G
720100 100011048H
730100 100111149I
740100 10101124AJ
750100 10111134BK
760100 11001144CL
770100 11011154DM
780100 11101164EN
790100 11111174FO
800101 000012050P
810101 000112151Q
820101 001012252R
830101 001112353S
840101 010012454T
850101 010112555U
860101 011012656V
870101 011112757W
880101 100013058X
890101 100113159Y
900101 10101325AZ
910101 10111335B[
920101 11001345C\
930101 11011355D]
940101 11101365E^
950101 11111375F_
DecBinOctHexChar
960110 000014060`
970110 000114161a
980110 001014262b
990110 001114363c
1000110 010014464d
1010110 010114565e
1020110 011014666f
1030110 011114767g
1040110 100015068h
1050110 100115169i
1060110 10101526Aj
1070110 10111536Bk
1080110 11001546Cl
1090110 11011556Dm
1100110 11101566En
1110110 11111576Fo
1120111 000016070p
1130111 000116171q
1140111 001016272r
1150111 001116373s
1160111 010016474t
1170111 010116575u
1180111 011016676v
1190111 011116777w
1200111 100017078x
1210111 100117179y
1220111 10101727Az
1230111 10111737B{
1240111 11001747C|
1250111 11011757D}
1260111 11101767E~

Try It

If you would like to try printing something using ASCII encoding, you can try it out using Arduino. See this tutorial for getting started with Arduino.

Open the Arduino IDE and paste in the following code:

language:c
void setup()
{
  Serial.begin(9600);
}

void loop()
{
  Serial.write(0x48); // H
  Serial.write(0x65); // e
  Serial.write(0x6C); // l
  Serial.write(0x6C); // l
  Serial.write(0x6F); // o
  Serial.write(0x21); // !
  Serial.write(0x0A); // \n

  delay(1000);
}

Run it on your Arduino, and open a Serial console. You should see the “Hello!” appear over and over:

Arduino saying Hello!

Notice that we had to use Serial.write() instead of Serial.print(). The write() command sends a raw byte across the serial line. print(), on the other hand, will try and interpret the number and send the ASCII-encoded version of that number. For example, Serial.print(0x48) would print 72 in the console.

Also, notice that we used the ASCII character 0x0A, which is the “line feed” control character. This causes the printer (or console in this case) to advance to the next line. It is similar to pressing the ‘enter’ key.

Resources and Going Further

There are many character encoding sets available. The most popular encoding for the World Wide Web is UTF-8. As of June 2016, UTF-8 is used in 87% of all web pages.

UTF-8 is backwards compatible with ASCII, which means the first 128 characters are the same as ASCII. UTF-8 can use 2, 3, and 4 bytes to encode characters from most modern written languages, including Latin, Greek, Cyrillic, Arabic, Chinese, Korean, and Japanese characters.

Knowledge of basic ASCII encoding can be useful when working in serial terminals. See the Serial Terminal Basics to learn how to use some of the many serial terminal programs available.

If you are interested in downloading the ASCII table in image format, click the button below. With an image, you can print it out and hang it on your wall, put it on a coffee mug, or have it printed on a mouse pad.

ASCII Table Images


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Hazardous Gas Monitor

$
0
0

Hazardous Gas Monitor a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t531

Introduction

Hazardous Gas Monitor

Build a portable gas monitor to check for dangerous levels of hazardous gases in your home, community, or on the go and prevent your friends from lighting a cigarette during a gasoline fight.*

This tutorial shows you how to build a web-connected “canary” monitor for three hazardous gases: Liquid Propane Gas (“LPG”), Methane (aka natural gas), and Carbon Monoxide (“CO”). Using the Particle Photon microcontroller, the sensor readings are converted into parts-per-million (“PPM”) and uploaded to the data.sparkfun.com web service.

*Please note that this is solely a movie reference – gasoline fights should probably be avoided in real life.

Check out the video below to see the Hazardous Gas Monitor in action:

Helpful Background Info

  1. How to set up the Particle Photon.
  2. Pushing data to the data.sparkfun.com web server.
  3. New to relays? Check out this a handy reference.
  4. Here’s a helpful overview on the N-Channel MOSFET.
  5. For powering the Photon, here’s a thorough guide on the Photon Battery Shield.
  6. Highly recommended to peruse the datasheets for the three gas sensors.
    1. LPG sensor datasheet
    2. Methane sensor datasheet
    3. CO sensor datasheet

Choosing a Battery

The gas sensors used in this project require a fair amount of current, about 0.17 mA each at 5V. To make the system portable, we’ll need a high capacity battery. One easy, and affordable, option is to use four (rechargeable) AA batteries in series. These batteries will last about 4 hours.

Another option is to use a lithium ion battery (“LIB”). LIBs have a higher capacity than AAs, but typically run at a lower voltage. If you go with this option, you may need to include a correction factor when you calculate the sensor value or boost the battery voltage with a transistor or other component.

Here’s a table that shows the approximate lifetime of a few different battery options.

Table2_BatteryCap3Sensors

If all of this sounds confusing, here’s a more thorough tutorial.

Materials

alt text

Microcontroller and Accessory Components

Gas Sensor Circuit

LPG (MQ6) Gas Sensor
Methane (MQ4) Gas Sensor
Carbon Monoxide (MQ7) Gas Sensor

Tools

  • Soldering Iron
  • Wire cutters/strippers
  • Drill
  • Screwdriver
  • Epoxy (or hot glue)

Build It

wiring diagram

Click the image for a closer look.

  1. Solder gas sensor breakout boards to gas sensors. Orientation doesn’t matter, just be sure that the silkscreen (aka labels) are facing down so that you can read them (had to learn that one the hard way..). Solder wires to the gas sensor breakout board.

    breakout
  2. Solder three voltage regulators to the PCB board. For each regulator, connect positive battery output to the regulator input, and connect middle voltage regulator pin to ground.

    VREG
  3. Connect the LPG (MQ6) and Methane (MQ4) sensors.

    MQ6, MQ4

    For each sensor:

    1. Connect H1 and A1 to the output of one of the voltage regulators (recommended to use an electrical connector).
    2. Connect GND to ground.
    3. Connect B1 to Photon analog pin (LPG goes to A0, Methane to A1)
    4. Connect a 4.7 kΩ resistor from B1 to ground.

    alt text
  4. Connect the CO (MQ7) gas sensor.

    alt text

    Aside: The MQ7 sensor requires cycling the heater voltage (H1) between 1.5V (for 90s) and 5V (for 60s). One way to do this is to use a relay triggered by the Photon (with the aid of a MOSFET and potentiometer) – when the relay is not powered, the voltage across H1 is 5V, and when the relay is powered the voltage across H1 is ~ 1.5V.

    1. Connect GND to ground.
    2. Connect B1 to Photon analog pin (A2). Connect 4.7 kΩ resistor from B1 to ground.
    3. Connect A1 to third voltage regulator output (5V source).
    4. Connect Photon 3.3V pin to positive relay input.
    5. Connect Photon Digital Pin D7 to left MOSFET pin, and a 10 kΩ resistor to ground.
    6. Connect middle MOSFET pin to relay ground pin. Connect right MOSFET pin to ground.
    7. Connect relay Normally Open (“NO”) pin to H1, and the Normally Closed (“NC”) pin to middle potentiometer pin.
    8. Connect right potentiometer pin to ground, and left pin to H1.
    9. Adjust potentiometer resistance until it changes the relay output to ~ 1.5V when the relay receives power.
  5. Connect an LED and 10 kΩ resistor to each of the Photon digital pins D0, D1, and D2. Connect buzzer to Photon digital pin D4.

    alt text
  6. Connect toggle switch between battery pack and PCB board power. Recommended to include an electrical connector for the battery pack to make it easier to switch out batteries.

    alt text
  7. Solder wires to Photon Battery Shield breakout.

    alt text
  8. Connect lamp switch between LIB and Photon battery shield – recommended to use an extra JST cable for this to keep the LIB battery cable in tact (and make it easier to install the lamp switch).

  9. Build a case for the electronics!

    alt text
    1. Drill hole for toggle switch on case lid.
    2. Drill 3 holes in the case lid for the LED lights to shine through, and 3 holes for the gas sensors to have air contact. Adhere components on the inside of the lid.

      alt text
    3. Drill hole in the side of the case for barrel jack USB cord to connect to the Photon Battery Shield.

      alt text
    4. Drill two small holes on the side of the case for the lamp switch cable. Adhere lamp switch to side of case.

    5. Label the LEDs with its corresponding gas sensor on the outside of the case.

    alt text
  10. Check electrical connections and, if everything is good to go, coat electrical connections in epoxy or hot glue.

[![alt text](https://cdn.sparkfun.com/r/600-600/assets/learn_tutorials/5/3/1/FinalSystem2.jpg)](https://cdn.sparkfun.com/assets/learn_tutorials/5/3/1/FinalSystem2.jpg)

Calculate Gas Sensor PPM

Each of the gas sensors outputs an analog value from 0 to 4095. To convert this value into voltage, use the following equation:

Sensor Voltage = AnalogReading * 3.3V / 4095

Once you have the sensor voltage, you can convert that into a parts per million (“PPM”) reading using the sensitivity calibration curve on page 5 of the gas sensor datasheets. To do this, recreate the sensitivity curve by picking data points from the graph or using a graphical analysis software like Engauge Digitizer.

Plot PPM on the y-axis and V_RL on the x-axis, where V_RL is the sensor voltage. There is a lot of room for error with this method, but it will give us enough accuracy to identify dangerous levels of hazardous gases. Estimated error bars are around 20 PPM for the LPG and Methane sensors, and about 5 PPM for the CO sensor.

MQ7_SensitivityPlot_CurvePoints

Next, find an approximate equation for the PPM vs. V_RL curve. I used an exponential fit (e.g. y = ex) and got the following equations:

LPG sensor: PPM = 26.572*e^(1.2894*V_RL)

Methane sensor: PPM = 10.938*e(1.7742*V_RL)

CO sensor: PPM = 3.027*e^(1.0698*V_RL)

Program It

First, set up a data stream on the data.sparkfun.com service. Next, write a program to read in the analog value of each gas sensor, convert it to PPM, and check it against known safe thresholds. Based on OSHA safety standards, the thresholds for the three gases are as follows:

  • LPG: 1,000 PPM
  • Methane: 1,000 PPM
  • CO: 50 PPM

If you want to get up and running quickly, or are new to programming, feel free to use my code! Use it as-is or modify to suit your particular needs.

language:c
// This #include statement was automatically added by the Particle IDE.
//This library is used to push data to the data.sparkfun.com server.
#include "SparkFunPhant/SparkFunPhant.h"
#include "math.h"

//This code was written by Jennifer Fox <jenfoxbot@gmail.com>
/*
 * ----------------------------------------------------------------------------
 * "THE Coffee-WARE LICENSE" (Revision 42):
 * <jenfoxbot@gmail.com>  wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a coffee in return.
 * ----------------------------------------------------------------------------
 */

//Variables to push data to data.sparkfun.com host -- Change publicKey[] and privateKey[]
const char server[] = "data.sparkfun.com"; // Phant destination server
const char publicKey[] = "INSERT_PUBLIC_KEY_HERE"; // Phant public key
const char privateKey[] = "INSERT_PRIVATE_KEY_HERE"; // Phant private key

Phant phant(server, publicKey, privateKey); // Create a Phant object

const unsigned long postingRate = 20000; //Post rate to data.sparkfun.com (time in milliseconds)
unsigned long lastPost = millis(); //Keeps track of posting rate


//Define analog pins on Photon to use for sensors
const int LPG = A0;
const int NG = A1;
const int CO = A2;

//Define digital pins on Photon to use for LEDs,  buzzer, and MQ7 (CO sensor) heater
const int LPGled = D0;
const int NGled = D1;
const int COled = D2;
const int buzzer = D3;
const int CORelayPin = D6;
const int COVoltPin = D7;

//Set up raw signal and PPM variables for each gas sensor
int LPGRaw;
int NGRaw;
int CORaw;

int LPGppm;
int NGppm;
int COppm;

//Set safety threshold levels for each  hazardous gas
const int  LPGthresh = 1000;
const int NGthresh = 1000;
const int COthresh = 50;


//Set variables for CO sensor (MQ7) voltage cycle
unsigned long startMillis;
unsigned long switchTimeMillis;
const int CO_5V_Interval = 60000; //60s for 5V interval
const int CO_1_5V_Interval = 90000; //90s for 1.5V interval
bool heaterInHighPhase;

void setup() {
    Serial.begin(9600);

    //Initialize LED and buzzer output pins
    pinMode(LPGled, OUTPUT);
    pinMode(NGled, OUTPUT);
    pinMode(COled, OUTPUT);
    pinMode(buzzer, OUTPUT);

    //Initialize CO sensor heater pins
    pinMode(CORelayPin, OUTPUT);
    pinMode(COVoltPin, OUTPUT);

    //Set start time (for CO sensor heater voltage)
    startMillis = millis();
    turnHeaterHigh();
}

void loop() {
    //Cycle CO sensor (MQ7) heater voltage

    if(heaterInHighPhase){
    // 5V phase - check to switch
        if(millis() > switchTimeMillis) {
        turnHeaterLow();
        }
    }
    else {
    // 1.4V phase - check to switch
        if(millis() > switchTimeMillis) {
        turnHeaterHigh();
        }
    }


    //Read in analog value from each gas sensor -- use function defined below to measure CO sensor at end of voltage cycle
    LPGRaw = analogRead(LPG);
    NGRaw = analogRead(NG);
    CORaw = measureCOSensor();

    //Caclulate the PPM of each gas sensor using the funtions defined below
    LPGppm = LPG_ppm(LPGRaw);
    NGppm = NG_ppm(NGRaw);
    COppm = CO_ppm(CORaw);

    //Serial monitor print for debugging and checking data
    Serial.println(NGRaw);
    Serial.println(NGppm);
    delay(1000);

    //Check gas sensor measurements against safety thresholds
    checkThreshold(LPGppm, NGppm, COppm);

    //Wait to post until ~ 20s has lapsed
    if (lastPost + postingRate < millis()) {
        Serial.println("Reading!");

        postToPhant(LPGppm, NGppm, COppm); //Post gas sensor readings and unit (PPM) to your data stream at data.sparkfun.com

        lastPost = millis();
    }

}

//Functions to calculate PPM from Photon analog reading
//Each equation is determined by visually picking points, plotting PPM v. V_RL, then fitting a trendline to the curve (exponential)
//Calculate LPG PPM
int LPG_ppm(double rawValue){

    double ppm = 26.572*exp(1.2894*(rawValue*3.3/4095)); //Multiply raw analog value by 3.3/4095 to convert to a voltage
    return ppm;
}

//Calculate NG PPM
int NG_ppm(double rawValue){

    double ppm = 10.938*exp(1.7742*(rawValue*3.3/4095));
    return ppm;
}

//Calculate CO PPM
int CO_ppm(double rawValue){

    double ppm = 3.027*exp(1.0698*(rawValue*3.3/4095));
    return ppm;
}


//Function to check PPM reading with maximum safe PPM threshold
//Include a margin of error (currently 10%)
void checkThreshold(int lpgppm, int ngppm, int coppm){
    int led1;
    int led2;
    int led3;

    if (lpgppm >= LPGthresh*0.9){
        digitalWrite(LPGled, HIGH);
        led1 = TRUE;
    }
    else{
        digitalWrite(LPGled, LOW);
        led1 = FALSE;
    }

    if (ngppm >= NGthresh*0.9){
        digitalWrite(D1, HIGH);
        led2 = TRUE;
    }
    else{
        digitalWrite(NGled, LOW);
        led2 = FALSE;
    }

    if (coppm >= COthresh*0.9){
        digitalWrite(D2, HIGH);
        led3 = TRUE;
    }
      else{
        digitalWrite(COled, LOW);
        led3 = FALSE;
    }

    if(led1 | led2 | led3){
        digitalWrite(buzzer, HIGH);
    }

    else{digitalWrite(buzzer, LOW);}


}

//Functions to switch heater voltage on MQ7 (CO) sensor
void turnHeaterHigh(){
  // 5v phase
  digitalWrite(COVoltPin, LOW);
  digitalWrite(CORelayPin, HIGH);

  heaterInHighPhase = true;
  switchTimeMillis = millis() + CO_5V_Interval;
}

void turnHeaterLow(){
  // 1.4v phase
  digitalWrite(COVoltPin, HIGH);
  digitalWrite(CORelayPin, LOW);

  heaterInHighPhase = false;
  switchTimeMillis = millis() + CO_1_5V_Interval;
}

//Function to read CO sensor voltage (just before switching to 1.5V)
int measureCOSensor(){
  unsigned int gasLevel = analogRead(CO);
  unsigned int time = (millis() - startMillis) / 1000;
  delay(time);

  return gasLevel;
}



//Function to post data to data.sparkfun.com host
//Many thanks to Jim Lindblom <jim@sparkfun.com> for the sample code and Phant library.
int postToPhant(int lpg, int ng, int co){

    phant.add("lpg", lpg); //Data stream field name "sensorvalue1"
    phant.add("ng", ng); //Data stream field name "sensorvalue2"
    phant.add("co", co); //Data stream field name "sensorvalue3"

    TCPClient client;
    char response[512];
    int i = 0;
    int retVal = 0;

    if (client.connect(server, 80)) // Connect to the server
    {
        // Post message to indicate connect success
        Serial.println("Posting!");

        // phant.post() will return a string formatted as an HTTP POST.
        // It'll include all of the field/data values we added before.
        // Use client.print() to send that string to the server.
        client.print(phant.post());
        delay(1000);
        // Now we'll do some simple checking to see what (if any) response
        // the server gives us.
        while (client.available())
        {
            char c = client.read();
            Serial.print(c);    // Print the response for debugging help.
            if (i < 512)
                response[i++] = c; // Add character to response string
        }
        // Search the response string for "200 OK", if that's found the post
        // succeeded.
        if (strstr(response, "200 OK"))
        {
            Serial.println("Post success!");
            retVal = 1;
        }
        else if (strstr(response, "400 Bad Request"))
        {   // "400 Bad Request" means the Phant POST was formatted incorrectly.
            // This most commonly ocurrs because a field is either missing,
            // duplicated, or misspelled.
            Serial.println("Bad request");
            retVal = -1;
        }
        else
        {
            // Otherwise we got a response we weren't looking for.
            retVal = -2;
        }
    }
    else
    {   // If the connection failed, print a message:
        Serial.println("connection failed");
        retVal = -3;
    }
    client.stop();  // Close the connection to server.
    return retVal;  // Return error (or success) code.
}

Change the following in the code:

  1. Copy and paste your data stream public key to the array called publicKey[].

    const char publicKey[] = "INSERT_PUBLIC_KEY_HERE";

2.Copy and paste your data stream private key to the array called privateKey[].

`const char privateKey[] = "INSERT_PRIVATE_KEY_HERE";`

To monitor the Photon output, use the Particle driver downloaded as described in the “Connecting Your Device” Photon tutorial. Once this is installed, in the command prompt, type particle serial monitor. This is super helpful for debugging and checking that the Photon is posting data to the web.

Be a Citizen Scientist

FinalMonitor_Outside

Now we get to test and employ our gas monitor! Turn the batteries for the gas sensors on using the toggle switch, wait about 3 - 5 minutes, then turn the Photon on with the lamp switch (the gas sensor heater coils take some time to heat up). Check that the Photon is connected to WiFi (on-board LED will slowly pulse light blue) and is uploading data to the server. Also check that the gas sensor readings increase when in proximity to hazardous gases – one easy, and safe, way is to hold a lighter and/or a match close to the sensors.

Once up and running, use the sensor to monitor for dangerous gas leaks around your home, school, workplace, neighborhood, etc. You can install the sensor in one location permanently, or use it to check gas levels in different locations (e.g. SoCal..).

Educator Extension!

This project is a perfect excuse for a hands-on chemistry lesson! Use the monitor to learn the fundamentals of various gases – what kinds of gases are in our environment, how are different gases produced, and what makes some of them hazardous or dangerous.

Study the local environment and use a lil' math to record and plot LPG, Methane, and CO in specific locations over time to see how the levels change. Use the data to help determine what causes changes in the gas levels and where/when gas concentrations are the highest.

Resources & Going Further

Monitor hazardous gas concentrations around your neighborhood or city and use the results to identify problem areas and improve public safety.

Use Bluetooth, or your smartphone WiFi, to connect to the Photon and upload data to the web wherever you are!

Include other sensors, gaseous or otherwise, to create a more comprehensive environmental monitoring system.


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Electret Mic Breakout Board Hookup Guide

$
0
0

Electret Mic Breakout Board Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t485

Introduction

Ready to add audio to your next project? The SparkFun Electret Microphone Breakout couples an Electret microphone (100Hz - 10kHz) with a 60x mic preamplifier to amplify the sounds of voice, claps, door knocks or any sounds loud enough to be picked up by a microcontroller’s analog to digital converter.

Electret Mic

All in one tiny package!

The Electret Mic Breakout translates amplitude (not volume) by capturing sound waves between two conducting plates (one a vibrating diaphragm and the other fixed) in the microphone and converting them into electrical waves. These electrical signals are then amplified and picked up by your microcontroller’s ADC. In this tutorial, we will present two different projects to get you up and running with your next sound reactive project in a snap or a clap.

Materials Required

For this tutorial you will only need a few tools and components.

SparkFun RedBoard - Programmed with Arduino

DEV-12757
$19.95
97
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
Break Away Headers - Straight

PRT-00116
$1.5
20
Jumper Wires Premium 6" M/M Pack of 10

PRT-08431
$3.95
2

Recommended Reading

If you are not familiar or comfortable with the following concepts, we recommend reading through these before continuing on with the Electret Mic BOB Hookup Guide.

Hardware Overview

Hardware

The Electret Mic Breakout Board only has three pins: VCC, GND and AUD. You can power this device from 3.3V to 5V, so it is a great compliment to most microcontroller units. For the amplification, we used Texas Instruments OPA344 rail-to-rail precision amplifier to give you maximum output swing.

back of board

Schematic

The gain of the amplifier is set by R5/R4 which is approximately 82V/V. Simulation and testing puts the gain closer to 60V/V.

alt text

Click the image for a closer look.

Frequency Response

alt text

Click the image for a closer look.

What this tells you is that you will see the same gain across the frequency spectrum that is picked up by the mic (100Hz-10KHz). The input of the amplifier is biased at ½ VCC. The very small AC voltage output by the mic rides on the DC offset and gets amplified through the OPA344. The output from the “AUD” pin is also at ½ the supply voltage, so it can be connected directly to the ADC of microcontroller. In quiet conditions, the ADC will ideally read ½ the full scale or 512 on a 10-bit converter.

Example Circuit and Code

We are going to run through a very simple project to get you started lighting an LED on the RedBoard based on the ADC values picked up by your microcontroller.

This is the Knocker. An LED will light up when a knock is detected.

alt text

alt text

Make the Following Connections

Electret Mic BOB → RedBoard

  • VCC → 5V
  • GND → GND
  • AUD → A0 (or any analog pin)
  • LED+ → 330 ohm resistor → digital Pin 9
  • LED- → GND

alt text

Open the Arduino IDE and create a new project.

language:c
 /*
 * The Circuit:
 * Connect AUD to analog input 0
 * Connect GND to GND
 * Connect VCC to 3.3V (3.3V yields the best results)
 *
 *  To adjust when the LED turns on based on audio input:
 *  Open up the serial com port (Top right hand corner of the Arduino IDE)
 *  It looks like a magnifying glass. Perform several experiments
 *  clapping, snapping, blowing, door slamming, knocking etc and see where the
 *  resting noise level is and where the loud noises are. Adjust the if statement
 *  according to your findings.
 *
 *  You can also adjust how long you take samples for by updating the "SampleWindow"
 *
 * This code has been adapted from the
 * Example Sound Level Sketch for the
 * Adafruit Microphone Amplifier
 *
 */

const int sampleWindow = 250; // Sample window width in mS (250 mS = 4Hz)
unsigned int knock;
int ledPin = 9;

void setup()
{
   Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop()
{
 unsigned long start= millis();  // Start of sample window
 unsigned int peakToPeak = 0;   // peak-to-peak level

 unsigned int signalMax = 0;
 unsigned int signalMin = 1024;

 // collect data for 250 miliseconds
 while (millis() - start < sampleWindow)
 {
   knock = analogRead(0);
      if (knock < 1024)  //This is the max of the 10-bit ADC so this loop will include all readings
      {
         if (knock > signalMax)
         {
           signalMax = knock;  // save just the max levels
         }
      else if (knock < signalMin)
        {
         signalMin = knock;  // save just the min levels
         }
     }
 }
 peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
 double volts = (peakToPeak * 3.3) / 1024;  // convert to volts


Serial.println(volts);
 if (volts >=1.0)
 {
  //turn on LED
  digitalWrite(ledPin, HIGH);
   delay(500);
  Serial.println("Knock Knock");
 }
 else
 {
 //turn LED off
 digitalWrite(ledPin, LOW);
 }
}

Once you have loaded and run the program with your hardware hooked up, you should the LED attached to pin 9 on the RedBoard light up when you knock. Check out the WindBag Alert that uses the same code with just a few additional lines for an additional practice and project inspiration.

The Windbag Alert

Do you have a co-worker that talks too much? Do you want to alert that long-talker in your life of their offenses with the least unassuming desk ornament? Do you like literal translations of bad expressions? Then make yourself a Windbag Alert. This rude little piece of hardware will inflate a bag (one of my doggy doop-doop bags) with the air of your stolen silence.

alt text

Here the bag is deflated but the Electret Mic is listening. If ADC values are above a certain threshold for too long the bag will begin to inflate.

alt text

Here, someone has been talking for about 30 seconds. They have just a few seconds before the bag fully inflates. The fan kicking on usually stops them dead in their tracks.

alt text

But, some people, those people, don’t care. And the bag completely inflates. Alerting that person they are indeed the office Windbag.

Let’s break this thing down. This project is simply a continuation for the LED Blinking project from the previous section.

Hardware

I used a 12V computer fan, because that’s what I had laying around. You can use any fan, even disassemble a hand held cooling fan found at dollar stores. That should eliminate the need for a higher power supply and the fan (+) would be attached to 5V and the source (Emitter) of the transistor would be connected to GND on the Arduino.

alt text

I used an old SparkFun box as my project enclosure, which sits on my power supply on my workbench. I wrapped a plastic bag around the computer fan using electrical tape. There is about ½" of space between the box top and fan. I used standoffs there. Make sure there is enough air flow.

Software

language:c
const int sampleWindow = 250; // Sample window width in mS (250 mS = 4Hz)
unsigned int sample;
int Wind = 9;

void setup()
{
  Serial.begin(9600);
  pinMode(Wind, OUTPUT);
}

void loop()
{
unsigned long startMillis= millis();  // Start of sample window
unsigned int peakToPeak = 0;   // peak-to-peak level

unsigned int signalMax = 0;
unsigned int signalMin = 1024;

// collect data for 1 second
while (millis() - startMillis < sampleWindow)
{
      sample = analogRead(0);
    if (sample < 1024)  //This is the max of the 10-bit ADC so this loop will include all readings
    {
         if (sample > signalMax)
        {
            signalMax = sample;  // save just the max levels
         }
         else if (sample < signalMin)
         {
            signalMin = sample;  // save just the min levels
         }
      }
   }
  peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
 double volts = (peakToPeak * 3.3) / 1024;  // convert to volts


Serial.println(volts);
if (volts >=0.5)
{
    //turn on FAN
    digitalWrite(Wind, HIGH);
delay(1000);
  digitalWrite(Wind, LOW);
delay(75);
  digitalWrite(Wind, HIGH);
delay(75);
  digitalWrite(Wind, LOW);
delay(75);
  digitalWrite(Wind, HIGH);
delay(75);
  digitalWrite(Wind, LOW);
delay(75);
  digitalWrite(Wind, HIGH);
delay(75);
   }
  else
  {
  //turn FAN off
 digitalWrite(Wind, LOW);
 }
}

I suggest playing with the delays so you can finely tune your machine to suit your needs.

Resources and Going Further

A quick Google search for “Electret Mic Breakout” will get you going for any type of project you may want to create. Here are a few of my favorites from Instructables.

If you need to add sound to your next project but need something a little more sensitive, robust or a little more useful, I recommend the SparkFun Sound Detector.

Documents

For more audio fun, check out these other great SparkFun tutorials:

Build an Auduino Step Sequencer

Make a Step Sequencer using an Arduino, the Auduino firmware, and a handful of hardware.

WAV Trigger Hookup Guide V11

An introduction to being able to trigger music and sound effects based on buttons, sensors, or switches using the WAV Trigger board.

MIDI Tutorial

Understanding the Musical Instrument Digital Interface.

MIDI Shield Hookup Guide

How to assemble the SparkFun MIDI Shield, plus several example projects.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Battery Babysitter Hookup Guide

$
0
0

Battery Babysitter Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t530

Introduction

The SparkFun Battery Babysitter is an all-in-one single-cell lithium polymer (LiPo) battery manager. It’s half battery-charger, half battery monitor, and it’s all you’ll ever need to keep your battery-powered project running safely and extensively.

SparkFun Battery Babysitter - LiPo Battery Manager

PRT-13777
$19.95

The Battery Babysitter features a pair of Texas Instruments LiPo-management IC’s: a BQ24075 battery charger and a BQ27441-G1A fuel gauge. The BQ24075 supports adjustable charge rates up to 1.5A, as well as USB-compliant 100mA and 500mA options. It also features power-path management, guaranteeing reliable power to your project.

The self-calibrating, I2C-based BQ27441-G1A measures your battery’s voltage to estimate its charge percentage and remaining capacity. The chip is also hooked up to a current-sensing resistor, which allows it to measure current and power! It’s a handy IC to have, especially if you ever need to keep an extra eye on your project’s power draw.

Suggested Materials

You’ll need a few components, accessories, and tools to get the Battery Babysitter up-and-running. The wishlist below includes all of the materials we use in this tutorial:

You can swap the RedBoard out for any Arduinio-compatible development board. Regardless of whether it runs at 3.3V or 5V, 8MHz or 16MHz, any Arduino should work with the Battery Babysitter’s fuel gauge IC.

Likewise, just about any single-cell lithium-polymer battery should work as well. The Battery Babysitter’s charger can be set as low as 100mA or as high as 1.5A, so if your batteries are best charged at 1C, look for LiPo’s with capacities ranging from 100mAh to 1500mAh.

Polymer Lithium Ion Battery - 400mAh

PRT-10718
$6.95
17
Polymer Lithium Ion Battery - 110mAh

PRT-13853
$4.95
Polymer Lithium Ion Battery - 850mAh

PRT-00341
$9.95
9
Polymer Lithium Ion Battery - 1000mAh

PRT-13813
$9.95

Finally, you’ll need a 5V supply to charge the battery, or just connect a USB cable into the on-board USB connector.

Suggested Reading

If you want to read up on some of the theories and concepts that the Battery Babysitter builds upon, check out some of these tutorials before continuing on:

Battery Technologies

The basics behind the batteries used in portable electronic devices: LiPo, NiMH, coin cells, and alkaline.

Electric Power

An overview of electric power, the rate of energy transfer. We'll talk definition of power, watts, equations, and power ratings. 1.21 gigawatts of tutorial fun!

I2C

An introduction to I2C, one of the main embedded communications protocols in use today.

What is a Battery?

An overview of the inner workings of a battery and how it was invented.

Hardware Overview

For quick reference, here is an annotated diagram of the Battery Babysitter’s most prominent features, connectors, and control circuitry:

Annotated top image

Below is a quick summary of the most significant components of the board. We’ll go more in-depth on charging, powering, and gauging in the sections that follow.

Charge Input(s)

As a primary source for battery-charging, the Battery Babysitter provides a micro-B USB port. This USB connector is only used to charge the battery – it will not show up as a USB device or pass any data through the port. (D+ and D- connectors are broken out to test points, though, if you want to change that.)

Alternatively, the External Charge Input port can be connected to any power supply between 4.35 and 6.4V. Keep in mind that the supply may be asked to source upwards of 1.5A, if the charge rate is set that high.

For more information on these two supply inputs, refer to the Battery Charging section of this guide.

Output Power and I2C Interface Headers

On the opposite side of the board sits the end goal of the Battery Babysitter: the voltage supply output. The voltage of this output supply will fall somewhere between 3V and 5.5V, depending on the state of your battery and/or presence of a charge supply. You can connect the rest of your system up to this supply output. For more information on the supply output header, refer to the Power-Path Management section of this guide.

Adjacent to that supply output is the BQ27441-G1A LiPo fuel gauge’s I2C interface. In addition to the standard power and SDA/SCL pins, this header also includes a programmable interrupt output: GPOUT. For more on these pins, and the BQ27441’s I2C interface, check out the LiPo Fuel Gague section.

System Output Enable – ON/OFF Switch

The Battery Babysitter’s ON/OFF switch toggles the “SYSOFF” pin of the BQ24075. It allows you to disconnect the battery from the system output– effectively controlling power to a load when the Babysitter is in battery-powered operation.

There are some “gotcha’s” to look out for with this switch:

  • To enable charging, the switch must be in the ON position. Battery charging will be disabled if the switch is off.
  • If a charge supply is connected – whether it’s USB or external – the system output voltage will be enabled, regardless of the state of the switch.

Battery Charging

To charge a LiPo battery with the Battery Babysitter, you can either connect a standard USB supply to the micro-B port

Charging via USB

…or connect an external source to the VIN pins. These pins include a footprint for a 2-pin 3.5mm screw terminal jack as well as standard 0.1"-pitch headers.

Charging via external supply

For normal charging conditiions, the voltage coming into either USB or VIN should be within 4.35V and 6.4V. The BQ24075 does feature overvoltage protection, which means it can protect against input voltages up to 28V, but any voltage above about 6.6V will cause the charge controller chip to shut off and disable charging.

To enable charging the ON/OFF switch must be in the ON position. If the switch is set to the OFF position, charging is disabled (the CHG LED will still be illuminated – don't let it fool you!).

Charge LED Indicator

The blue CHG LED is connected to the BQ24075’s CHG output. The LED will turn on when the battery is charging and off when charging is complete.

Setting the Charge Current

Most batteries shouldn't be charged at a rate over 1C. For example, a 110mAh battery's 1C charge current would be 110mA. Depending on your battery's capacity, you may need to do some configuring of the Battery Babysitter's set charge current.

The 2-position DIP switch on the Battery Babysitter allows you to easily set the charge current to one of three constant-current values. The two switches set EN1 and EN2 of the BQ24075, which the “1” and “2” labels on the switch should match up to.

Charge current set to 500mA

With EN1 set to off and EN2 set to “ON”, the charge current will be set to 500mA.

Consult the the table below for help setting your charge current. In the table, and throughout this tutorial, a 1 is equivalent to a switch in the “ON” position.

EN1EN2Charge Rate
00Suspend Mode (no charging)
10Fast Charge (1500 mA default)
01500 mA
11100 mA
Note: This truth table is flipped from that of the BQ24075 datasheet. It's written out to match the "ON" text on the DIP switch to a "1".

There is also a handy table on the back of the PCB, in case you forget which charge rate you currently have set.

If you’re short on fingernails, a pair of tweezers or a small screwdriver may be helpful for toggling those tiny dip switch sliders.

Customizing the Fast Charge Current (ISET)

Like many charge-controllers, the BQ24075 uses an external resistor to configure the charge current. The chip’s ISET pin is broken out for this purpose. By default, the Battery Babysitter is set to deliver a 1.5A charge current in fast-charge mode. But, by adding a custom resistor, you can drop that down to a more custom-fit charge rate.

ISET breakout from schematic

The equation below will determine the Battery Babysitter’s fast-charge rate, based on the resistance between ISET and ground (RISET):

ICHARGE = 890 / RISET
- or -
RISET = 890 / ICHARGE

RISET and ICHARGE are in units of ohms (Ω) and amps (A), respectively.

The Battery Babysitter equips the ISET pin with a 590Ω resistor to ground, which sets the charge current to its maximum: 1.5A.

ICHARGE can be set to anywhere between 100mA and 1500mA, which means RISET should fall somewhere between 590Ω and 8.9kΩ.

If you’d like to alter the fast-charge current, begin by cutting the ISET jumper on the back of the board.

ISET jumper cut

Then use the equation above to calculate an RISET value that will produce your desired charge current. If you want to set the charge current to 1A, for example, try to find a resistor around 890Ω. 1kΩ may be as close as you can get (with one resistor), which will set the charge current to 890mA.

Add the resistor across the unpopulated ISET pin, and solder the legs in.

Resistor soldered to ISET

Finally, make sure the DIP switch pins are set correctly (EN1 = 1, EN2 = 0).

Safety Timer (TMR)

The BQ24075 features a pair of charge timers that can may help prevent damage to a battery: a pre-charge timer and a max-charge timer.

Charge Phases

The BQ27045 varies charge current based on the voltage of the battery. There are three distinct phases of charging: pre-charge, fast-charge, and tapering.

Typical charge cycle
Typical charge cycle. (Figure 21 from the BQ27045 datasheet.)

The charger will be in pre-charge mode if the battery voltage is below about 3V. A battery this low on charge is in a fragile state and requires some delicate handling while it feeds on electrons to get back to a healthy level. In pre-charge mode, the charge current will be regulated to about 10% of the fast-charge current. For example, if the fast-charge current is set to 1.5A, the pre-charge current will be 150mA.

Fast-charge mode occurs while the battery voltage is between 3V and about 4.2V. During this state, the BQ27045 will charge the battery at constant current, determined by EN1 and EN2 (100mA, 500mA, or whatever the set fast-charge rate may be).

As the battery voltage nears 4.2V, the charge current will quickly taper off, as demonstrated in the graph above. In this state, the battery is held at a constant 4.2V.

The BQ24075’s safety timers determine how long the BQ27045 can remain in either the pre-charge or fast-charge states, before giving up and shutting down. If a timer expires, the CHG LED will blink at 2Hz, and charging will be disabled. The timer can be cleared by toggling the CE pin from HIGH to LOW.

Setting the Saftey Timers

The length of the safety timers are determined by a resistor (or lack of resistor) connected to TMR. There are three timer-configuring options:

  • Disable timer: Connect TMR to ground.
  • Default timer: Leave TMR open.
  • Custom timer: Connect a 18kΩ to 72kΩ resistor from TMR to ground to configure the timers.
By default, the Battery Babysitter disables the charge timers, by connecting TMR to ground.

The pre-charge and max-charge timers are set according to the following equations, based on a resistance from TMR to ground – RTMR. (The calculated times are in seconds, resistance in ohms.)

tPRECHG = 0.048 × RTMR
tMAXCHG = 0.48 × RTMR

Resistor values between 18kΩ and 72kΩ can be added to set the maximum pre-charge time between 24-36 minutes, and the max-charge timer between 240 and 360 minutes.

As with customizing charge current, if you want to make a modification to the charge timers, you first need to cut the TMR jumper, then add an external resistor between TMR and ground.

Power-Path Management

One of the BQ24075’s most unique features is dynamic power-path management (DPPM), which maintains a reliable output supply as long as either a battery or input supply (VIN/USB) are present.

The DPPM system can throttle charge current in order to maintain a reliable output supply. In the words of TI, DPPM “reduces the number of charge and discharge cycles on the battery,” and it allows your project to “run with a defective or absent battery pack.”

JST wire extending out of power path output

Footprints for a 0.1" header, 2-pin 3.5mm screw terminal and JST PTH connector are all connected to the power path management output.

Output Voltage Range

The output of the power-path management system is broken out to the “VOUT” pins, labeled “+” and “-”. This supply output is active as long as either a battery or input supply are connected to the Battery Babysitter. (In the case of the battery-supply, the ON/OFF switch must be ON.) The voltage will swing between 3.0V and 5.5V, depending on the charge of your battery and the voltage/pressence of the input supply.

If the Battery Babysitter is powered by only a battery, the output voltage will usually be 50-100mV below the battery voltage. For example, a battery producing 3.75V might produce an output between 3.65 and 3.74V. A larger load, pulling more current, will create a bigger voltage drop.

If a 5V USB supply and battery are connected to the Babysitter, the output voltage will be somewhere between 3V and 5V, depending on the load, and charge percentage of the battery. If the battery is at, or near, full charge, the output could be as high as 5V. As the load increases, the voltage at the output supply will drop as low as 4.4V.

If your battery is charging, the output voltage will be around 4.3V, but may drop as low as 3.8V depending on the load.

TLDR

  • If only a battery is present, the output should be about the battery voltage (minus a small drop).
  • If battery and 5V USB are connected, and the battery is charging, the output will be 3.8 - 4.3V.
  • If battery and 5V USB are connected, and the battery is fully charged, the output will be 4.5 - 5V.

Any load connected to VOUT should be able to handle a 3-5.5V input, but expect 3.6-5V assuming a healthy battery and USB supply. It's usually a good idea to regulate the output voltage of the Battery Babysitter to 3.3V, or find something that operates within the standard LiPo voltage range.

Power Path Operation Modes

The DPPM system is designed to protect a non-self-regulating charge supply by enforcing a limit on how much current that supply can source. Just as EN1 and EN2 are used to set charge current, they also control the input current limit:

Input current limits based on EN1 and EN2 DIP switch settings (1="ON").
EN1EN2Power-Path ModeInput Current Limit
00StandbyUSB suspend
10DPPMILIM (1500 mA default)
01USB500500 mA
11USB100100 mA

These limits help guarantee that your input supply will not be tasked with sourcing more current than it’s capable of.

If both VIN (USB or external) and a battery are connected and a load is pulling more than the set input current limit, the pair of supplies will supplement each other– the input supply will source current to the set limit (100mA, 500mA, etc.), and the battery will take care of the rest.

Input Current-Limit Example

The DPPM's input current limits are designed to protect against over-loading a USB supply. If, for example, your Battery Babysitter is powering a project that is consistently drawing 1Aandboth a battery and USB supply are connected to the board, here is the current draw you might expect from the pair of supplies:

Current draw across modes, assuming a 1A system load.
Power-Path ModeCurrent From BatteryCurrent From VIN (e.g. USB)
USB100900 mA100 mA
USB500500 mA500 mA
DPPM (set to 1.5A)0 mA1000 mA
Standby1000 mA0 mA

Input Current Limit (ILIM)

An external resistor between the ILIM pin and ground is used to set the maximum input current in DPPM mode. This value is set by the following equation, where resistance is in ohms and current is in amps:

ILIM = 1550 / RILIM

The Battery Babysitter populates this pin with a 1.1kΩ resistor, which sets the input current limit in DPPM mode to about 1.4A.

To customize this resistance value, as with the other charger features, cut the ILIM jumper on the back of the board. Then, calculate your desired current/resistance values, and populate a PTH resistor into the available ILIM resistor footprint.

LiPo Fuel Gauge

The Battery Babysitter’s other predominant component is a BQ27441-G1A LiPo fuel gauge. With a highly sensitive analog-to-digital converter, it can measure a battery’s voltage (mV) and state-of-charge (%). Plus, thanks to an external sense resistor, it can measure current (mA), power (mW), and even estimate remaining capacity (mAh).

The BQ27441 supports I2C, a two-wire serial interface, as its controlling interface. I2C is used to configure the fuel gauge with characteristics like full capacity, and it’s used to read out all of the gauge’s battery measurements.

BQ27441 I/O highlighted

The fuel gauge also features a programmable interrupt output, broken out to the GPOUT pin. This pin can be configured as either active-high or active-low, and it can be set to trigger when the battery charge falls below a set percentage or when the percentage changes by a set integer value.

Powering the BQ27441-G1A

The BQ27441-G1A LiPo fuel gauge is powered by the LiPo battery. To power its core logic, the fuel gauge regulates the battery voltage down to 1.8V. The 1.8V OUT pin on the side of the Battery Babysitter breaks out the fuel gauge’s 1.8V output supply, but it is meant as more of a voltage reference than a power source.

Although the BQ27441-G1A runs at 1.8V, its I2C and GPOUT pins are tolerant up to 5V. That’s where the VPU pin comes into play. The VPU pin, short for VPULL-UP, is the pull-up voltage for the open-drain SDA and SCL pins. This pin is an input, and should be connected to the operating voltage of your system – 3.3V, 5V, etc. A voltage supply is required on this pin, unless you have pull-up’s on the I2C bus elsewhere in your project.

Example Hardware Hookup

There are a variety of ways to integrate the Battery Babysitter into your project. Below is an foundational example circuit, which takes care of I2C wiring, but does not power the Arduino from the Babysitter.

RedBoard example hookup

Optionally, a wire can be connected from the Battery Babysitter’s VOUT pin to the Arduino’s 5V pin – powering the Arduino at somewhere between 3.4 and 5.5V. These pins should only be connected when the Arduino is not connected to USB, though; while you’re testing out the I2C interface and using the serial monitor for debugging, it’s best to leave that wire out.

Powering an Arduino From the Battery Babysitter

The Battery Babysitter is best-suited to powering 3.3V-based devices, like the Arduino Pro Mini 3.3V/8MHz, ESP8266 Thing, SAMD21 Mini Breakout, or Particle Photon. In those cases, you should be able to connect VOUT of the Battery Babysitter to your development board's "VIN" pin, where the Babysitter's output will be safely regulated down to 3.3V.

For example, here's the babysitter connected to an Arduino Pro Mini 3.3V:

When the Babysitter is powering a 5V-based Arduino – RedBoard, Arduino Uno, etc. – the Arduino's 5V regulator will be underpowered and will likely run close to the Battery Babysitter's output voltage, anywhere between 3.4-5V. That means an Arduino running at 16MHz may be underpowered.

BQ27441 Arduino Library

To make interfacing with the Battery Babysitter’s BQ27441 LiPo fuel gauge as painless as possible, we’ve written an Arduino library to abstract away the unique I2C interface and register interfacing. Head over to the SparkFun_BQ27441_Arduino_Library GitHub repository to download the latest, greatest release, or click the button below to download the library in a ZIP file.

Download the SparkFun BQ27441 Arduino Library!

For help installing the library, check out our Installing an Arduino Library tutorial.

Start Simple: BQ27441_Basic Example

The library includes a handful of examples, which you’re free to explore. To begin, we recommend BQ27441_Basic. Click through File>Examples>SparkFun BQ27441 LiPo Fuel Gauge Arduino Library>BQ27441_Basic to open it up.

Then set your Arduino port/board, and upload away!

After uploading, open up your serial monitor, and set the baud rate to 115200 bps. You should see the Arduino initialize the fuel gauge, and then begin printing some battery stats:

Serial output example

The basic example prints state-of-charge (%), battery voltage (mV), average current draw from the battery (mA), remaining and full capacities (mAh), average power draw on the battery (mW), and the battery’s state-of-health (%). The current and power draws will be negative when the battery is sourcing current, and positive when it’s charging. Try hooking up some power resistors to the Battery Babysitter’s output, or start charging to see how these numbers change.

You can adjust the full capacity value by configuring the BATTERY_CAPACITY variable at the top of the example sketch. For example, by assigning that variable a value of 850, the sketch configures the BQ27441 to calculate the battery state assuming an 850 mAh battery is connected to it.

Using the BQ27441 Arduino Library

Here is a quick primer to incorporating the BQ27441 library into a sketch of your own. First, set the library up by including it. Then – usually in the setup() function – call lipo.begin(). You can check the return value of the begin function, to make sure the Battery Babysitter is connected correctly.

language:c
#include <SparkFunBQ27441.h>

void setup()
{
    Serial.begin(115200);
    if (!lipo.begin())
    {
        Serial.println("Error: Unable to communicate with BQ27441.");
        Serial.println("  Check wiring and try again.");
        Serial.println("  (Battery must be plugged into Battery Babysitter!)");
        while (1) ;
    }
    Serial.println("Connected to BQ27441!");
}

Next, you may want to set the battery’s full capacity using the lipo.setCapacity() function:

language:c
lipo.setCapacity(1000); // Configure BQ27441 to assume a 1000 mAh battery

Expect a short delay – 1-to-2 seconds – before your Arduino completes the execution of this function. The Battery Babysitter’s capacity setting will remain at the set value until it loses power (usually when a battery is disconnected or fully discharged).

After those quick function-calls, you’re ready to read some battery statistics. You can use these functions to read state-of-charge, voltage, remaining capacity, current, power, and more.

language:c
unsigned int soc = lipo.soc(); // Read state-of-charge (in %)
unsigned int volts = lipo.voltage(); // Read voltage (in mV)
int current = lipo.current(AVG); // Read average current (in mA)
unsigned int capacity = lipo.capacity(REMAIN); // Read remaining capacity (in mAh)
int power = lipo.power(); // Read power consumption (in mW)
int health = lipo.soh(); // Read state-of-health (in %)

Now, take those values, and do something with them! Maybe that something is as simple as displaying the battery statistics on a MicroView.

Displaying battery characteristics on a MicroView

Using GPOUT

The BQ27441’s programmable output – GPOUT – can be used to alleviate your microcontroller from constantly having to poll the fuel gauge. GPOUT can be configured to alert your Arduino of one of two state changes. To start using the pin, simply connect it to a free Arduino digital pin, and load up one of the examples.

Low Battery Alert

The GPOUT pin can be used to alert your system that the battery’s state-of-charge has fallen below a pair of values. You can set two SoC thresholds in this mode: a higher “SOC1” value, and a critically low “SOCF” value. For example, the SOC1 threshold might be 20%, while the SOCF threshold is 5%.

In this mode, when the battery voltage falls below a threshold the interrupt will activate. It will remain in that state until the battery is charged, and its SoC rises above the threshold.

This interrupt function is documented in the BQ27441_GPOUT_BAT_LOW example.

Change in State-of-Charge

Alternatively, the BQ27441 can be configured to trigger the GPOUT pin whenever the SoC goes up or down by a set integer value. That integer value can be configured between 1 and 100. So, for example, if the change-delta is set to 1, GPOUT will trigger every time the SoC goes up or down a percent – 0%, 1%, 2%, and so on. If the change-delta is set to 10%, the interrupt will fire every time the SoC rises or falls to a factor of 10: 0%, 10%, 20%, etc.

This interrupt function is documented in the BQ27441_GPOUT_SOC_INT example.

Resources & Going Further

The SparkFun Battery Babysitter and the BQ27441 Arduino Library are both open-source, so there are plenty of resources to go around, including:

If you’d like to learn more about the BQ27441-G1A LiPo Fuel Guage, TI has published an excellent 59-page Technical Reference manual, plus, of course, there’s the datasheet.

For more information on the BQ24075 LiPo charger, the datasheet should have all of the information you might need.

The Battery Babysitter can be incorporated into just about any LiPo-powered project out there. If you’re looking for a little project-inspiration, check out some of these great SparkFun tutorials:

Weather Station Wirelessly Connected to Wunderground

Build your own open source, official Wunderground weather station that updates every 10 seconds over Wifi via an Electric Imp.

Photon Remote Temperature Sensor

Learn how to build your own Internet-connect, solar-powered temperature collection station using the Photon from Particle.

Blynk Board Washer/Dryer Alarm

How to configure the Blynk Board and app to notify you when your washer or dryer is done shaking.

Sparcade: Edison as a Web Server for Browser Games

Turn the Intel® Edison into an access point that serves a simple browser-based game. High scores from the game are displayed on a character LCD.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Experiment Guide for the Johnny-Five Inventor's Kit

$
0
0

Experiment Guide for the Johnny-Five Inventor's Kit a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t523

Introduction to the Johnny-Five Inventor's Kit

Johnny-Five Inventor's Kit

KIT-13847
$124.95

The Johnny-Five Inventor’s Kit you have in front of you is your toolkit, and this Experiment Guide is your map. We’re going to dive into the world of embedded electronics, JavaScript, the internet, and the way they come together as the “Internet of Things” (IoT). The Johnny-Five JavaScript framework provides a beginner-friendly way to start building things—quickly. This guide contains all the information you need to successfully build the circuits in all 14 experiments. At the center of this guide is one core philosophy: that anyone can (and should) play around with basic electronics and code.

When you’re done with this guide, you’ll have the know-how to start creating your own projects and experiments. You can build robots, automate your home, or log data about the world around you. The world, in fact, will be your hardware-hacking oyster. Enough inspirational sentiment — let’s get building!

Note: To get started with this guide you will need to have an internet connection and administrative privileges on the computer that you are using.

Included Materials

Here are all of the parts in the Johnny-Five Inventor’s Kit for the Tessel 2 (J5IK):

  • Tessel 2— The Tessel 2 Single-Board Computer (SBC)
  • USB-A to USB micro B— for connecting your computer to the Tessel 2
  • Wall Charger (5V, 1A)— Gotta power the Tessel 2 somehow! This charger makes it easy to power your projects!
  • Breadboard— This perforated grid is the ticket to easy experimentation with circuits.
  • Carrying Case— Take your kit anywhere with ease!
  • Jumper wires— These multi-colored wires with pins on each end making connecting things together a breeze.
  • Rainbow Pack of LEDs— LEDs are indispensable. Here’s a whole rainbow of ‘em.
  • 100 Ohm Resistors— These are just about right for using with LEDs at 3.3V (the voltage we’ll be using for the circuits in this guide)
  • 10K Ohm Resistors— These make excellent pull-ups, pull-downs and current limiters (don’t worry if you haven’t seen these terms before)
  • Photocell— A sensor that detects ambient light. Also called a photoresistor. Perfect for detecting when a drawer is opened or when nighttime approaches.
  • 10KΩ Trimpots— Also known as a variable resistor or a potentiometer, this is a device commonly used to control volume and contrast (it usually has a dial or a slider), and makes a great general user control input.
  • Red, Blue, Yellow and Green Tactile Buttons— These fun-to-press buttons give you several colors to choose from.
  • RGB LED— Why use an LED that can only be one color when you can have any color?
  • SPDT (Single-Pole, Dual Throw) Switch— It’s a switch! You slide it back and forth, and it fits into a breadboard just great.
  • Magnetic Door Switch— A mountable magnetic switch used in home automation and security. Great for detecting when a door or drawer is opened!
  • BME280 Atmospheric Sensor Breakout— A sensor for detecting temperature, pressure and humidity. It communicates using the I2C serial communication protocol. The header pins are soldered on for you, which makes connecting this to your project nice and easy.
  • Soil Moisture Sensor— The name describes it pretty well!
  • SparkFun Motor Driver— This nifty little board is perfect for controlling the speed and direction of up to two separate motors.
  • Hobby Gearmotor Set— A set of hobby level motors (two of ‘em) with gearboxes set to 120 RPM.
  • 7 Segment Display— It’s an LED that lets you display numerals via the combination of lit-up segments, just like an alarm clock from the 1980s!
  • 3.3V 16x2 White on Black LCD— This LCD can display 16 characters on two lines with a snazzy white-on-black background appearance. It operates at 3.3 volts (this is the voltage that the Tessel 2 is most comfortable with).
  • 74HC595 Shift Register— An integrated circuit (IC) that allows you to increase the number of inputs and outputs you can control from a microcontroller.

Suggested Reading

While you can get through this guide without doing any outside reading, the following tutorials cover the essential core of electronics and circuits and are super useful:

What is a Circuit?

Every electrical project starts with a circuit. Don't know what a circuit is? We're here to help.

How to Use a Breadboard

Welcome to the wonderful world of breadboards. Here we will learn what a breadboard is and how to use one to build your very first circuit.

Analog vs. Digital

This tutorial covers the concept of analog and digital signals, as they relate to electronics.

Open Source!

At SparkFun, our engineers and educators are constantly improving kits such as these and coming up with new experiments. We would like to give attribution to Rick Waldron and Bocoup, as he originally started the development of Johnny-Five many years ago. The contents of this guide are licensed under the Creative Commons Attribution Share-Alike 4.0 Unported License.

To view a copy of this license visit this link, or write: Creative Commons, 171 Second Street, Suite 300, San Francisco, CA 94105, USA.

About the Tessel 2

!The Tessel 2 Development Board

The Tessel 2 is an open-source development board. It runs JavaScript and supports npm, which means scripts to control it can be built with Node.js. It’s a platform for experimenting, tinkering, prototyping and producing embedded hardware, perfect for the Internet of Things.

OK, So What’s a Development Board?

Development boards are platforms for prototyping and building embedded systems. At the heart of (most) development boards is a microcontroller, which combines a processor and memory with IO capabilities. Microcontrollers like the one on the Tessel 2 provide a collection of GPIO (general-purpose IO) pins for connecting input and output devices to. The pins on the microcontroller itself—a chip—are small, too small for human fingers to work with easily (plus you’d need to solder things to them). Development boards instead connect these GPIO pins to pin sockets that are easy to plug things into.

Other common features of boards play a supporting role: connections for programming and communicating with the board, status lights and reset buttons, power connections.

More powerful boards like the Tessel 2 and the well-known Raspberry Pi are sometimes also called single-board computers (SBCs).

Tessel 2’s Features

The Tessel is a mighty little board. Some of Tessel 2’s specifications include:

  • 2 USB ports (you can connect cameras or flash storage, for example)
  • 10/100 ethernet port
  • 802.11 b/g/n WiFi
  • 580MHz Mediatek router-on-a-chip (you can turn your Tessel 2 into an access point!)
  • 48MHz SAMD21 coprocessor (for making IO zippy)
  • 64MB DDR2 RAM, 32MB of flash (lots of space for your programs and stuff)

Working with Tessel 2

Tessel has a set of command-line interface (CLI) tools for setting up and working with the Tessel 2 board. You’ll install these and do a one-time set-up provisioning of your Tessel.

You can write scripts for the Tessel 2 in any text editor, using JavaScript and including npm modules as you desire. A one-line terminal command deploys and executes your script on the Tessel.

Inputs and Outputs

There are two primary sets of pins on the Tessel 2: Port “A” and Port “B”. Each port has 10 pins: two pins for power (3.3V and ground) and eight GPIO pins.

The Tessel 2's GPIO pins: Port A and Port B

Some pins support different features. You can read details about every Tessel 2 pin, or just keep that info handy for reference later.

Powering the Board

There are multiple ways to power the Tessel 2. We’ll start by using the included USB cable.

Over USB

alt text

Connecting to the board directly with USB will allow you to easily modify any circuits and re-deploy code from the comfort of your desk, without having to retrieve your project. This is also handy when you don’t have access to the local network (for deploying code over WiFi).

USB Wall Charger

alt text

Once you have completely set up and provisioned your Tessel 2, you can deploy code through your local WiFi network. At some point you’ll itch to make your Tessel free of wires and tethering, but it still needs power. We supplied a 5V USB charger in the J5IK so you can place your project in a semi-remote location around your home or office and deploy code from anywhere on your local network.

USB Battery Pack

alt text

USB Battery packs are becoming quite popular as swag and giveaways at events. We collect them like candy because they allow us to power projects with minimal consideration to power management circuitry. If you have one of these handy, just use the included USB cable to plug the Tessel 2 into your battery and away you go! That’s it, simple as pie.

Ports and Pins on the Tessel 2

The Tessel 2 has two IO modules, Port A and Port B. Each port has 8 GPIO (general-purpose I/O) pins. Here’s their naming conventions and what all of them do.

alt text

Pin Naming Conventions

The pins on the Tessel 2 are broken out across the two different ports. The naming conventions in code will be referenced with the port letter first and then the pin number of that port. The port letter is not case sensitive! As an example, the first pin on port A would be referred to as pin a0 or A0. Use this table as a reference in terms of the naming of pins.

PortPin NumberJohnny-Five Name
A0“a0” or “A0”
A1“a1” or “A1”
A2“a2” or “A2”
A3“a3” or “A3”
A4“a4” or “A4”
A5“a5” or “A5”
A6“a6” or “A6”
A7“a7” or “A7”
B0“b0” or “B0”
B1“b1” or “B1”
B2“b2” or “B2”
B3“b3” or “B3”
B4“b4” or “B4”
B5“b5” or “B5”
B6“b6” or “B6”
B7“b7” or “B7”

Pin Capabilities: What Each Pin Can Do

The pins of each port have different functionalities available to them.

Other things to know:

  • All eight numbered pins, both ports (16 total), can be used as GPIO.
  • Pins 4 and 7 on Port A support analog-to-digital input. All pins on Port B support analog input.
  • Pins 5 and 6 on both ports support Pulse-Width Modulation (PWM).
  • Pins 0 and 1 on both ports can be used for I2C serial communication.
  • Serial TX/RX (hardware UART) is available on both port, pins 5 (TX) and 6 (RX).
  • Port B, Pin 7: Supports digital-to-analog conversion (DAC)

The two ports are essentially duplicates, with the following exceptions:

  • Port B: All numbered pins can be used for analog input.
  • Port B, Pin 7: Supports DAC.

For exhaustive details, see the pin functionality reference chart below:

PortPin NumberDigital I/OSCLSDATXRXAnalog InAnalog OutInterruptPWM
A0
A1
A2
A3
A4
A5
A6
A7
B0
B1
B2
B3
B4
B5
B6
B7

Software Installation and Setup

Let’s prepare the software side of things so you’re ready to build stuff in this guide. You’ll need to have a few things installed, and you’ll want to set up a project area for your JavaScript programs. So, don’t skip ahead!

Installing Needed Things

You’re going to need:

  • A text editor
  • Node.js
  • A terminal application

Installing a Text Editor: Atom

You will need a text editor in which to edit and save your JavaScript files. This means a plain text editor, not a Word document. If you’ve already got one, like SublimeText, Notepad++, vim, etc., groovy. If not, go ahead and install Atom.

atom text editor logo

You can use any text editor you like if you already have on installed and are up and running. But, if you have never used a text editor to write JavaScript, HTML, etc. we recommend using Atom. Atom is a free and open source text editor that works on all three major operating systems, is light weight and when you get comfortable…it’s hackable!

Download Atom by heading to the Atom website.

alt text

Installing Node.js

node.js logo

Node.js is a JavaScript runtime, that is, it’s software that can execute your JavaScript code. Node.js has special features that support some of the best potentials of the JavaScript programming language, like event-driven, non-blocking I/O. npm is Node’s package manager. It’s a giant repository of encapsulated bits of reusable useful code, called modules, that you can use in your programs. npm will get installed for you when you install Node.js.

alt text

Installing Node.js is a straightforward download-and-double-click process. Head on over to the Node.js website. Heads up: You’ll want to select the “LTS” version for download (LTS stands for long-term support). At time of writing, LTS is v4.4.5:

alt text

Using a Terminal: Command Line Basics

Working with the Tessel is just like doing web development. But if you’re not familiar with web development, you might want to take a minute or two to get comfortable with some key tools of the trade: the command line (the “terminal”, where you execute commands) and the text editor, where you will work on and save your programs. Tessel’s site has a great resource to help you get started with terminal.

In the context of this tutorial, things that should be run in the command line look like this:

hello i am a command line command!

You’ll see this when you get to the first experiment. But, don’t skip ahead—you’ll need the tools we install in the next step.

Setting up a Project Working Area

Take a moment to set up a working area (directory) where you can put the programs for your Johnny-Five Inventor Kit (J5IK). You’ll also need to initialize the new project with npm and install needed npm modules for both Johnny-Five and Tessel.

You can accomplish all of this by typing (or copying and pasting) the following commands in a terminal:

mkdir j5ik;
cd j5ik;
npm init -y;
npm install johnny-five tessel-io;

Running these commands will generate some output in your terminal. If everything goes smoothly, you’ll see some output about edits to a package.json file, and some additional output as npm installs the needed modules. You may also see a few WARN statements about missing description or repository field. Don’t worry—nothing’s broken.

An example of the kind of output you’ll see (though yours will differ in some particulars):

Wrote to /your/path/j5ik/package.json:
{"name": "j5ik","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\"&& exit 1"
  },"keywords": [],"author": "","license": "ISC"
}

j5ik@1.0.0 /your/path/j5ik
├── johnny-five
└── tessel-io
npm WARN j5ik@1.0.0 No description
npm WARN j5ik@1.0.0 No repository field.

Hardware Installation and Setup

It’s time to get your Tessel 2 set up. The steps we’ll walk through now include:

  1. Installing the t2-cli software tool
  2. Connecting the Tessel 2 with a USB cable
  3. Finding, renaming and provisioning the Tessel
  4. Updating the Tessel’s firmware

Installing the Command-Line Tool

Note to Linux users:
  • If you are making a global installation on a Linux computer, be sure to add sudo in front of your npm installation command!
  • Some Linux distrobutions require a few more library installs for `t2-cli` to work! Please install the libraries with the following command: apt-get install libusb-1.0-0-dev libudev-dev. You can find further documentation here.

You interact with the Tessel 2 using a command-line interface (CLI) tool called t2-cli. This tool can be installed using npm (Node.js' package manager, which gets installed automatically with Node.js).

Type the following into your terminal:

npm install t2-cli -g

The -g piece of that command (a flag) is important—this will tell npm to install the package globally, not just in the current project or directory.

The installation will take a few moments, and you will see a bunch of stuff scroll by that looks sort of like this:

alt text

Troubleshooting

Note: If you see any warnings or errors when trying to install t2-cli, the first thing to check is your Node.js version. To do this, type the following command in your terminal:

node –version

You’re aiming for the LTS (long-term support) version of Node.js, which at time of writing is v4.4.5. Learn more about how to upgrade and manage node versions with nvm.

Setting up your Tessel!

Now, time to get your hands dirty and get things up and running! Connect your Tessel 2 to your computer and give it about 30 seconds to boot up.

alt text

Once your Tessel 2 has booted (the blue LED will be steady instead of blinking), type the following command into your terminal:

t2 list

The t2-cli tool will look for connected Tessels. Tessels can be connected by USB or over WiFi, but for now, it should spot your single, USB-connected Tessel. You’ll see something like this:

alt text

Success! You can now communicate with your Tessel 2!

Naming Your Tessel 2

Giving your Tessel 2 a name is not required to use it, but it’s fun and friendly. To name your Tessel 2 use the following command:

t2 rename [name]

For example we renamed our Tessel 2 “Bishop” by typing following.

t2 rename bishop

The t2-cli tool will respond with the following output:

alt text

Double-check it!

t2 list

alt text

Connecting Your Tessel 2 to the Internet

If you’ve ever configured and connected other embedded systems to the Internet, the simplicity of this should make you grin.

You’ll need to be connected to your local WiFi network first. To connect your Tessel to a WiFi network, type the following command into your terminal:

t2 wifi -n [SSID] -p [password]

Replace [SSID] with the name of your wireless network (careful! It’s case-sensitive) and [password], well, I be you can figure that out!

You’ll see some output that looks something like the following:

INFO Looking for your Tessel...
INFO Connected to bishop.
INFO Wifi Enabled.
INFO Wifi Connected. SSID: your-network-ssid, password: your-network-password, security: psk2

That’s it! Simple as pie!

You can do a bunch of other stuff with your Tessel and network connectivity. Tessel’s website has in-depth documentation on WiFi connection options.

Troubleshooting

Note: Like Kindles and some Androids, Tessel 2’s don’t play nice with 5GHz WiFi networks.

Provision Your Tessel 2

Your Tessel exists, has a name, and is connected to your WiFi network. The next step is to provision the Tessel. That creates a secure, trusted connection between your computer and the Tessel, whether it’s connected by wire or over the air (WiFi). You’ll need to do this before you can deploy code to the Tessel.

Type the following command in your terminal:

t2 provision

You’ll see something like:

INFO Looking for your Tessel...
INFO Connected to bishop.
INFO Creating public and private keys for Tessel authentication...
INFO SSH Keys written.
INFO Authenticating Tessel with public key...
INFO Tessel authenticated with public key.

Verify it worked:

t2 list

You’ll see your Tessel twice! That’s because it’s connected via USB and WiFi.

INFO Searching for nearby Tessels...
USB bishop
LAN bishop

Great! We have one last setup step.

Update Your Tessel 2

The Tessel community is constantly improving the software and firmware for the Tessel 2. It’s likely that in the time between your Tessel 2’s manufacture and now, the firmware has been updated. To update your Tessel, type the following command in your terminal:

t2 update

The update process can last some time, so I would recommend a snack break or checking up on some news feeds while this happens. When the update is finished you will get the command prompt back, and you are all ready to go with your Tessel 2!

Introduction

Making an LED (Light-Emitting Diode) blink is the most basic “Hello, World!” exercise for hardware, and is a great way to familiarize yourself with a new platform. In this experiment, you’ll learn how to build a basic LED circuit and use Johnny-Five with your Tessel 2 to make the LED blink and pulse. In doing so, you’ll learn about digital output and Pulse Width Modulation (PWM).

Perhaps you’ve controlled LEDs before by writing Arduino sketches (programs). Using Johnny-Five + Node.js to control hardware is a little different, and this article will illustrate some of those differences. If you’re totally new to all of this — not to worry! You don’t need any prior experience.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2 and USB cable
  • 1x Breadboard
  • 1x Standard LED (Choose any color in the bag full of LEDs)
  • 1x 100Ω Resistor
  • 2x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this experiment:

Introducing LEDs

Diodes are electronic components that only allow current to flow through them in a single direction, like a one-way street. Light-Emitting Diodes (LEDs) are a kind of diode that emit light when current flows through them.

Photo of a standard red LED

Grab an LED and take a look at it. The longer leg is called the anode. That’s where current enters the LED. The anode is the positive pin and should always be connected to current source. The shorter leg, the cathode, is where current exits the LED. The cathode is the negative pin and should always be connected to a pathway to ground. Many LEDs also have a flat spot on the cathode (negative) side.

Drawing of LED parts: anode and cathode

If you apply too much current to an LED, it can burn out. We need to limit the amount of current that passes through the LED. To do that, we’ll use a resistor. When you use a resistor in this way to limit current, it is called — surprise! — a current-limiting resistor. With the Tessel 2 board, you should use a 100 Ohm resistor. We have included a baggy of them in the kit just for this reason!

If you’re curious to learn more about how voltage, current and resistance relate to one another, read this tutorial about Ohm’s Law.

Hardware Hookup

Its now the fun part! It’s time to start building your circuit. Let’s take a look at what goes into building this circuit.

Polarity

LEDs are polarized, meaning they need to be oriented in a specific direction when they are plugged in. You don’t want to plug a polarized part in backward!

On the other hand, resistors are not polarized; they’re symmetric, which means they don’t have an opinion about which way current flows across them. You can plug a resistor in facing either direction in a circuit, and it will be just fine.

Plugging Things In

When working with components like resistors, you’ll need to bend their legs at (about) 90° in order to correctly fit into the breadboard sockets. You can trim the legs shorter to make them easier to work with, if you like:

Bent resistor

All jumper wires work the same. They are used to connect two points together. All of the experiments in this guide will show the wires with different colored insulations for clarity, but using different combinations of colors is completely acceptable.

Image of jumper wires

Breadboards are vital tools for prototyping circuits. Inside the breadboard there are electrical connections between certain sockets. Power rails— columns on the left and the right of the breadboard — are electrically connected vertically, while terminal rows— rows in the middle of the breadboard — are connected horizontally (note that connections do not continue across the center notch in the breadboard).

image of breadboard

You can read a tutorial about breadboards to learn more.

Build the LED Circuit

Each of the experiments in this guide will have a wiring diagram. They’ll show you where to plug in components and how to connect them to your Tessel 2.

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Plug the LED into the breadboard, taking care to plug the cathode into row 1 and the anode into row 2. Make sure not to plug it in backward!
  2. Connect a 100Ω resistor between the LED’s cathode and ground as shown, spanning the notch in the middle of the breadboard.
  3. Use jumper wires to connect the breadboard’s components to the Tessel 2: connect ground (row 1) to the Tessel 2’s Port A GND pin and source (row 2) to the Tessel 2’s Port A, Pin 5.

Using Johnny-Five to Make an LED Blink

Open your favorite code editor, create a file called led.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your led.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var led = new five.Led("a5");
  led.blink(500);
});

Now for the big reveal! Type — or copy and paste — the following into your terminal:

t2 run led.js

You terminal will display something like this:

alt text

And when the program starts up:

alt text

What You Should See

Your LED should be blinking:

StateTime
On500ms
Off500ms

Exploring the Code

Let’s take a deeper look at what’s going on in the led.js Johnny-Five code.

Requiring Modules

In Node.js, a program can use any number of code modules. Modules are independent chunks of functionality. The software functionality for Tessel and Johnny-Five is contained within modules. We need to tell Node.js to require those modules so that they are available to the program:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

Note: For Node.js to be able to find and use the modules, you need to use npm to install for the project. That happened when you set up your working environment—you used npm install to install both the tessel-io and johnny-five modules.

Instantiating Objects

Next, the code needs to instantiate (create) a new object that represents the Tessel 2 board, and assign it to a variable (board) so we can access it later:

language:javascript
var board = new five.Board({
  io: new Tessel()
});

This creates a new instance of a Johnny-Five Board.

Johnny-Five supports many kinds of development boards. The support for some boards is built right in to Johnny-Five, but others — including Tessels — rely on external plugins encapsulated in modules. That’s why the code requires the tessel-ionpm module. Here, we tell Johnny-Five to use a Tessel object for IO when communicating with the board.

Learn more: Working with JavaScript Objects

Listening for Events

JavaScript code statements are typically executed top to bottom, in order, until they’re “done” (the program runs to completion) and nothing is left to do. One of Node.js' great powers is to allow programmers to “schedule” things to happen outside of this simple sequential-then-done flow. A program will terminate if there’s nothing left to do, but there are a number of ways to give the program something to do so that it keeps running.

Because the Tessel 2 board initialization involves hardware and I/O, it takes a few moments—considerably longer than the rest of the led.js script would take to execute. The initialization of the board won’t get in our program’s way—it happens asynchronously, allowing our script to keep executing statements without blocking—but we need to schedule something to happen when the board is ultimately ready.

language:javascript
board.on("ready", function() {
  // ...this will execute when the board emits the `ready` event
});

The code snippet defines a function that will get executed when (‘on’) the board emits the ready event.

Next we need to fill in what that function should do when the board is ready to go.

Learn more: In-depth: JavaScript’s Concurrency Model and Event Loop

Blinking the LED

Once the board is ready, it’s time to configure an LED on Port A, Pin 5 and then tell that LED to blink. In Johnny-Five, that looks like this:

language:javascript
board.on("ready", function() {
  var led = new five.Led("a5");
  led.blink(500);
});

Instances of Johnny-Five’s Led class have some handy tools (attributes and methods) for doing LED things—for example, blink..

This code creates a new Led object and tells it what pin to use (in this case "a5"). Then it tells the LED to blink every 500 milliseconds (half a second). That means the LED will cycle 500ms off, then 500ms on.

Comparing Node.js + Johnny-Five With Arduino Sketches

The structure of Node.js scripts written with Johnny-Five differs from how Arduino sketches are written in the Arduino Programming Language. The following is an example sketch in the Arduino Programming Language that would make an LED blink on and off (assuming that LED was connected to pin 13 of a theoretical board):

language:cpp
void setup() {
  pinMode(13, OUTPUT); // Set up pin 13 as an OUTPUT pin
}

void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH puts voltage on the pin)
  delay(500);               // wait for a half second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(500);               // wait for a half second
}

Arduino sketches have two sections:

  1. setup: runs once and is a place for configuring pins and initializing stuff
  2. loop: runs over and over and over and over

Another thing you’ll notice is that Arduino code is lower-level, meaning that there are fewer abstractions of specific hardware details. Instead of having an LED object that can do LED-like things (blink, pulse, fade, etc.), you interact directly with the digital pin and write LOW and HIGH states to it.

Between those digital writes, you tell everything to stop and wait for 500 milliseconds (delay). And the thing about delay is: it stops everything. It’s a process-blocking operation. Nothing else can happen while delay, well, delays.

In terms of code complexity, the difference between Johnny-Five and the Arduino Programming Language isn’t too significant when you’re just blinking an LED, but when it comes to pulsing an LED, Arduino sketch code starts getting more complicated.

Pulsing an LED

Now that we’ve covered the basics and some of the lower level technical aspects of Johnny-Five, let’s write a program that pulses the LED. Instead of blinking the LED on and off, pulsing fades the LED smoothly from off to on, and then from on to off again.

Pulse Width Modulation (PWM)

The state of a digital output pin can only be one of two things: LOW or HIGH. That means, at any given exact moment, an LED connected to the pin can only be off or on. We fool the eye into thinking an LED is dimmed to, say, half brightness by using a technique called Pulse Width Modulation (PWM)

With PWM, the pin can be switched between HIGH and LOW very quickly, causing the LED turn on and off, too. This cycle between on and off happens too fast for the human eye to discern. The percentage of time that the pin (with the LED attached) is HIGH (on) over a given period is its duty cycle. A 30 percent duty cycle (on — or HIGH — 30% of the time) will make an LED look like it’s partially lit — dimmer than bright but definitely on. By adjusting the duty cycle over time, we can fake (very convincingly!) an LED fading on and off.

Only certain pins on development boards support PWM. On the Tessel 2, pins 5 and 6 on both ports (A and B) support PWM.

Pulsing an LED With Arduino

Pulsing an LED in an Arduino sketch (Arduino Programming Language) requires more effort than blinking. Much has changed here from the blinking sketch, but certain things remain the same. There is still a process-blocking operation (delay), this time for 30ms on each loop cycle. We can no longer use the digitalWrite() function (it can only write binary LOW or HIGH); instead we’ll need the analogWrite() function for writing PWM values from 0 (0% duty cycle) to 255 (100% duty cycle). There are also now three variables to keep track of: led for the pin number, brightness to track the present brightness state, and lastly fadeAmount which holds the increase or decrease value to be applied to the value of brightness. Whew!

Here’s what that looks like all together:

language:cpp
int led = 9;           // the PWM pin the LED is attached to
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

void setup() {
  pinMode(led, OUTPUT);
}

void loop() {
  analogWrite(led, brightness);

  brightness = brightness + fadeAmount;

  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ;
  }

  delay(30);
}

It may be hard to get your head around the logic in that program. It’s not that easy to read. It doesn’t scream “pulse an LED” in the way that it expresses itself, does it?

Pulsing an LED With Johnny-Five

Let’s see what pulsing an LED looks like in Johnny-Five. Open your led.js script again. You’ll need to edit one line. Change the line that currently reads:

led.blink(500);

to

led.pulse(500);

No kidding—that’s it! No need to keep track of things, handle scheduling and timing or do arithmetic—instances of Johnny-Five’s Led do it all for you. Like blink, the pulse method takes an argument that is the pulse period in milliseconds. Here is the complete script for your copying-and-pasting convenience:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

  var board = new five.Board({
    io: new Tessel()
  });

  board.on("ready", function() {
    var led = new five.Led("a5");
    led.pulse(500);
  });

Remember, to run the script and see your LED pulse, type — or copy and paste — the following command in a terminal:

t2 run led.js

What You Should See

Your LED should be pulsing in 500ms period cycles.

Building Further

Try adjusting the speed passed to the led.blink() and led.pulse() calls. For example: led.blink(1000) or led.pulse(1000) would change the cycles to 1000ms periods.

Reading Further

Experiment 2: Multiple LEDs

Introduction

In Experiment 1 of the Johnny-Five Inventor’s Kit (J5IK), you learned how to blink and pulse a single LED with a Tessel 2. In this experiment, you’ll learn how to control multiple, colorful LEDs with Johnny-Five to create animated variations on a simple “Cylon effect.” This article dives into structuring looping logic for your projects using Johnny-Five and JavaScript fundamentals.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this experiment:

  • What is a Circuit?– This tutorial will explain what a circuit is, as well as discuss voltage in further detail.
  • Voltage, Current, Resistance, and Ohm’s Law– Learn the basics of electronics with these fundamental concepts.
  • LEDs (Light-Emitting Diodes)– LEDs are found everywhere. Learn more about LEDs and why they are used in so many products all over the world.
  • Resistors– Why use resistors? Learn more about resistors and why they are important in circuits like this one.
  • Polarity– Polarity is a very important characteristic to pay attention to when building circuits.

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 6x LEDs (One of each color: red, orange, yellow, green, blue, purple)
  • 6x 100Ω Resistor
  • 7x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Hardware Hookup

Its now the fun part! It’s time to start building your circuit. Let’s take a look at what goes into building this circuit.

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Multiple-LED Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Connect the LEDs to the breadboard. Make sure to connect their cathode legs to sockets in the ground column in the power rail.
  2. Plug in the 100Ω resistors in terminal rows shared with the anode legs of the LEDs, spanning the central notch.
  3. Connect jumper wires between the resistors and the Tessel 2. You may find it helpful to use colors that correspond to the LED’s color.
  4. Use a jumper wire to connect the ground power rail of the breadboard to the Tessel 2’s GND pin.

Lighting Up LEDs Side-to-Side

Open your favorite code editor, create a file called side-to-side.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your side-to-side.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});
board.on("ready", () => {
  var leds = new five.Leds(["a2", "a3", "a4", "a5", "a6", "a7"]);
  var index = 0;
  var step = 1;

  board.loop(100, () => {
    leds.off();
    leds[index].on();
    index += step;
    if (index === 0 || index === leds.length - 1) {
      step *= -1;
    }
  });
});

Before you run this on your Tessel 2, pause for a moment. Can you tell what the program will do?

Type – or copy and paste – the following command into your terminal and press enter:

t2 run side-to-side.js

Once the program starts up, your multiple-LED circuit should light up in a pattern like this:

Exploring the Code

Before continuing, we recommend that you’ve read Experiment 1: Exploring the Code.

The side-to-side program lights up LEDs in the following pattern:

  1. From lowest pin number to highest pin number, turn on one LED at a time every 100 milliseconds, then:
  2. From highest pin number to lowest pin number, turn on one LED at a time every 100 milliseconds, then:
  3. Repeat from step 1.
Collections of LEDs With the Leds Class

Instead of instantiating each LED as its own object separately using the Led class (as we did in Experiment 1), we can create a single collection that contains all of the LEDs in one swoop:

language:javascript
board.on("ready", function() {
  var leds = new five.Leds(["a2", "a3", "a4", "a5", "a6", "a7"]);
});

Johnny-Five’s Leds constructor takes an Array of pin numbers and creates an Led object for each of them. Each of these Led objects can be accessed and manipulated from the container-like leds object. Instances of the Leds class behave like Arrays but have some extra goodies (they’re described as “Array-like objects”).

Read up on JavaScript Arrays if the concept is new or you’re feeling rusty.

Looping in Johnny-Five

To turn on LEDs one at a time, we need some way of creating a loop that executes every 100 milliseconds. We’re in luck. Board object instances have a loop method that can do just that! Convenient!

language:javascript
board.on("ready", () => {
  board.loop(100, () => {
    // ... This function gets invoked every 100 milliseconds
  });
});

The function (in this case, an arrow function]) passed as the second argument to loop will get invoked every 100 milliseconds. Now, let’s see what needs to happen in that loop.

Lighting Up, Lighting Down

Here’s what we need to accomplish in each invocation of the loop callback function:

language:javascript
board.on("ready", () => {
  var index = 0;
  var step = 1;

  board.loop(100, () => {
    leds.off();            // 1. Turn all of the LEDs off
    leds[index].on();      // 2. Turn on the "next" active LED
    // ...                 // 3. Determine what the next active LED will be
  });
});

In step one, all LEDs are turned off. Leds instances have an off method that will turn off every Led in its collection. Easy peasy.

The variable index holds the index of the next LED that should get turned on. The initial value of index is 0. Why 0? Each Led in leds can be accessed by its numeric index, like an Array:

ReferenceLED
leds[0]Led object controlling red LED on Port A, Pin 2
leds[1]Led object controlling red LED on Port A, Pin 3
leds[2]Led object controlling red LED on Port A, Pin 4
leds[3]Led object controlling red LED on Port A, Pin 5
leds[4]Led object controlling red LED on Port A, Pin 6
leds[5]Led object controlling red LED on Port A, Pin 7

The first time the loop executes, index is 0, and it will turn on leds[0], which is the first (red) LED on Port A, Pin 2:

language:javascript
leds[index].on();

Step 3 sets us up for the next time the loop function executes. The value of index needs to be set to the index of the next LED that should turn on. This is what the step variable helps us with. Add step to index to get the index of the next LED to light up:

language:javascript
board.on("ready", () => {
  var index = 0;
  var step = 1;

  board.loop(100, () => {
    leds.off();            // 1. Turn all of the LEDs off
    leds[index].on();      // 2. Turn on the "next" active LED
    index += step;         // 3a. Add `step` to index
  });
});

At the completion of the first invocation of the loop callback function, index will hold the value 1.

During the second invocation, the second, orange LED (leds[1]) will light up. index will be incremented to 2.

And so on, lighting up red, orange, yellow, green, blue … But then we get to the purple LED (Port A, Pin 7) at index 5. There is no Led element at leds[6], so what do we do now? Well, we can flip the sign of step, changing its value to -1:

language:javascript
board.on("ready", () => {
  var index = 0;
  var step = 1;

  board.loop(100, () => {
    leds.off();            // 1. Turn all of the LEDs off
    leds[index].on();      // 2. Turn on the "next" active LED
    index += step;         // 3a. Add `step` to index
    if (index === leds.length - 1) { // 3b. If we're at the highest index...
      step *= -1; // ...invert the sign of step
    }
  });
});

Now invocations of the loop callback function will decrease (decrement) the index value, and the LEDs will light up in reverse order. When the index gets down to 0— the first LED — we need to swap the sign of step again:

language:javascript
board.on("ready", () => {
  var index = 0;
  var step = 1;

  board.loop(100, () => {
    leds.off();            // 1. Turn all of the LEDs off
    leds[index].on();      // 2. Turn on the "next" active LED
    index += step;         // 3a. Add `step` to index
    // If we are at the lowest OR the highest index...
    if (index === 0 || index === leds.length - 1) {
      step *= -1;
    }
  });
});

Using board.loop with the leds can be adapted in various ways to change the way the LEDs light up. Let’s try a few variations.

Variation: One-by-One On, One-by-One Off

Now we’ll light up each LED one at a time and keep them on as we go; the display will loop as:

  1. From lowest pin number to highest pin number, turn on each LED and keep it on.
  2. From highest pin number to lowest pin number, turn off each LED and keep it off.
  3. Repeat from step 1.

Open your favorite code editor, create a file called one-by-one-on-off.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your one-by-one-on-off.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});
board.on("ready", () => {
  var leds = new five.Leds(["a2", "a3", "a4", "a5", "a6", "a7"]);
  var index = 0;
  var step = 1;

  board.loop(100, () => {
    leds.off().slice(0, index).on();
    index += step;
    if (index === 0 || index === leds.length) {
      step *= -1;
    }
  });
});

All of the changes are confined to the loop callback function. There’s one line doing much of the heavy lifting here:

leds.off().slice(0, index).on();

This single line turns all of the LEDs off and then turns on all LEDs between 0 and the current index. slice is an Array method that returns a chunk of an array between the start and end indexes provided (leds isn’t an Array, remember, but it acts like one, so it also has a slice method).

As in the previous example, this script will flip the sign on step when it reaches either end of the leds collection.

Run the script by typing – or copying and pasting – the following command in your terminal:

t2 run one-by-one-on-off.js

Once the program starts up, your LEDs circuit should display something like this:

Variation: One-by-One On, Clear and Repeat

Now let’s simplify that same program: light up each pin, one at a time, and then turn them off; the display will loop as:

  1. From lowest pin number to highest pin number, turn on each LED and keep it on.
  2. Once all the LEDs are on, turn them all off
  3. Repeat from step 1.

Open your favorite code editor, create a file called one-by-one-clear-repeat.js and save it in the j5ik/ directory. Type – or copy and paste – the following JavaScript code into your one-by-one-clear-repeat.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});
board.on("ready", () => {
  var leds = new five.Leds(["a2", "a3", "a4", "a5", "a6", "a7"]);
  var index = 0;

  board.loop(100, () => {
    if (index === leds.length) {
      leds.off();
      index = 0;
    } else {
      leds[index].on();
      index++;
    }
  });
});

Again, there is very little to change here, so we’ll skip right to the operations within the call to board.loop(...).

language:javascript
board.loop(100, () => {
  if (index === leds.length) {
    leds.off();
    index = 0;
  } else {
    leds[index].on();
    index++;
  }
});

The semantics for this program are slightly different from the previous examples. Because we’re always lighting LEDs up in the same direction — lowest to highest index — we don’t have to deal with the logic for swapping the sign on a step variable. Instead, a simple increment of the index value on each invocation of the loop callback function is all we need, resetting it to 0 when we run out of LED indexes.

  1. If the index equals the number of LEDs in the leds collection,
  2. Turn all ledsoff.
  3. Set the index back to 0.
  4. Else,
  5. Turn the led at present indexon.
  6. Increment the index.

Type — or copy and paste — the following into your terminal:

t2 run one-by-one-clear-repeat.js

Once the program starts up, your LEDs circuit should display something like this:

Variation: Collision

Changing gears a bit, this next program will light LEDs from the middle, out, and back (there will be two LEDs lit at a time); the display will loop as:

  1. From the first to the last and the last to the first, by pin number, light the LEDs one at a time.
  2. Repeat from step 1.

Open your favorite code editor, create a file called collision.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your collision.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});
board.on("ready", () => {
  var leds = new five.Leds(["a2", "a3", "a4", "a5", "a6", "a7"]);
  var index = 0;
  var step = 1;

  board.loop(100, () => {
    leds.off();
    leds[index].on();
    leds[leds.length - index - 1].on();

    index += step;

    if (index === 0 || index === leds.length - 1) {
      step *= -1;
    }
  });
});

This example contains logic more in line with the first few variations again — turning on the correct LED and then determining what the next LED’s index will be:

  1. Turn all ledsoff.
  2. Turn the leds at index and its counterpart on.
  3. Update the index with step (either 1 or -1).
  4. If index equals 0, or index equals the number that corresponds to the last possible led in the leds collection, flip the sign of step.

Type — or copy and paste — the following into your terminal:

t2 run collision.js

Once the program starts up, your LEDs circuit should display something like this:

Building Further

  • Try writing your own algorithms for other patterns not shown here.

Reading Further

Experiment 3: Reading a Potentiometer

Introduction

So far the experiments have been focused on output: writing code with Johnny-Five to control the state of one or more LEDs. In this experiment, you’ll learn how to read analog input data from a potentiometer. You’ll learn about how development boards (like the Tessel 2) sample and process analog input and how to use data from analog sources to make things happen. Using data from the potentiometer, you’ll control a bar graph in your terminal, alter the brightness of an LED and control the activity of multiple LEDs.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x Potentiometer
  • 1x Standard LED (any color)
  • 1x 100Ω Resistor
  • 7x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Trimpot 10K with Knob

COM-09806
$0.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introducing Potentiometers

A potentiometer is a resistance-based analog sensor that changes its internal resistance based on the rotation of its knob. The potentiometer has an internal voltage divider, creating a varying voltage on the center pin. The voltage on the center pin changes as the knob is turned. You can use an analog input pin to read this changing voltage.

alt text

Hardware Hookup

Its now the fun part! It’s time to start building your circuit. Let’s take a look at what goes into building this circuit.

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Potentiometer Circuit

To hook up the potentiometer, attach the two outside pins to a supply voltage (3.3V in this circuit) and ground. It doesn’t matter which is connected where, as long as one is connected to power, and the other to ground. The center pin is then connected to an analog input pin so the Tessel 2 can measure changes in voltage as the knob is turned.

Note: The potentiometer included in the kit has three marks on it that will help you figure out which breadboard rows the pins are plugged into.

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Connect the potentiometer to the breadboard. Connect the potentiometer’s power pins (supply and ground) to the power rail with jumper wires and connect the middle pin to the Tessel 2’s Port A, Pin 7.
  2. Connect the LED. Use a jumper wire to connect the Tessel 2’s Port B, Pin 5 through the 100Ω resistor and to the LED’s anode (positive, longer) leg. Connect the LED’s cathode to ground on the power rail. Double-check the legs on the LED to make sure you haven’t plugged it in backward!
  3. Use jumper wires to connect the Tessel 2’s 3.3V and GND pins to the breadboard’s power rails.

Reading Analog Sensors With Johnny-Five

Open your favorite code editor, create a file called sensor-basic.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your sensor-basic.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel(),
  repl: false,
  debug: false,
});

board.on("ready", () => {
  var sensor = new five.Sensor("a7");

  sensor.on("change", () => console.log(sensor.value));
});

Type — or copy and paste — the following into your terminal:

t2 run sensor-basic.js

This isn’t particularly interesting, as all it does is output the value of the sensor (integers between 0 and 1023) until the program is interrupted. yawn

alt text

You should see something similar to this. Your sensor values (0-1023) being logged in the console.

Exploring the Hardware

Analog Input

For software to be able to work with data coming from an analog sensor, it first needs to be converted from an analog signal (infinite possible values) to a digital signal (discrete set of values). The microcontroller on the Tessel 2 does this analog-to-digital conversion (ADC) for you, sampling the incoming analog voltages and converting them to a range of values between 0 (0V) and 1023 (3.3V). Values in between are quantized to the nearest integer.

Asynchronous I/O

In Experiment 1: Blink an LED, we looked at the asynchronous nature of Node.js runtime, comparing how the Arduino Programming Language’s delay function is blocking, while Johnny-Five’s execution model follows the Node.js convention: non-blocking. Listening for Boardready events is an example of a common asynchronous pattern. Non-blocking I/O is extremely important to the JavaScript-for-hardware story, and the Tessel 2 has an exemplary implementation.

Tessel 2’s support for asynchronous, non-blocking I/O is in its hardware. In addition to the Mediatek chip (that’s where your code executes), it has a second processor (Atmel® SAMD21) that is responsible for I/O.

The MediaTek processor and the Atmel coprocessor exchange messages representing I/O state. Code that executes on the MediaTek chip (the Linux user space) has asynchronous access to the state captured on SAMD21. For example, if a digital input pin goes HIGH, the SAMD21 sends a message to the MediaTek chip and any code running can elect to consume that message. When code running on the MediaTek chip wants to output values to the SAMD21 to be written to an output pin, it simply sends the message, then keeps going.

alt text

The MediaTek chip (green) and the Atmel SAMD21 (blue) allow for Asynchronous I/O on your Tessel 2.

For the purpose of our experiment, it’s helpful to understand that when program code running on the MediaTek chip wants to know the value of an analog input, it sends a request for that information, registers a handler (a function) and continues on. Sometime “later” (likely within a millisecond or two), and always in a different execution turn, the SAMD21 responds with the present value of the input. The registered handler is then invoked with response value. This may happen once or repeatedly, but never causes the program to stop and wait.

Exploring the Code

Notice that the Board constructor call is being passed an object with two properties that we haven’t seen before: repl: false and debug: false. These settings tell Johnny-Five to shut off both the “on-by-default” REPL (Read–Eval–Print Loop, an interactive prompt) and connection debugging output.

Once the board has emitted the ready event, hardware inputs are ready for interaction:

language:javascript
var sensor = new five.Sensor("a7");

The first thing to do is create an instance of the Sensor class, indicating that this sensor is attached to Port A, Pin 7.

language:javascript
sensor.on("change", () => console.log(sensor.value));

Then, a handler function is registered for change events, meaning that anytime the reading changes, the function will be called.

Every time this function is called and the sensor value is displayed, it occurs in a different execution turn than the previous invocation, staying true to the asynchronous, non-blocking model. The handler function for change events simply logs sensor.value. sensor.value is a 10-bit number (0-1023), representing the last successful ADC-processed read from the Sensor object’s associated analog input pin.

Note: The minimum version of Node.js that runs on Tessel 2 supports many ES2015 features, including Arrow Functions, so we’re using those here to simplify the program.

Variation: Sensor Input Graphing

For this experiment, you will be “bar chart graphing” light intensity values in your terminal using the Barcli module:

barcli

barcli [bahrk-lee]

Barcli is a simple tool for displaying real-time data in the console. Multiple instances of Barcli can be stacked to show multiple axes, sensors or other data sources in an easy-to-read horizontal bar graph.

In your terminal, make sure you’re inside the working directory (j5ik), then type — or copy and paste — the following command:

npm install barcli

We’ll make our sensor data a little more interesting (than just numbers scrolling by). Let’s visualize it as a graph displayed directly in the terminal. Open your favorite code editor, create a file called sensor-graph.js and save it in the j5ik/ directory.

Type — or copy and paste — the following JavaScript code into your sensor-graph.js file:

language:javascript
var Barcli = require("barcli");
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var range = [0, 100];
  var graph = new Barcli({
    label: "My Data",
    range: range,
  });
  var sensor = new five.Sensor({
    pin: "a7",
    threshold: 5 // See notes below for detailed explanation
  });

  sensor.on("change", () => {
    graph.update(sensor.scaleTo(range));
  });
});

Type — or copy and paste — the following into your terminal:

t2 run sensor-graph.js

Once the program starts up, the terminal should display something like this:

alt text

Exploring the Code

We’ve now required the Barcli module:

language:javascript
var Barcli = require("barcli");

… which means it can be put to use in your program.

To create a graph, we’ll need an instance of a Barcli object. First, though, we need to define a range of values that are valid for the graph:

language:javascript
var range = [0, 100];
var graph = new Barcli({
  label: "My Data",
  range: range,
});

The graph object is now able to represent values from 0 to 100. However, recall that values coming from the potentiometer will range from 0 to 1023. We’ve got to scale those, too, so that they can be graphed!

The way we’re instantiating the Sensor object looks a bit different from the previous example. Instead of passing the constructor a String identifying the pin, like so:

language:javascript
var sensor = new five.Sensor("a7");

… we’re using the options object form here, which allows us to pass a whole object full of extra information to the constructor:

language:javascript
var sensor = new five.Sensor({
  pin: "a7",
  threshold: 5
});

Let’s talk about that threshold property. It defines how much a sensor’s value needs to change before a change event is emitted. The default value of threshold is 1. As you saw in the first example, any change to the sensor’s value – remember, values range from 0 to 1023 and are whole numbers (integers) – will cause a change event. For this variation, that’s too much sensitivity.

Specifically, we want to define a threshold that will limit the change events to those that are relevant to our range, which is 0-100. Since we’ll be scaling the sensor’s value from 0-1023 to 0-100, we only care about changes of approximately every 10 steps in 1023 (obviously that’s fudging a little, and you’re encouraged to be more precise in your actual programs). The threshold value is exactly half of the approximate step:

  • > (value + 5)
  • < (value - 5)

Finally, the program replaces the call to console.log(...) with a call to graph.update(...) and passes the result of calling the sensor object’s scaleTo(...) method with the same range as graph is using:

language:javascript
sensor.on("change", () => {
  graph.update(sensor.scaleTo(range));
});

Unpacking the line:

language:javascript
graph.update(sensor.scaleTo(range));

When invocations are nested like this, they proceed from the inside out. First, the sensor object’s 10-bit value is scaled to 0-100 (range) and then that resulting value is passed to the graph object’s update method.

Variation: Using Sensor Input to Create Output

For the final variation of this experiment, you’ll process the sensor readings to control the brightness of the LED in your circuit. Open your favorite code editor, create a file called sensor-input-to-output.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your sensor-input-to-output.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var sensor = new five.Sensor({
    pin: "a7",
    threshold: 2
  });
  var led = new five.Led("b5");

  sensor.on("change", () => {
    led.brightness(sensor.scaleTo(0, 255));
  });
});

Type — or copy and paste — the following into your terminal:

t2 run sensor-input-to-output.js

Once the program starts up, LED should display something like this:

Exploring the Code

Again, we’re instantiating a Sensor object to represent the potentiometer, and defining a threshold. This time we’ll set it to 2, because the rounded result of 1023 (the top of the 10-bit sensor range) divided by 255 (the top of the 8-bit brightness range) is 4, and threshold should be set to half of the full step size:

language:javascript
var sensor = new five.Sensor({
  pin: "a7",
  threshold: 2
});

Next, a new instance of the Led class is created, with Pin 5 on Port B:

language:javascript
var led = new five.Led("b5");

+The change event remains the same, but the operation within the handler is updated to call the led object’s brightness(...) method, passing the sensor’s value scaled from its 10-bit input range (0-1023) to the 8-bit output range (0-255) of the led:

 language:javascript
 sensor.on("change", () => {
   led.brightness(sensor.scaleTo(0, 255));
 });

Alternatively, the conversion could have been written as a bit-shifting operation, where the 10-bit value is shifted 2 bits to the right, since brightness(...) expects an 8-bit value (0-255). This bit-shifting operation is the most efficient way to scale the 10-bit analog input value to the 8-bit PWM output value:

language:javascript
0b1111111111 === 1023;
0b0011111111 === 255;
0b11111111 === 255;
(0b1111111111 >> 2) === 255;

And could be applied in our code like so:

language:javascript
sensor.on("change", () => {
  led.brightness(sensor.value >> 2);
});

This snippet means “shift the sensor.value 2 bits to the right” — the two right-most bits are discarded. Voila! An 8-bit number from a 10-bit number.

Building Further

  • Experiment with bit shifting in your Node.js console.

Reading Further

Experiment 4: Reading a Push Button

Introduction

In Experiment 3, you journeyed into the fun world of input by reading data from an analog sensor. This experiment continues that journey, moving now into digital input. You’ll learn how digital input differs from analog input, and you’ll meet a useful new component: the push button (also sometimes called a momentary switch). You’ll learn how to control a single LED with button presses, and then how to control multiple LEDs from multiple buttons.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this experiment:

Parts Needed

To complete this experiment, you’ll build two circuits. You’ll need the following parts:

  • 1x Tessel 2
  • 1x Breadboard
  • 2x Standard LED (any color is fine)
  • 2x Push Button
  • 2x 100Ω Resistors
  • 2x 10kΩ Resistors
  • 12x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Momentary Pushbutton Switch - 12mm Square

COM-09190
$0.5
4
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 10K Ohm 1/6th Watt PTH - 20 pack

COM-11508
$0.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introducing the Push Button

alt text

A momentary push button is a kind of switch, closing (completing) a circuit while it is being actively pressed. If you take a push button and look at it, you’ll notice it has four pins, which might seem like a lot of pins. Let’s walk through how the pins are connected to each other.

The four pins on a push button are split into two pairs. Each pin is adjacent to two other pins: the other half of its pair (on the opposite side of the button) and a pin not paired with it (located on the same side). A pin is always electrically connected to the other pin in its pair, but is only connected to the other adjacent pin when the button is actively being pressed. When you press down on the button and get a nice “click,” the button bridges the two sets of pins and allows current to flow through the circuit.

How do you know which pins are paired up? The buttons included in this kit will only fit across the breadboard ditch in one direction. Once you get the button pressed firmly into the breadboard (across the ditch), the pins are horizontally paired. The pins toward the top of the breadboard are connected, and the pins toward the button of the breadboard are connected.

Note: Not all buttons share this pin format. Please refer to the data sheet of your specific button to determine which pins are paired up.

All right, now we have a sense of how a button can complete a circuit, but we need the right kind of circuit for our button. Button presses need to cause a digital input on the Tessel to move between HIGH and LOW logic levels when the button is pressed. The circuits in the two wiring diagrams for this experiment use a 10kΩ pull-down resistor with the buttons to make sure that the Tessel will read the button circuit as LOW (off/false) when the button isn’t pressed and HIGH (on/true) when it is.

Hardware Hookup

Your kit comes with four different colored push buttons. All push buttons behave the same, so go ahead and use your favorite color!

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Button Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Connect the pushbutton to the breadboard. It should only fit in one orientation spanning the center notch. Use jumper wires to connect one of the right-hand pins of the button to the ground power rail, through a 10kΩ resistor, as shown. Connect the other pin of the right side of the button to the supply power rail with another jumper wire.
  2. Starting from a socket on the same row as the 10kΩ resistor — but on the opposite side of it from the button — connect a jumper wire to the Tessel’s Port A, Pin 0.
  3. Plug the LED into the breadboard as shown, making sure the anode (longer leg) is closer to the top of the breadboard. Connect the cathode (shorter leg) to the ground power rail using a jumper wire. Connect the anode, through a 100Ω resistor, to the Tessel 2’s Port A, Pin 5.
  4. Connect the Tessel’s +3.3V and GND pins to the breadboard’s power rails, using jumper wires.

Observing a Button With Johnny-Five’s Button Class

Open your favorite code editor, create a file called button.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your button.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var button = new five.Button("a2");
  button.on("press", () => console.log("Button Pressed!"));
  button.on("release", () => console.log("Button Released!"));
});

Type — or copy and paste — the following into your terminal:

t2 run button.js

What You Should See

When you press the button, your terminal will display the appropriate message:

alt text

Console output triggered by button events

Exploring the Code

Using Input to Control Output With Johnny-Five

OK, let’s make this do something a little more interesting before we dive in and look at how it works. Go back to your button.js and either type the changes or copy and paste the following code:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var led = new five.Led("a5");
  var button = new five.Button("a2");
  button.on("press", () => led.on());
  button.on("release", () => led.off());
});

Type — or copy and paste — the following into your terminal:

t2 run button.js –single

The --single flag tells the T2 CLI to only deploy the single, specified file. This will preserve all other existing code on the Tessel 2 while still deploying your new program changes, which can make the deployment faster.

What You Should See

When you press the button, the LED should light up. When you release the button, the LED should turn off.

Exploring the Code

Once the board has emitted the ready event, we can initialize Led and Button instances to interact with our hardware on the specified pins:

language:javascript
var led = new five.Led("a5");
var button = new five.Button("a2");

The Johnny-Five Button class takes care of processing values from input in order to emit intuitive events for each state of the hardware. We’ve registered handlers for these events: press, hold and release.

When the button is pressed, turn the LED on:

language:javascript
button.on("press", () => led.on());

When the button is released, turn the LED off:

language:javascript
button.on("release", () => led.off());

Note: The minimum version of Node.js that runs on Tessel 2 supports many ES2015 features, including Arrow Functions, so we’re using those here to simplify the program.

Variation: Using Complex Input to Control Output With Johnny-Five

Go back to your button.js and either type the changes or copy and paste the following code:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var led = new five.Led("a5");
  var button = new five.Button("a2");
  button.on("press", () => led.on());
  button.on("hold", () => led.blink(500));
  button.on("release", () => led.stop().off());
});

What You Should See

When the button is pressed, the LED turns on. If the button is held (longer than half a second), the button will start blinking. When the button is released, the LED will turn off.

Exploring the Code

This variation adds a handler for the Button object instance’s hold event.

When the button is held (defaults to 500ms hold time), change the output to blink in 500ms cycles:

language:javascript
button.on("hold", () => led.blink(500));

We need to make a small change to the release handler as well. When the button is released, we also need to stop any scheduled and running tasks (blink) before we turn the LED off:

language:javascript
button.on("release", () => led.stop().off());

Part II: Using Multiple Inputs to Control Multiple Outputs With Johnny-Five

Introduction

In Experiment 2, you saw how Johnny-Five’s Leds class could be used to manage a collection of Led objects. Similarly, the Buttons class can be used to control multiple Button instances. Buttons and Leds are both “Collections” classes. Instances of these Collections classes are Array-like objects that take care of instantiating the individual objects (Button, Led, e.g.) in their collection on your behalf.

The Collections class constructors are flexible. They’ll accept an Array that may contain pin numbers, configuration objects or existing instances of the component class they are initializing. Take a look at the following:

language:javascript
var a0 = new five.Led("a0");
var a1 = { pin: "a1", id: "some-custom-id" };
var a2 = "a2";
var leds = new five.Leds([a0, a1, a2]);

This would create an instance of the Leds class containing three Led instances, which each represent a single LED connected to a Tessel 2. These Collections classes do the busywork so you don’t have to.

The next few examples will use Collections classes to manage multiple inputs and outputs.

Hardware Hookup

The second circuit in this experiment builds on the first. Go ahead and add the additional components to match the wiring diagram:

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

Multiple Inputs and Outputs With Buttons

Open your favorite code editor, create a file called buttons-leds.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your buttons-leds.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var leds = new five.Leds(["b5", "b6"]);
  var buttons = new five.Buttons(["a5", "a6"]);

  buttons.on("press", (button) => {
    leds.off();
    leds[buttons.indexOf(button)].on();
  });
});

Type — or copy and paste — the following command into your terminal:

t2 run buttons-leds.js –single

The --single flag tells the T2 CLI to only deploy the single, specified file. This will preserve the existing code on the Tessel 2 while still deploying your new program changes, which can make the deployment faster.

What You Should See

Pressing the first button should cause the first LED to light up. Pressing the second button should cause the second button to light up. Either LED will stay lit until the other button is pressed.

Exploring the Code

As always, once the board object has emitted the ready event, we can initialize instances of the Leds and Buttons Collections classes to interact with our hardware:

language:javascript
var leds = new five.Leds(["b5", "b6"]);
var buttons = new five.Buttons(["a5", "a6"]);

Here’s another cool thing about these Collections classes: instead of registering handlers on events for each of the objects in the collection’s list individually (tedious and bug-prone), you can listen to them all with a single handler:

language:javascript
buttons.on("press", () => {
  // Yay! One of the buttons was pressed
});

OK, but which button?:

language:javascript
buttons.on("press", button => {
  // The first argument (`button`) passed to the callback handler function
  // is a reference to the `Button` instance that was pressed
  // So...turn on the corresponding LED somehow...
});

We’ve mentioned this before — Collections classes act like Arrays, so much so that they are referred to as “array-like” (seriously! That’s a technical term nowadays). Some of the ways they act like Arrays: they have a length property, and you can access their constituent objects using numeric indices. We saw this in Experiment 2.

That means that the first Button object can be accessed as buttons[0] and the second as buttons[1]. Ditto for leds[0] and leds[1] for the Led objects.

Collection ElementObject
leds[0]Led object instance (Port B, Pin 5)
leds[1]Led object instance (Port B, Pin 6)
buttons[0]Led object instance (Port A, Pin 5)
buttons[1]Led object instance (Port A, Pin 6)

Now we could explicitly turn on a specific LED, accessing it by index:

language:javascript
buttons.on("press", button => {
  leds[0].on();
});

But we want to dynamically determine which LED to turn on. If the first button is pressed (buttons[0]), we should turn on the first LED (leds[0]). That means we need to know the index (0 or 1) of the button that is being pressed so we can turn on the corresponding LED.

Well, good news. Buttons is array-like enough that we can use the indexOf method like so:

language:javascript
buttons.on("press", button => {
  // Use indexOf method, just like a real Array
  // This will return the numeric index for the `button` object in `buttons`
  // (either 0 or 1)
  var index = buttons.indexOf(button);
  leds.off();  // Turn 'em all off first
  leds[index].on(); // Turn on the correct LED
});

Or more succinctly:

buttons.on("press", (button) => {
  leds.off();
  leds[buttons.indexOf(button)].on();
});

Building Further

  • Create a game where an LED is lit after some random amount of time, and the player must turn it off before x amount of time has passed. The amount x may get shorter as the player progresses.

Reading Further

  • JavaScript– JavaScript is the programming language that you’ll be using:
  • Node.js– Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five– Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 5: Reading an SPDT Switch

Introduction

You got your first taste of processing digital input in Exercise 4 by working with a push button. This experiment introduces a Single-Pole, Double-Throw (SPDT) switch. You’ll see how the Johnny-Five Switch class can be used with a variety of physical switches, including a magnetic switch that you can use to protect your lunch from marauding fridge raiders. This experiment also includes the integration of a third-party module and service, Twilio, which you can use to send SMS text messages — now that’s leveling up!

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorial provides in-depth background on some of the hardware concepts in this experiment:

  • Switch Basics— Types of switches, what they do, and how they work

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x Standard LED (any color is fine)
  • 1x SPDT Switch
  • 1x Magnetic Door Switch
  • 1x 100Ω Resistor
  • 7x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
SPDT Mini Power Switch

COM-00102
$1.5
Magnetic Door Switch Set

COM-13247
$2.95
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introducing the Single-Pole, Double-Throw (SPDT) Switch

alt text

SPDTs have three legs: one common leg and two legs that vie for connection to the common leg. The common pin is in the middle. It’s always connected to one of the outside pins, but which pin it’s connected to depends on which way the switch is flipped. The state of the switch — “on” or “off” — is read from the common leg. A connected digital input pin on the Tessel will read HIGH when the common leg is electrically connected to the +3.3V leg on the switch; that means the switch is “on.” It will read LOW when the common pin is connected to the ground pin (switch in the “off” position).

Note: The circuit in this experiment doesn’t need a pull-down or pull-up resistor like the one in Experiment 4. That’s because the common pin in the switch is always connected to something. There’s never a “disconnected” state that can cause floating. There’s a nice tutorial about pull resistors if you’d like to learn more.

Hardware Hookup

This experiment has two wiring diagrams, but let’s not get ahead of ourselves! The first is below:

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Building the Switch Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Plug the LED in, be sure to note that the anode is towards the top of the breadboard with each leg plugged into its own row.
  2. Place the 100Ohm resistor so that one leg is in the same row of hole as the anode of the LED and spans the ditch plugging into the row adjacent to the LED.
  3. Using jumper wires connect the cathode of the LED to the ground rail of the breadboard and the a separate wire connecting the end of the resistor to Pin 5 of Port B on your Tessel.
  4. Insert the SPDT switch into the breadboard so that each of the 3 pins insert into their own rows.
  5. Using jumper wires connect the upper pin of the switch to the positive power rail, the lowest pin to the ground power rail and the center pin to Pin 5 on Port A of your Tessel. 6.Finally power the breadboard using jumper wires! connect 3.3V to the positive rail and GND to the ground rail.

Observing a Switch With Johnny-Five

Open your favorite code editor, create a file called switch.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your switch.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var spdt = new five.Switch("a5");
  spdt.on("close", () => console.log("Switch closed"));
  spdt.on("open", () => console.log("Switch opened"));
});

Type — or copy and paste — the following into your terminal:

t2 run switch.js

Note: The minimum version of Node.js that runs on Tessel 2 supports many ES2015 features, including Arrow Functions, which we will be using throughout this experiment to simplify your program code.

What You Should See

When you slide the switch back and forth, your terminal will display the appropriate message:

alt text

Exploring the Code

As in all previous experiments, once the board object has emitted the ready event, we can initialize an instance of the Switch class to interact with our hardware:

language:javascript
var spdt = new five.Switch("a5");

Next, create two event listeners: one for the close event (which means the switch is “on”) and one for the open event (the switch is “off”). These events are conceptually very similar to the Button events that we covered in Experiment 4. Buttons are, after all, a kind of switch too.

language:javascript
spdt.on("close", () => console.log("Switch closed"));
spdt.on("open", () => console.log("Switch opened"));

And that’s it! Flipping the switch back and forth will cause Switch closed and Switch opened messages to display in the console (your terminal window’s output).

Variation: Using a Switch to Control an LED with Johnny-Five

As a minor modification, create a new Led object and control its on/off state with the Switch. Type — or copy and paste — the following JavaScript code into your switch.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var led = new five.Led("b5");
  var spdt = new five.Switch("a5");
  spdt.on("close", () => led.on());
  spdt.on("open", () => led.off());
});

Type — or copy and paste — the following into your terminal:

t2 run switch.js

What You Should See

When the switch is in one position, the LED is off. When the switch is in its other position, the LED is on.

Exploring the Code

Just as we did in all previous experiments, once the board object has emitted the ready event, we can initialize instances of the Led and Switch classes to interact with our hardware:

language:javascript
var led = new five.Led("b5");
var spdt = new five.Switch("a5");

This time, instead of logging (displaying) messages, the Switch event handlers will turn the LED on or off, depending on which state the circuit is in:

language:javascript
spdt.on("close", () => led.on());
spdt.on("open", () => led.off());

Monitoring a Fridge With Johnny-Five

Ever had a pesky coworker who has a habit of swiping your lunch? Let’s try to catch her in the act! For this experiment, you’re going to make a surveillance device that will send us an SMS text message when a refrigerator door is opened.

Introducing the Magnetic Door Switch

In Experiment 4 and the first example in this experiment, you built circuits containing switches controlled by direct human contact: fingers pressing or flipping. The door switch included in the Johnny-Five Inventor’s Kit is a little different: it is sensitive to a magnetic field.

The switch assembly has two pieces. When the two halves of the switch assembly are very near each other, or touching, the switch is in one state. Moving the two halves more than 20mm apart from each other will cause the switch to change state. One half contains a magnet, and the other contains a reed switch, a switch that changes state when exposed to a magnetic field.

This type of two-piece switch is often used in home-security systems. One half of the switch is attached to a fixed surface, and the other half to a moving door or window. When the door or window is opened, the two halves are separated from each other, breaking the contact and changing the switch’s state.

Building the Circuit

Build the magnetic switch circuit using the wiring diagram:

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Using jumper wires, connect one half of the switch assembly to Port A, Pin 2 and the ground column of the breadboard’s power rail. It doesn’t matter which pin of the switch is connected to GND or the input pin — both orientations work fine.
  2. Plug in the LED. Connect the anode to Port A, Pin 5 through a 100Ω resistor. Connect the cathode to the ground column of the power rail using a jumper wire.
  3. Connect the Tessel’s GND pin to the breadboard’s power rail using a jumper wire.

Building a Prototype

Before we start sending SMS messages out into the ether, let’s use the circuit above to create a prototype. This will prove our hardware is set up correctly. For the moment, instead of dispatching a text message, we’ll indicate the switch’s status with an LED. We’ll turn the LED on when the “door opens” (switch halves are separated) and shut it off when the “door closes” (switch halves are near or touching).

Open your favorite code editor, create a file called intruder-alert.js and save it in the j5ik/ directory. Type — or copy and paste — the following JavaScript code into your intruder-alert.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var led = new five.Led("a5");
  var door = new five.Switch({
    pin: "a2",
    invert: true,
  });

  door.on("open", () => led.on());
  door.on("close", () => led.off());
});

Type — or copy and paste — the following command into your terminal:

t2 run intruder-alert.js

What You Should See

Opening and closing the magnet switch will turn the LED on and off, respectively.

Exploring the Code

There’s a small difference in how the Switch object is instantiated in this code example, compared with the SPDT example:

language:javascript
var door = new five.Switch({
  pin: "a2",
  invert: true,
});

In this case, we’re telling Johnny-Five to invert the switch, logically.

Consider the default state of the circuit in the SPDT example above and the pushbutton examples in Experiment 4. In those, when the switches are in their “off” position (or the button is not pressed), the associated digital input pin will read LOW.

Now, scroll back up and look at the wiring diagram image again for the magnetic door switch circuit. It would seem that when the two halves of the switch assembly are apart as shown, the circuit would be open and the digital pin would read LOW, like the earlier switch and button examples.

However, the internal wiring of this particular magnetic door switch works in such a way that the pin will read HIGH. When a switch or component has this kind of architecture, we say that it is pulled high—the circuit’s default, inactive state is HIGH rather than LOW.

The invert option tells Johnny-Five to invert its interpretation of the Switch’s states, such that HIGH reads correspond to the open event and LOW reads to the closed event. That way, pulling the two halves of the switch apart results in “open” and putting them together again is “closed,” which feels correct.

Note: Unless you pass a particular value for the type property, a Switch object instance will default to invert: true, so the behavior remains the same if you remove the invert:true from the code here.

Integrating SMS (Twilio) to the Surveillance Device

In order to enable SMS (text messaging), you’ll need to set up a trial account with Twilio:

  1. Go to https://www.twilio.com/try-twilio and sign up for an account

  2. Get your API credentials. Navigate to your account’s “dashboard”. Write down (or otherwise keep handy) both the Account SID and your Auth Token— you’ll need those for the program.

alt text

  1. Set up a Twilio phone number. Start by heading to the Phone Numbers dashboard page.

  2. Click the Get Started button

alt text

  1. Click the “Get your first Twilio phone number” button and walk through the steps.

alt text

  1. Write down the number; you’ll need this for the program too.

alt text

Twilio maintains an npm module that you can use. Install the Twilio module for Node.js by typing — or copying and pasting — the following command into your terminal:

npm install twilio

Type — or copy and paste — the following JavaScript code into your intruder-alert.js file:

language:javascript
var twilio = require("twilio");
var Tessel = require("tessel-io");
var five = require("johnny-five");
var board = new five.Board({
  io: new Tessel()
});

var accountSid = ""; // SID copied from www.twilio.com/console
var authToken = ""; // token copied from www.twilio.com/console

var sender = ""; // This is your Twilio phone number
var recipient = ""; // This is your own mobile phone number

var client = new twilio.RestClient(accountSid, authToken);

board.on("ready", () => {
  var door = new five.Switch({
    pin: "a2",
    invert: true,
  });

  door.on("open", () => {
    var details = {
      body: `Security Breach at ${Date.now()}`,
      from: sender,
      to: recipient,
    };

    client.messages.create(details, error => {
      if (error) {
        console.error(error.message);
      }
      // Success! Nothing else to do
    });
  });
});

Type — or copy and paste — the following into your terminal:

t2 run intruder-alert.js

When you remove the magnet, you should momentarily receive a text message warning you of an intruder!

Exploring the Code

The script instantiates a Twilio client object with the defined credentials. That object takes care of communicating back and forth with Twilio.

language:javascript
var accountSid = ""; // SID copied from www.twilio.com/console
var authToken = ""; // token copied from www.twilio.com/console

var sender = ""; // This is your Twilio phone number
var recipient = ""; // This is your own mobile phone number

var client = new twilio.RestClient(accountSid, authToken);

After the board is ready, a Switch is instantiated, just like before. But there is a change to the open event handler. When the door is opened:

door.on("open", () => {
  // 1. Define the details of the SMS to send
  // 2. Use the Twilio client to send the message
});

Fleshing that out:

language:javascript
door.on("open", () => {

  // SMS details
  var details = {
    body: `Security Breach at ${Date.now()}`,
    from: sender, // Twilio phone number
    to: recipient,  // You! (phone number)
  };

  // Send the SMS
  client.messages.create(details, error => {
    if (error) {
      console.error(error.message);
    }
    // Success! Nothing else to do
  });
});

The details object sets up a body for the text message (using a template literal and the JavaScript Date object), as well as sender and recipient phone numbers.

Then we rely on the Twilio client object for dispatching the message, invoking client.messages.create with the details object and also a callback function. If there is an error (the first argument to the callback function if so), log it to the console. Otherwise, we’re good—the message was sent successfully.

Building Further

  • Turn a time lapse camera on and off – use a switch to turn on a time lapse camera app using tessel-av.
  • Set an alarm – use a switch to turn an alarm clock app on and off

Reading Further

Experiment 6: Reading a Light Sensor

All experiments will require a connection to the internet for installing JavaScript module packages via `npm`. This connection is not required for deploying the programs to your Tessel 2, but is at least required as a one-time setup operation.

Introduction

This isn’t your first rodeo with an analog sensor—this experiment will build on what you learned in Experiment 3: Reading a Potentiometer.

In this experiment, you’ll meet a new component: photoresistors. Also called photocells or Light-Dependent Resistors (LDRs), these simple sensors change resistance depending on ambient light intensity. You’ll learn why you need to use an additional resistor in your circuit to be able to read values from the photoresistor. You’ll build a bar graph to display changing light conditions. Then you’ll make a light-sensitive nightlight.

Throughout this experiment, you’ll use Johnny-Five’s Light class to read data from the photoresistor, and, in multiple examples, you’ll see how changing the scale of the data read from the photoresistor can be useful in further manipulating or presenting that data.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x Photoresistor
  • 1x Standard LED (any color is fine)
  • 1x 10kΩ Resistor
  • 1x 100Ω Resistor
  • 6x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Mini Photocell

SEN-09088
$1.5
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introducing the Photoresistor

photoresistor

The resistance of a photoresistor changes depending on how much light is hitting it. When it’s really bright, the photocell has less resistance—it’s more conductive. When it’s dim, the photocell has more resistance.

The resistance changes, yes, but the Tessel 2 analog input pins respond to changing voltage. Fortunately, there’s a straightforward way to create a circuit that translates changes in resistance to changes in voltage: use a voltage divider.

A voltage divider is a circuit that uses a pair of resistors to translate an input voltage (Vin) into different (always lower) voltage (Vout). All of the voltage that goes into the circuit has to get “used up” by the components in between the two resistors; all of the supply voltage (3.3V in our case) must be accounted for. If R1 and R2 in a voltage-divider circuit have equal resistance (say, two 100Ω resistors), the voltage at Vout will be one-half of the input voltage, or 1.15V—each gobbles up half of the voltage.

Each resistor drops its share of the supply voltage, proportional to its share of the circuit’s total resistance. If R1 is 300Ω and R2 is 100Ω, Vout is one-quarter (25%) of the input voltage because three-quarters has already been snatched up by R1. See? The second resistor didn’t change; it has a static resistance. Meanwhile, the changing resistance of R1 is translated into voltage changes at Vout.

In this example’s circuit, the second resistor will be a 10kΩ resistor. It won’t change resistance. It’ll just chill. But the photoresistor—that’ll change resistance as light changes, changing its proportional resistance in the context of the whole circuit. So, voila!, voltage at Vout changes, too, and we can read that using the Tessel.

several ways of representing a voltage divider circuit

Several different schematic representations of a voltage divider

The photoresistor changes its resistance based on the light to which it is exposed. To use this with the Tessel 2 board, you will need to build a voltage divider with a 10kΩ resistor as shown in the wiring diagram for this experiment. The Tessel 2 board cannot read a change in resistance, only a change in voltage. A voltage divider allows you to translate a change in resistance to a corresponding voltage value.

The voltage divider enables the use of resistance-based sensors like the photoresistor in a voltage-based system. As you explore different sensors, you will find more resistance-based sensors that only have two pins like the photoresistor. To use them with your Tessel 2 board you will need to build a voltage divider like the one in this experiment. To learn more about resistors in general, check out our tutorial on resistors and also our tutorial on voltage dividers.

Note: Make sure you are using the 10kΩ resistor in your voltage divider with the sensors in this kit. Otherwise you will get odd and inconsistent results.

Hardware Hookup

Enough reading … let’s get this circuit built!

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Photoresistor Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Plug the photoresistor into the breadboard. It works fine in either orientation (it is not polarized). Connect a 10kΩ resistor between one leg of the photoresistor and ground. On the other side of the resistor, but in the same row, connect the photoresistor to Tessel 2’s Port A, Pin 7 with a jumper wire.
  2. Connect the photoresistor to the supply voltage column on the power rail using a jumper wire. Connect the other end of the resistor to the ground column on the power rail with a jumper wire.
  3. Plug in the LED. Make sure not to plug it in backward! The anode (longer leg) should be connected with a jumper wire to Port B, Pin 6 through a 100Ω resistor. Connect the LED’s cathode to the ground column on the power rail with a jumper wire.
  4. Use jumper wires to connect the Tessel’s 3.3V and GND pins to the power rail of the breadboard.

Observing Light Intensity With Johnny-Five

Before we get into bar charts, let’s take a look at the most basic observation example. Open your favorite code editor, create a file called light.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your light.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var light = new five.Light("a7");

  light.on("change", () => console.log(light.level));
});

Type—or copy and paste—the following into your terminal:

t2 run light.js

Like the first program in Experiment 3, this isn’t very interesting, but it does get us started! You’ll see values between 0.00 and 1.00 scroll by in your terminal. Cover the photoresistor with your hand to see the values decrease.

Exploring the Code

Once the board has emitted the ready event, hardware inputs are ready for interaction. The Johnny-Five Light class is made for the job:

language:javascript
var light = new five.Light("a7");

Then a handler function is registered for change events. When the sensor’s value changes, this function gets called.

language:javascript
light.on("change", () => console.log(light.level));

The handler function doesn’t do much yet; it just logs out the current value of the level attribute. level is the current value read from the analog input pin, as a percentage (e.g., 0.38 is 38% of a possible 100%).

Graphing Light Intensity With Johnny-Five and Barcli

For this experiment, you will be “bar chart graphing” light intensity values in your terminal using the Barcli module:

barcli

barcli [bahrk-lee]

Barcli is a simple tool for displaying real-time data in the console. Multiple instances of Barcli can be stacked to show multiple axes, sensors or other data sources in an easy-to-read horizontal bar graph.

In your terminal, type—or copy and paste—the following command:

npm install barcli

Next, open your favorite code editor, create a file called light-bar-chart.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your light-bar-chart.js file:

language:javascript
var Barcli = require("barcli");
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel(),
  // Experiment 3 explains these options
  repl: false,
  debug: false,
});

board.on("ready", function() {
  var graph = new Barcli({
    color: "white",
    label: "Light Level",
    range: [0, 1],
  });
  var light = new five.Light("a7");

  light.on("change", () => {
    graph.update(light.level);
  });
});

Type—or copy and paste—the following into your terminal:

t2 run light-bar-chart.js

Once the program starts up, the terminal should display something like this:

alt text

(This was produced by shining a small LED flashlight back and forth over the sensor. Results will vary by source and ambient light.)

Exploring the Code

To create a graph, first initialize a new instance of Barcli with a range of [0, 1] to match the range of light level values (see Experiment 3 for more background on barcli and scaling). To make the bar visually suggestive of “light level”, set the color to "white":

language:javascript
var graph = new Barcli({
  color: "white",
  label: "Light Level",
  range: [0, 1],
});

Now, update the change event-handler function:

language:javascript
var light = new five.Light("a7");

light.on("change", () => {
  graph.update(light.level);
});

Last, call graph.update(light.level) to update the chart with the most recent light level readings.

Variation: Building a Light-Sensing Nightlight

How about using a photoresistor to help determine when a nightlight should be turned on? The general idea is: when the room is dim, turn the light on. When the room is bright, turn the light off.

Open your favorite code editor, create a file called nightlight.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your nightlight.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var light = new five.Light({
    pin: "a7"
  });
  var nightlight = new five.Led("b6");
  light.on("change", () => {
    if (light.level < 0.5) {
      nightlight.on();
    } else {
      nightlight.off();
    }
  });
});

Type—or copy and paste—the following into your terminal:

t2 run nightlight.js

Cover and uncover the photoresistor with your hand to change its light readings.

What You Should See

Covering the photoresistor with your hand to block light should cause the nightlight to turn on, while shining a pen light onto the photoresistor or otherwise exposing it to bright light should make the nightlight turn off.

Exploring the Code

After the board is ready, and the light (photoresistor Light) and nightlight (Led) instances have been created, the next trick is to attach an event handler to the photoresistor’s change event:

language: javascript
light.on("change", () => {
  if (light.level < 0.5) {
    nightlight.on();
  } else {
    nightlight.off();
  }
});

light.level returns a the photo-sensor’s 10-bit value (0 - 1023) rescaled to a range between 0 and 1. If the room is dim(ish)—a light.level of less than 0.5—turn the nightlight on. Otherwise, turn it off.

Making the Nightlight Better

Ahem. That first attempt is a little inelegant, for a couple of reasons:

  • The values read from the light object are not going to span the full possible 10-bit range of 0–1023. Using the 10kΩ resistor in the voltage divider will result in output voltages that cover much of the 0–3.3V range, but not all. Also, you might not have the ability to expose the photoresistor to a fully dark condition or a fully bright one, depending on where you are doing your work.
  • Light levels near the threshold (light.level of 0.5, which is the same as light.value of 511 on a 0–1023 scale) can cause obnoxious blinking on and off of the LED.

We can do a little better. Try typing or pasting the following code into your nightlight.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var light = new five.Light("a7");
  var nightlight = new five.Led("b6");
  var dimmest = 1023;
  var brightest = 0;

  light.on("change", () => {
    var relativeValue;
    if (light.value < dimmest) {
      dimmest = light.value;
    }
    if (light.value > brightest) {
      brightest = light.value;
    }
    relativeValue = five.Fn.scale(light.value, dimmest, brightest, 0, 511);
    if (relativeValue <= 255) {
      nightlight.brightness(255 - relativeValue);
    } else {
      nightlight.off();
    }
  });
});

Now, once again type—or copy and paste—the following into your terminal:

t2 run nightlight.js

Once again cover and uncover the photoresistor or shine a penlight onto it.

What You Should See

At first you may see the nightlight blinking a little, but as the script calibrates and gathers readings, the range and scaling makes the nightlight behave more smoothly. As the photoresistor is covered with your hand, the nightlight should fade to brighter. As you remove your hand, it should fade back down to off.

Exploring the Code

Outside of the event-handling function, we create a couple of variables to keep track of the dimmest and brightest values the light object encounters, over time:

language:javascript
var dimmest = 1023;
var brightest = 0;

Now let’s look at the first part of the updated change event-handling function:

language:javascript
light.on("change", () => {
  var relativeValue; // We'll get to this in a moment
  if (light.value < dimmest) {
    dimmest = light.value;
  }
  if (light.value > brightest) {
    brightest = light.value;
  }
  // ...
});

This keeps track of the lowest and highest readings from the photoresistor over time. If the value of the photoresistor is dimmer (lower) than the current value of dimmest, update dimmest to the new value. Likewise, if the value of the photoresistor is brighter (higher) than the current value of brightest, update brightest to the most recent value. This happens on each iteration, assuring that dimmest and brightest are always up to date with the low and high bounds of all readings.

The current light.value falls somewhere in between dimmest and brightest (inclusive). [dimmest, brightest] is, in fact, the scale of our readings so far. We need to take the information gathered so far and figure out whether the nightlight should be on at all, and, if so, how bright it should be.

Here are some rules and background:

  1. The nightlight shouldn’t be on at all if the current reading falls in the top (brighter) half of the range of all readings ever seen.
  2. The brightness method on Led object instances takes an 8-bit number (0–255), where 0 is off and 255 is full brightness.
  3. The nightlight should be brightest (255) when the photoresistor is at its lowest reading (dimmest).
  4. The nightlight should dim as photoresistor readings increase from dimmest, dimming to 0 (off) at the midpoint of the [dimmest, brightest] range.

five.Fn.scale(value, oldLow, oldHigh, newLow, newHigh) is a method that remaps a value from its old range to a new range. The following line rescales the current value, based on its current range ([dimmest, brightest]) to a range representing 9-bit numbers ([0, 511]).

language:javascript
relativeValue = five.Fn.scale(light.value, dimmest, brightest, 0, 511);

Per rule 1 above—only values in the lower half of the scale should cause the LED nightlight to be on. So:

language:javascript
if (relativeValue <= 255) {
  // Set the nightlight to some brightness between 0 and 255
  // Note the nice 8-bit number we have to work with now
} else {
  nightlight.off();
}

relativeValue values between 0 and 255 should cause the nightlight to be on. However, the higher the relativeValue is in that range, the dimmer the LED should be. We can adjust for that by subtractingrelativeValue from 255 to get the appropriate brightness for the nightlight:

language:javascript
if (relativeValue <= 255) {
  nightlight.brightness(255 - relativeValue);
} else {
  nightlight.off();
}

Building Further

  • Try adding a potentiometer to the circuit, and use it to control the ambient-light threshold at which the nightlight turns on.
  • Trying using tessel-av, an external sound adapter and a set of speakers to make audible notifications for various light levels.
  • Also with tessel-av, use light level to trigger the start and stop of video surveillance. Look at using IFTTT Maker Channel to alert you when someone turns on the lights in your room.

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using.
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 7: Animating LEDs

Introduction

In Experiments 1 and 2 you learned how to control one LED, and then several LEDs, using the Johnny-Five Ledblink(), on() and off() methods. We also quickly looked at pulse(), which is essentially a prepackaged, commonly used “animation” for LEDs. In this experiment, you’ll learn how to do basic LED fading and then make use of built-in easing functions.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorial provides in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 3x Standard LEDs (one each of red, green and blue)
  • 3x 100Ω Resistors
  • 4x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Hardware Hookup

The circuit below is a simplified version of Experiment 2; each LED is wired in the same way, but we are using three LEDs so you can focus on the programming aspects of animation.

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Multiple-LED Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Connect the LEDs to the breadboard. Make sure to connect their cathode (shorter) legs to sockets in the ground column of the power rail.
  2. Plug in the 100Ω resistors in terminal rows shared with the anode (longer) legs of the LEDs, spanning the central notch.
  3. Connect jumper wires between the resistors and the Tessel 2. You may find it helpful to use colors that correspond to the LED’s color.
  4. Use a jumper wire to connect the ground power rail of the breadboard to the Tessel 2’s GND pin.

Fading In

Open your favorite code editor, create a file called fade-in.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your fade-in.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var leds = new five.Leds(["a5", "a6", "b5"]);
  var index = 0;

  var fader = () => {
    if (index < leds.length) {
      leds[index++].fadeIn(1000, fader);
    }
  };
  fader();
});

Type—or copy and paste—the following into your terminal:

t2 run fade-in.js

What You Should See

Starting with the red LED, each LED will fade in, taking one second each.

Exploring the Code

Once the board has emitted the ready event, instantiate a new Leds object and a variable called index, with an initial value of 0:

language:javascript
var leds = new five.Leds(["a5", "a6", "b5"]);
var index = 0;

Next, create a function called fader:

language:javascript
var fader = () => {
  if (index < leds.length) {
    leds[index++].fadeIn(1000, fader);
  }
};

First, fader() checks that the value of index is less than the total number of LEDs in leds, meaning that it is a valid index for one of the Led objects leds contains. Then, it will do this:

language:javascript
leds[index++].fadeIn(1000, fader);

All righty, there are a few things going on in that line. Let’s start with index++. That little chunk means “look up the current stored value of this variable, then, afterward, increase its stored value by 1”.

leds[index++].fadeIn(...) invokes fadeIn on leds[index], but if we were to look at the value of index afterward, it would have increased by 1. Basically, this saves us a line; the following is equivalent:

language:javascript
led[index].fadeIn(...);
index = index + 1;

Right. Now the arguments being passed to led.fadeIn:

language:javascript
leds[index++].fadeIn(1000, fader);

The first, 1000, is how long (in milliseconds) the fading-in should take. The second is a callback function to invoke once the fade operation is complete. The fader function passes itself as a callback function to led.fadeIn. This can feel mind-twisting if you’re new to it, but is perfectly safe and common. It’s called asynchronous recursion.

The next time fader is called, the index has incremented by 1!

CallindexLED
10Red
22Green
23Blue
43N/A

The fourth time fader is called will be the last—the test for index < leds.length will fail.

Lastly, to kick off the async recursion that will light these LEDs up, we must call fader() explicitly:

language:javascript
fader();

Variation: Fading In, Fading Out

Instead of leaving the LEDs turned on, let’s fade them in and then out again, before moving on to the next LED. Open your favorite code editor, create a file called fade-in-out.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your fade-in-out.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var leds = new five.Leds(["a5", "a6", "b5"]);
  var index = 0;

  var fader = () => {
    if (index < leds.length) {
      leds[index].fadeIn(1000, () => {
        leds[index++].fadeOut(1000, fader);
      });
    }
  };
  fader();
});

Type—or copy and paste—the following into your terminal:

t2 run fade-in-out.js

What You Should See

Starting with the red LED, each LED will:

  1. Fade in, lasting one second.
  2. Fade out, lasting one second.
  3. Move onto the next LED.

Exploring the Code

The changes are all contained within part of the fader function:

language:javascript
leds[index].fadeIn(1000, () => {
  leds[index++].fadeOut(1000, fader);
});

Let’s step through this. First, leds[index] has its fadeIn method invoked. fadeIn is told to take 1000 milliseconds (a second) to do the fading. A callback function is provided for fadeIn to invoke once the fading-in is all done. In this callback function, fadeOut is invoked on leds[index] (and index is incremented). The fading-out is set to take one second, and told to invoke fader when it’s through, starting the whole cycle again on the next index.

Variation: Cross Fading

This time, instead of waiting for the previous LED to fade out, the next LED in the Leds instance will fade in at the same time as the previous one is fading out. Open your favorite code editor, create a file called cross-fade.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your cross-fade.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var leds = new five.Leds(["a5", "a6", "b5"]);
  var index = 0;

  var fader = () => {
    if (index > 0) {
      leds[index - 1].fadeOut(1000);
    }
    if (index < leds.length) {
      leds[index++].fadeIn(1000, fader);
    }
  };
  fader();
});

Type—or copy and paste—the following into your terminal:

t2 run cross-fade.js

What You Should See

Starting with the red LED, each LED will:

  1. Fade in over one second.
  2. Move onto the next LED. Fade out the previous LED while fading in the current LED.

Exploring the Code

Again, no changes to the initial setup, but a new piece has been added before the (index < leds.length) condition:

language:javascript
if (index > 0) {
  leds[index - 1].fadeOut(1000);
}

This fades out the previous LED (if there is one). There’s no callback function provided because we don’t need one. That LED is done.

Next, the current LED is faded in:

language:javascript
leds[index++].fadeIn(1000, fader);

This time, fader is passed as a callback to start the next cycle (fading this LED out, fading in the next LED…) after this LED is done fading in.

Introducing Easing

led.fadeIn and led.fadeOut apply a mathematical algorithm that determines the amount of brightness to change over time. fadeIn and fadeOut don’t actually fade in and out linearly; that is, there’s an easing function applied to make the fading feel more natural and smooth. By default, the easing function used is out sine (though, if you want, there is an available easing function linear that does what it sounds like it would do). out sine, graphically, looks like this:

alt text

What other easing functions can we use?

alt text

So, what do those look like? Let’s write some code and find out. Open your favorite code editor, create a file called fader-easing.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your fader-easing.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var leds = new five.Leds(["a5", "a6", "b5"]);
  var duration = 2000;

  var fader = () => {
    if (!easingFunctions.length) {
      process.exit();
    }
    var easing = easingFunctions.shift();

    leds.fadeOut(500, () => {
      leds.fadeIn({ easing, duration }, fader);
    });
  };

  fader();
});

var easingFunctions = [
  "linear","inQuad","outQuad","inCube","outCube","inOutCube","inQuart","outQuart","inOutQuart","inQuint","outQuint","inOutQuint","inExpo","outExpo","inOutExpo","inCirc","outCirc","inOutCirc","inBounce","outBounce","inOutBounce",
];

Type—or copy and paste—the following into your terminal:

t2 run fader-easing.js

What You Should See

All three LEDs will simultaneously demonstrate each easing function.

Exploring the Code

The first major difference in this program is the list of easing functions that follows the board’s ready event handler registration. Those functions are built in to Johnny-Five.

Within the board’s ready event, and after the instantiation of the Leds object, we’ve declared a duration variable, with a value of 2000. This is going to be used as a time value in milliseconds.

language:javascript
var duration = 2000;

Next, the familiar fader function definition. However, the internal operations have changed. The program is designed to iterate through each easing function and display it as an “animation” of our leds:

language:javascript
var fader = () => {
  // 1
  if (!easingFunctions.length) {
    // 1.1
    process.exit();
  }
  // 2
  var easing = easingFunctions.shift();

  // 3
  leds.fadeOut(500, () => {
    // 4, 5
    leds.fadeIn({ easing, duration }, fader);
  });
};

Here’s what it does:

  1. It checks that there are entries remaining in easingFunctions array.
  2. If not, then there’s nothing left to do, so it exits the program.
  3. It Removes the first entry in the easingFunctions and shifts the remaining entries to the beginning. This is accomplished by calling the shift() method of the easingFunctions array.
  4. It fades out all of the leds over 500ms. Since we’re passing a number as the first argument to fadeOut, the default easing function will be used. (We could pass an object that specifies an easing function for fading out if we wanted). The second argument is a callback function to invoke when the fadeOut operation completes.
  5. Once that operation completes, and the callback function is invoked, the next operation is an invocation of the leds.fadeIn(...) method with two arguments: an object containing properties specifying both an easing and a duration in milliseconds for which the operation should run, and a callback function, which also happens to be our fader function. This means that once the fadeIn easing operation completes, the fader function is called, which starts us back at step 1 of this list.

Note: leds.fadeIn({ easing, duration }, fader) is functionally equivalent to leds.fadeIn({ easing: easing, duration: duration }, fader). The former uses object property shorthand.

Animating with Keyframes

So far you’ve been working with higher-level abstraction of easing capabilities; now it’s time to see how that capability is implemented. Johnny-Five provides another class called Animation that produces instances for controlling one or more components. To give you an idea of what the Animation class can provide, take a look at this mind-blowing project, created by the author of the Animation class, Donovan Buck:

What you’re seeing in the video is a series of static gaits, executed by “animating” the position of 18 servos. Animations are built from one or more segments.

segments can be defined with many optional properties to tweak the behavior, but the most basic and important options are:

OptionDescriptionDefault
durationthe duration of the segment, in milliseconds1000
cuePoint Array of values between 0 and 1, representing the proportional time points along the duration of the segment for each keyframe[0,1] (this argument may be omitted if there are only two keyframes)
keyFrames Array of values representing keyframes. Required.
onComplete Callback function to invoke when segment animation is complete

A keyframe defines the state of the component at a given snapshot in time. In the case of LEDs, the most relevant state attribute is intensity, the brightness of the LED scaled to [0, 100].

Let’s take a look at a simplified version of the animation that ran for our fader programs. Open your favorite code editor, create a file called keyframes-fade-in.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your keyframes-fade-in.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var led = new five.Led("a5");
  var animation = new five.Animation(led);

  animation.enqueue({
    duration: 2000,
    keyFrames: [
      { intensity: 0 },
      { intensity: 100}
    ],
    oncomplete() {
      console.log("Done!");
    }
  });
});

Type—or copy and paste—the following into your terminal:

t2 run keyframes-fade-in.js

What You Should See

The red LED will fade in.

Exploring the Code

language:javascript
var animation = new five.Animation(led);

A new animation instance is created, and it is passed the led object. That’s what we’ll be animating.

language:javascript
animation.enqueue({
  duration: 2000,
  keyFrames: [
    { intensity: 0 },
    { intensity: 100}
  ],
  oncomplete() {
    console.log("Done!");
  }
});

animation.enqueue(...) is used to add the animation segment (defined in the passed object) to the animation queue. This causes it to start playing, as it is the only animation in the queue and queues are auto-play.

When the animation is complete, “Done!” will be displayed in the console.

Animating Multiple LEDs with Keyframes

Open your favorite code editor, create a file called keyframes-multiple.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your keyframes-multiple.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var leds = new five.Leds(["a5", "a6", "b5"]);
  var animation = new five.Animation(leds);

  var animateForever = () => {
    animation.enqueue({
      duration: 2000,
      cuePoints: [0, 0.05, 1.0],
      keyFrames: [
        [ {intensity: 100}, {intensity: 0}, {intensity: 100}],
        [ {intensity: 0}, {intensity: 100}, {intensity: 0} ],
        [ {intensity: 100}, {intensity: 0}, {intensity: 100} ],
      ],
      oncomplete() {
        console.log("Do it again!");
        animateForever();
      }
    });
  };
  animateForever();
});

Type—or copy and paste—the following into your terminal:

t2 run keyframes-multiple.js

What You Should See

The two outer LEDs will animate in one style, while the inner LED will have a different animation. Each time the animation repeats, “Do it again!” displays in the console and the animation is enqueued and played again.

Exploring the Code

First, the code instantiates a new Leds object with three Leds. It passes that Leds object when instantiating a new Animation object:

language:javascript
var leds = new five.Leds(["a5", "a6", "b5"]);
var animation = new five.Animation(leds);

The animateForever function enqueues a segment object:

var animateForever = () => {
  animation.enqueue({
    duration: 2000,
    cuePoints: [0, 0.05, 1.0],
    keyFrames: [
      [ {intensity: 100}, {intensity: 0}, {intensity: 100}],
      [ {intensity: 0}, {intensity: 100}, {intensity: 0} ],
      [ {intensity: 100}, {intensity: 0}, {intensity: 100} ],
    ],
    oncomplete() {
      console.log("Do it again!");
      animateForever();
    }
  });
};

The cuePoints are not distributed equally. The second keyframe cue point is at 0.05 (instead of 0.5, which would be an even step). Thus: the second keyframe will apply very quickly after the first. Then there is a longer gap between the second and third keyframes (0.05 to 1.0).

The keyFrames here is a 2-dimensional Array (an Array of Arrays). Each individual keyframe Array applies to one LED. The first and third LEDs share the same keyframes (bright, dark, then bright again) while the second LED is inverted (dark, bright, dark).

The oncomplete function logs a message to the console and then invokes animateForever again. The animation loops and loops …

Building Further

  • Experiment with more elaborate, longer-running keyframe sequences.

Reading Further

  • JavaScript– JavaScript is the programming language that you’ll be using:
  • Node.js– Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five– Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 8: Driving an RGB LED

Introduction

You know what’s even more fun than a blinking LED? Changing colors with one LED. RGB (Red-Green-Blue) LEDs have three different color-emitting diodes that can be combined to create all sorts of colors. In this circuit, you’ll learn how to use an RGB LED to create unique color combinations. Depending on how bright each diode is, nearly any color is possible!

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorial provides in-depth background on some of the hardware concepts in this experiment:

  • LEDs (Light-Emitting Diodes)— LEDs are found everywhere. Learn more about LEDs and why they are used in so many products all over the world.

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x LED, RGB Common Cathode
  • 3x 100Ω Resistors
  • 5x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - RGB Clear Common Cathode

COM-00105
$1.95
1
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introducing the Red-Green-Blue (RGB) LED

alt text

The Red-Green-Blue (RGB) is three LEDs in one. By controlling the intensities of each of the three component colors individually, you can create all of the colors of the rainbow. The RGB LED in your kit is a common-cathode RGB LED. Each of the three shorter legs controls an individual color (red, green or blue). The fourth, longer leg is a shared ground—-the common cathode. In contrast to standard individual LEDs, the cathode leg on a common-cathode RGB LED is longer than the other legs.

But which leg is which color? Pick up the RGB so that the longest leg (common ground) is aligned to the left as shown in the graphic below. From left to right, the pins are: red, ground (common cathode), green, blue.

RGB

Hardware Hookup

Ready to start hooking everything up? Check out the wiring diagram and hookup table below, to see how everything is connected.

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the RGB LED Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

Note: Each color's pin needs its own current-limiting resistor. You'll need three resistors to wire a single common-cathode RGB LED.
  1. Connect the RGB LED to the breadboard as shown. The legs, top to bottom, will be red, ground, green, blue – with each leg in its own row on the breadboard. Remember: the cathode (ground) leg is the longest leg.
  2. Connect a 100Ω resistor across the center gap in each component color’s row.
  3. On the far side of the resistor from each color leg, use jumper wires to connect each color to a pin on the Tessel 2. Red should connect to Port A, Pin 5. Green: Port A, Pin 6. Blue: Port B, Pin 5.
  4. Connect the ground (cathode) leg of the RBG LED to the Tessel’s GND pin using a jumper wire.

Cycling Colors on Your RBG LED With Johnny-Five

Open your favorite code editor, create a file called rgb-led.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your rgb-led.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var led = new five.Led.RGB({
    pins: {
      red: "a5",
      green: "a6",
      blue: "b5",
    }
  });

  var index = 0;
  var rainbow = ["white", "black", "red", "orange", "yellow", "green", "blue", "indigo", "violet"];

  board.loop(1000, () => {
    led.color(rainbow[index]);
    index = index + 1;
    if (index === rainbow.length) {
      index = 0;
    }
  });
});

Type—or copy and paste—the following into your terminal:

t2 run rgb-led.js

What You Should See

The RGB LED should loop through the colors in the rainbow Array.

Exploring the Code

After the board is ready, a new Led.RGB is instantiated. We need to tell Johnny-Five which pins each of the RGB LED’s colors are connected to:

language:javascript
var led = new five.Led.RGB({
  pins: {
    red: "a5",
    green: "a6",
    blue: "b5",
  }
});

Next, a couple of variables are initialized: one to keep track of an Array index for looping, another an Array of colors to display with the RGB LED:

language:javascript
var index = 0;
var rainbow = ["white", "black", "red", "orange", "yellow", "green", "blue", "indigo", "violet"];

Then, similar to looping in Experiment 7 and other previous experiments:

language:javascript
board.loop(1000, () => {
  led.color(rainbow[index]);
  index = index + 1;
  if (index === rainbow.length) {
    index = 0;
  }
});

The loop (see Experiment 2 method will call our code every second. Inside the loop we take the next color name from the rainbow array and pass it to the led’s color() method.

There are a number of ways you can tell the RGB Led object’s color method what color to use. One of those ways is to use a string. You can pass any valid CSS color name. The strings in the rainbow Array are all valid CSS colors.

Setting Specific Colors With Johnny-Five

The following two lines do the same thing:

language:javascript
led.color("red");
led.color([255, 0, 0]);

In the second line, an 8-bit value (0–255) is passed for each of the three component colors (red, green, blue).

Go back to your rgb-led.js and either type or copy and paste the following:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var led = new five.Led.RGB({
    pins: {
      red: "a5",
      green: "a6",
      blue: "b5",
    }
  });

  led.color(0, 255, 255);
});

Type—or copy and paste—the following into your terminal:

t2 run rgb-led.js –single

The --single flag tells the T2 CLI to only deploy the single, specified file. This will preserve the existing code on the Tessel 2, while still deploying your new program changes. This can make deployment faster.

What You Should See

The LED should be cyan.

Exploring the Code

language:javascript
led.color(0, 255, 255);

This line sets red to 0, green to 255 and blue to 255. The resulting color is cyan.

Animating an RGB LED With Keyframes

In Experiment 7 you learned about keyframe animations, so let’s see what we can do with a basic set of keyframes and the RGB LED.

Open your favorite code editor, create a file called keyframes-rainbow.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your keyframes-rainbow.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var rgb = new five.Led.RGB(["a5", "a6", "b5"]);

  var animation = new five.Animation(rgb);

  var rainbow = () => {
    animation.enqueue({
      loop: true,
      duration: 6000,
      cuePoints: [ 0, 0.16, 0.32, 0.5, 0.66, 0.83, 1 ],
      keyFrames: [
        // Any valid "color" argument can be used!
        {color: "red"},
        [255, 99, 0],
        {color: "ffff00"},
        {color: { red: 0x00, green: 0xFF, blue: 0x00 } },
        {color: "indigo"},"#4B0082",
      ],
      oncomplete: rainbow
    });
  };
  rainbow();
});

What You Should See

The RGB LED will cycle through the colors in the rainbow repeatedly, like the first rainbow example. However, instead of abruptly changing from color to color, the LED will display a cross-fading effect, smoothly moving from one color to the next.

Exploring the Code

In the first two examples, two different color values were used:

language:javascript
led.color("red");
led.color([255, 0 0]);

The keyframes in this example use yet more valid color values:

language:javascript
keyframes: [
  // Any valid "color" argument can be used!
  {color: "red"},
  [255, 99, 0],
  {color: "ffff00"},
  {color: { red: 0x00, green: 0xFF, blue: 0x00 } },
  {color: "indigo"},"#4B0082",
]

Explore the many ways to define color in Johnny-Five!

Troubleshooting

LED Remains Dark or Shows Incorrect Color?

When the code runs you should see your LED go through the colors of the rainbow. If any of the primary colors (red, green or blue) don’t light up, check your wiring and try again. With the four pins of the LED so close together, it’s sometimes easy to misplace one. Double check each pin is where it should be.

Building Further

The LED.RGB class has many interesting methods:

  • Change the intensity with the intensity() method.
  • Control with the on() and off() methods.
  • Build a visual thermometer using the BME280 with red representing “hot,” green “room temperature” and blue “cold.”

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using.
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 9: Using an H-Bridge Motor Controller

Introduction

Motors are simultaneously simple and complicated. Simple because they’re a basic design: run current through ‘em and they spin. Reverse the direction of the current, and they spin the other way. Give 'em more current, and they spin faster. But to choreograph the speed and direction of a motor or motors—that takes a little more doing.

In this experiment, you’ll meet a device called an H-Bridge. It’s a kind of sophisticated switch that lets you control up to two motors at a time. You can use an SPDT switch (like we used in Experiment 5: Reading an SPDT Switch to control the direction of the motors, and a potentiometer (Experiment 3: Reading a Potentiometer to control the speed.

We hope you are buckled in because this is going to be a wild ride!

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Tessel 2 5V wall adapter
  • 1x Breadboard
  • 1x SparkFun Motor Driver
  • 2x Hobby Gear Motor
  • 1x Switch
  • 1x Potentiometer
  • 20x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
SparkFun Motor Driver - Dual TB6612FNG (1A)

ROB-09457
$8.95
14
Trimpot 10K with Knob

COM-09806
$0.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
SPDT Mini Power Switch

COM-00102
$1.5
Hobby Gearmotor - 200 RPM (Pair)

ROB-13302
$3.95
Tessel 2

DEV-13841
$44.95

Introducing the SparkFun Motor Driver

alt text

The SparkFun Motor Driver is a small circuit board that contains circuitry for controlling one or two motors at once. At the heart of the driver board is an H-Bridge, which allows you to control both direction and speed.

The H-Bridge board has 16 pins (don’t panic; we’ll guide you through the hookup). The pin names are printed on the bottom of the controller board:

alt text

PWMA PWM signal for controlling the speed of motor A
AIN2 Direction pin 2 for motor A
AIN1 Direction pin 1 for motor A
STBY Standby HIGH for board on, LOW for board off
BIN1 Direction pin for motor B
BIN2 Direction pin 2 for motor B
PWMB PWM signal for controlling the speed of motor B
GND Ground
VM Motor power source 5V to 14V
VCC Chip voltage (3.3V)
GND Ground
A01 Motor A connection
A02 Motor A connection
B02 Motor B Connection
B01 Motor B Connection
GND Ground

Hardware Hookup

Are you ready to get your motor revving? Let’s get the circuit built first!

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the H-Bridge Motor Circuit

Deep breaths. This circuit isn’t so challenging to build—just pay attention and take it slowly. Anytime you work with motors, you have to be a smidge more careful about power sources. Motors cause power spikes, and need to be isolated from the (more delicate) circuitry in the Tessel and (potentially) your other components. You’ll notice that there are two power sources for this project: 5V (VM) from the wall adapter for the motors, 3.3V from the Tessel 2 for the rest of the circuit (both share a common ground—that’s normal). Anyway, here are a few warnings:

It's important to use the 5V wall adapter for your Tessel in this exercise instead of powering your board over USB from your computer. When motors start up, they cause spikes in current draw that can overwhelm your computer's USB port (symptom: the program crashes). If your Tessel 2 isn't on your local WiFi network yet, now's the time to set that up.
CAUTION: Take care when building circuits containing motors. In this experiment, the motors are provided with a separate power source (5V) — we need to be sure to keep motor voltage (MV) isolated from other circuitry. Accidentally using MV to power other circuitry may cause irreparable damage to your Tessel 2 board!

While building this circuit, refer to the wiring diagram and the images of the H-Bridge’s pins above. Keep in mind that the photo of the H-Bridge board’s different pins shows the bottom of the board. When the board is plugged in to the breadboard, the pins are flipped left to right. The steps below take that into account.

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Connect the H-Bridge board to the breadboard. Make sure to orient it in the direction shown in the diagram. The board should span the center notch.
  2. Using jumper wires, make connections between the H-Bridge and the power rail of the breadboard. The following steps assume you are looking at the H-Bridge board from the top, once it is connected to the breadboard.
    1. Connect the VCC pin (left side, second from top) to the supply power rail.
    2. Connect STBY (right side, fourth from top) to the supply power rail.
    3. Connect the three GND pins to the power rail. On the H-Bridge board, looking from the top, these pins are:
      1. Left side, third pin from top
      2. Left side, bottom pin
      3. Right side, bottom pin
  3. Connect the motors to the motor connection pins on the H-Bridge.
    1. Connect motor A’s red and black wires to the H-Bridge’s left side, fourth and fifth pins respectively.
    2. Connect the second motor’s red and black wires to the H-Bridge’s left side, sixth and seventh pins, respectively.
  4. Using jumper wires, connect H-Bridge pins for controlling motor A to pins on the Tessel 2.
    1. Connect the H-Bridge’s PWMA pin (top right) to Tessel’s Port A, Pin 5.
    2. Connect the H-Bridge’s AIN2 pin (right side, second from top) to Tessel’s Port A, Pin 4.
    3. Connect the H-Bridge’s AIN1 pin (right side, third from top) to Tessel’s Port A, Pin 3.
  5. Using jumper wires, connect H-Bridge pins for controlling motor B to pins on the Tessel 2.
    1. Connect the H-Bridge’s PWMB pin (right side, second from bottom) to Tessel’s Port B, Pin 5.
    2. Connect the H-Bridge’s BIN2 pin (right side, third from bottom) to Tessel’s Port B, Pin 4.
    3. Connect the H-Bridge’s BIN1 pin (right side, fourth from bottom) to Tessel’s Port B, Pin 3.
  6. Connect the potentiometer to the breadboard. Connect its ground and power pins to the power rail of the breadboard, using jumper wires. Connect its third pin to Tessel’s Port B, Pin 0.
  7. Connect the SPDT switch to the breadboard. Connect its ground and power pins to the power rail of the breadboard, using jumper wires. Connect its third pin to Tessel’s Port A, Pin 0.
  8. Connect 3.3V power and ground from the Tessel 2’s 3.3V and GND pins to the breadboard’s power rail using jumper wires.
  9. Connect 5V power to the H-Bridge board’s VM (motor voltage) pin. Using a jumper wire, connect the H-Bridge VM pin (left side, top pin) to the 5V pin on the Tessel 2. If you’re using the J5IK version of the Tessel 2, headers will be pre-soldered to the 5V power pins. On the Tessel board, the 5V pin is the bottom pin in the column of three pins in the header.

Spinning a Single Motor at Half Speed With Johnny-Five

To control a motor’s speed and direction requires three pins per motor. We’ll start by controlling just one of the two motors.

While the circuit you created above includes both motors from your kit, as well as a switch and potentiometer, let’s look at some basic code to control only one of them with just code. Open your favorite code editor, create a file called motor-single.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your motor-single.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var motor = new five.Motor([ "a5", "a4", "a3" ]);

  motor.forward(128);
});

Type—or copy and paste—the following into your terminal:

t2 run motor-single.js

What You Should See

When this program runs, you will see that one of your motors is spinning at half speed. The speed is measured in terms of an 8-bit range: 0 is effectively stopped and 255 is top speed.

Exploring the Code

As with all Johnny-Five programs, after the board object has emitted the ready event, we can initialize a Motor instance:

language:javascript
var motor = new five.Motor([ "a5", "a4", "a3" ]);

Let’s first talk about the argument that’s passed to the Motor constructor:

language:javascript
[ "a5", "a4", "a3" ]

Undoubtedly you will recognize that these are pin names, but why these three pins? What do they mean?

To control a motor’s speed and direction requires three pins per motor:

In this case, we’re using a directional, dual-motor H-Bridge controller, which requires three pins per motor:

  1. One pin to control the speed of the motor.
  2. One pin to make the motor go in one direction.
  3. One pin to make the motor go in the opposite direction.

The speed of the motor is controlled using PWM (Pulse Width Modulation). The two direction pins are set HIGH or LOW to dictate the direction the motor spins.

Terminology for this stuff is a bit all over the place. Some guides and datasheets will show direction as clockwise or cw. Counter direction is also called counter-clockwise or ccw. It would be impossible for Johnny-Five to support all variations verbatim, so the Motor class attempts to simplify this by calling them pwm, direction (dir) and counter direction (cdir).

Control Type/RoleJohnny-Five Motor Pin NameBreakout Pin (Printed)
PWMpwmPWMA or PWMB
Counter DirectioncdirAIN2 or BIN2
DirectiondirAIN1 or BIN1

Different HIGH-LOW combinations on the dir and cdir pins cause different things to happen with the motor. The following table takes into account info from the TB6612FNG datasheet to illustrate how these pins are manipulated by the Motor instance internally:

IN1IN2PWMResults
HH~Short Brake
LH~CCW
HL~CW
LL~Stop

OK, back to our code. Johnny-Five does as much as possible to simplify the code that you write, so this:

language:javascript
[ "a5", "a4", "a3" ]

Means:

language:javascript
[ pwm, dir, cdir ]

And is actually just a short hand for writing out the full pin definition:

language:javascript
var motor = new five.Motor({
  pins: {
    pwm: "a5",
    dir: "a4",
    cdir: "a3",
  }
});

Neat, right?!

The next line simply instructs the motor to spin “forward” (which is relative, based on how the two motor wires are attached to the output pins) at half speed (motor.forward(...) takes an 8-bit number, so 255 would be FULL STEAM AHEAD):

language:javascript
motor.forward(127);

And that’s it!

Variation: Control a Single Motor Speed and Direction With Johnny-Five

Open your favorite code editor, create a file called motor-speed-direction.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your motor-speed-direction.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var spdt = new five.Switch("a0");
  var throttle = new five.Sensor("b0");
  var motor = new five.Motor([ "a5", "a4", "a3" ]);

  spdt.on("open", () => {
    motor.stop().forward(motor.speed());
  });

  spdt.on("close", () => {
    motor.stop().reverse(motor.speed());
  });

  throttle.on("change", () => {
    motor.speed(throttle.value >> 2);
  });
});

Type—or copy and paste—the following into your terminal:

t2 run motor-speed-direction.js

What You Should See

Motor A can be controlled in two ways:

  1. When you flip the switch, the motor will change direction, maintaining its current speed.
  2. When the potentiometer is adjusted, the speed of the motor is changed accordingly.

Exploring the Code

If you haven’t read the following, now is a good time:

After the board object has emitted the ready event, we can initialize Switch, Sensor and Motor instances:

language:javascript
var spdt = new five.Switch("a0"); // For the switch
var throttle = new five.Sensor("b0"); // For the potentiometer
var motor = new five.Motor([ "a5", "a4", "a3" ]); // For motor A

Then, register the event handlers that will turn switch state (open or closed) into motor direction:

language:javascript
spdt.on("open", () => {
  motor.stop().forward(motor.speed());
});

spdt.on("close", () => {
  motor.stop().reverse(motor.speed());
});
Note: It's smart to send a complete `stop` signal to a motor before changing the direction. Kind of like how you don't want to put your car into reverse if you're tooling down the highway.

Finally, register an event handler for changes from the throttle sensor, which updates the speed of the motor.

As you learned in Experiment 3: Reading a Potentiometer, analog sensor input values are 10-bit (0–1023), but the motor speed needs to be an 8-bit (0–255) value. We can bit-shift the throttle value to get an 8-bit number (the two least significant bits on the right get discarded).

language:javascript
throttle.on("change", () => {
  motor.speed(throttle.value >> 2);
});

Variation: Control Multiple Motors' Speed and Direction With Johnny-Five

Open your favorite code editor, create a file called motor-multi-speed-direction.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your motor-multi-speed-direction.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var spdt = new five.Switch("a0");
  var throttle = new five.Sensor("b0");
  var motors = new five.Motors([
    [ "a5", "a4", "a3" ],
    [ "b5", "b4", "b3" ],
  ]);
  var speed = 0;

  spdt.on("open", () => {
    motors.stop().forward(speed);
  });

  spdt.on("close", () => {
    motors.stop().reverse(speed);
  });

  throttle.on("change", () => {
    speed = throttle.value >> 2;
    motors.speed(speed);
  });
});

Type—or copy and paste—the following into your terminal:

t2 run motor-multi-speed-direction.js

What You Should See

Both motors are controlled by the switch and potentiometer inputs:

  1. When you flip the switch, the motors will change direction, maintaining current speed.
  2. When the potentiometer is adjusted, the speed of both motors is changed accordingly.

Exploring the Code

If you haven’t read Experiment 2: Multiple LEDs, now is a good time.

After the board object has emitted the ready event, we can initialize a Switch and a Sensor like the last example. But instead of Motor, here the code uses a Motors instance:

language:javascript
var spdt = new five.Switch("a0");
var throttle = new five.Sensor("b0");
var motors = new five.Motors([
  [ "a5", "a4", "a3" ],
  [ "b5", "b4", "b3" ],
]);

Recall in Experiment 2: Multiple LEDs, you were introduced to collection classes, which allowed your program to initialize a “list” or “collection” of a specific component class … that’s what you’re doing here as well.

Motors allows you to create two Motor instances that can be controlled simultaneously.

The variable speed keeps track of the current speed of both motors:

language:javascript
var speed = 0;

Then, register the event handlers that will turn switch state (open or closed) into motor direction. This is effectively the same as the previous iteration, except now we’re using motors and setting the value from the speed variable:

language:javascript
spdt.on("open", () => {
  motors.stop().forward(speed);
});

spdt.on("close", () => {
  motors.stop().reverse(speed);
});

Finally, the event handler for throttle changes is updated to first update the speed variable, then set the speed of both motors:

language:javascript
throttle.on("change", () => {
  speed = throttle.value >> 2;
  motors.speed(speed);
});

Building Further

  • Make a browser-based “remote control” that’s served from an Express server, with commands transmitted over a socket provided by Socket.io.
  • Attach your Tessel 2 and two motors to a Shadow Chassis with a USB and drive it.

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using.
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 10: Using the BME280

Introduction

The sensor used in this experiment is pretty sophisticated. The BME280 reads barometric pressure, temperature and humidity. It can even extrapolate altitude based on pressure changes! It communicates all that data to the Tessel 2 using a serial protocol called I2C (Inter-Integrated Circuit) protocol. This sensor has built-in support in Johnny-Five using the Multi class.

I2C is a popular serial protocol; it shows up all over the place in digital electronics. The design of I2C, with a shared bus, takes far fewer wires than other serial options (e.g., SPI, which we’ll meet in a future experiment)—especially when hooking up multiple devices. You can (theoretically) connect up to 1008 different devices to the same two pins and use ‘em all at once.

Got a C or Arduino background? To work with I2C sensors, you’d normally have to work with device-specific libraries written by others (or maybe yourself!). But in Johnny-Five there are a number of I2C sensors built right in to the framework—the heavy lifting is done for you and the low-level details abstracted out of your way.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorial provides in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x The BME280 Atmospheric Sensor
  • 6x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
SparkFun Atmospheric Sensor Breakout - BME280

SEN-13676
$19.95
5
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95

Introduction to the BME280

BME280 pic

The SparkFun BME280 Atmospheric Sensor Breakout is an easy way to measure stuff about the atmosphere around you: pressure, humidity and air temperature. All of this is combined into a petite package, called a breakout board.

The 3.3V breakout is power-efficient, using as little as 5µA (that’s 1/1000000 of an amp!) when idling and less than 1mA when it’s taking measurements. There are 10 pins on the breakout board, but six is the maximum ever used at one time.

In this experiment you will work with the BME280 to read the temperature, pressure and humidity of the room as well as your altitude based off of the atmospheric pressure. Finally, in the Building Further section you will use your BME280 as the heart of a web-based weather dashboard application.

Hardware Hookup

Is it hot in here, or is it just me? Let’s find out using this sensor, but first you need to hook it up!

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the BME280 Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

Compared to the H-Bridge motor circuit in Experiment 9, this one is pretty simple. Attach the BME280 breakout board to the breadboard so that it spans the center notch. Connect the BME280’s SCL (clock) pin to Tessel 2’s Port A, Pin 0. Connect the SDA (data) pin to the Tessel’s Port A, Pin 1. Connect 3.3V to the Tessel’s 3.3V pin and GND to GND.

Observing the Environment With Johnny-Five and the BME280

For this experiment, you will be “graphing” sensor output in your browser, using:

However, before we dive into our browser “monitor” system, let’s take a look at the most basic example. Open your favorite code editor, create a file called bme.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your bme.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var monitor = new five.Multi({
    controller: "BME280"
  });

  monitor.on("change", function() {
    console.log("thermometer");
    console.log("  celsius      : ", this.thermometer.celsius);
    console.log("  fahrenheit   : ", this.thermometer.fahrenheit);
    console.log("  kelvin       : ", this.thermometer.kelvin);
    console.log("--------------------------------------");

    console.log("barometer");
    console.log("  pressure     : ", this.barometer.pressure);
    console.log("--------------------------------------");

    console.log("altimeter");
    console.log("  feet         : ", this.altimeter.feet);
    console.log("  meters       : ", this.altimeter.meters);
    console.log("--------------------------------------");
  });
});

Type—or copy and paste—the following into your terminal:

t2 run bme.js

What You Should See

alt text

This is going to print a lot of data to your console, very quickly—so quickly that you likely won’t be able to make sense of it! Go ahead and exit the program by typing Command-C or Control-C.

Exploring the Code

Once the board has emitted the ready event, hardware inputs are ready for interaction, so the first thing that occurs is an instantiation of a Multi object. Multi objects represent two or more components, usually sensors, that are packaged together and exposed via a single register. Multi and IMU (Inertial Measurement Unit) boards that combine multiple movement sensors like accelerometers, gyroscopes, etc.) are very similar; the latter is used for non-motion-related packages.

language:javascript
var monitor = new five.Multi({
  controller: "BME280"
});

Now that we have a monitorMulti instance, the next thing to do is register an event handler to be invoked whenever changes are detected in the sensor readings:

language:javascript
monitor.on("change", function() {
  // ...
});

Within that handler, we’re logging all of the relevant data properties for this multi-component package:

language:javascript
console.log("thermometer");
console.log("  celsius      : ", this.thermometer.celsius);
console.log("  fahrenheit   : ", this.thermometer.fahrenheit);
console.log("  kelvin       : ", this.thermometer.kelvin);
console.log("--------------------------------------");

console.log("barometer");
console.log("  pressure     : ", this.barometer.pressure);
console.log("--------------------------------------");

console.log("altimeter");
console.log("  feet         : ", this.altimeter.feet);
console.log("  meters       : ", this.altimeter.meters);
console.log("--------------------------------------");

… which is a lot of data and will likely overwhelm the terminal, so be ready to type Command-C or Control-C to end the program.

Making a Slick Gauge Dashboard for the BME280

Now that we’ve demonstrated the basics of using a sensor package like the BME280, let’s make something interesting! The next sections will guide you through creating a web application that displays all of the data from the BME280 as nice-looking gauges in a browser. The data updates automatically because we will use these snazzy things called Web Sockets — basically there will be no need for you to refresh the page!

The steps for building this little application are:

  1. Install some needed npm packages.
  2. Create a directory and files for the client-side web application: HTML and JavaScript.
  3. Create files for the Tessel 2: a JavaScript program and a .tesselinclude file.
  4. Deploy and run the program on the Tessel 2!

Install Needed Packages

First, we need to install a few modules that we’ll use in this application:

npm install socket.io express justgage

Note: You can install more than one package at a time with `npm` by separating the package names with spaces.

Create Client-Side Application Files

Once npm packages are installed, create a new subdirectory called app/ inside of your j51k directory.

Inside the app directory, create a file called index.html. Type—or copy and paste—the following HTML code into your index.html file:

language:html<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Tessel 2 Enviro-Monitor</title><style>
    .gauge {
      display: block;
      float: left;
    }
    #thermometer,
    #barometer,
    #altimeter,
    #hygrometer {
      width: 25%;
    }</style></head><body><div id="thermometer" class="gauge"></div><div id="barometer" class="gauge"></div><div id="altimeter" class="gauge"></div><div id="hygrometer" class="gauge"></div><script src="/socket.io/socket.io.js"></script><script src="/vendor/justgage/justgage.js"></script><script src="/vendor/justgage/raphael-2.1.4.min.js"></script><script src="main.js"></script></body></html>

Next, create another file in the app subdirectory called main.js. Type—or copy and paste—the following JavaScript code into your main.js file:

language:javascript
window.onload = function() {
  var socket = io();
  var monitor = {};

  monitor.thermometer = new JustGage({
    id: "thermometer",
    value: 10,
    min: 0,
    max: 100,
    title: "Thermometer",
    label: "° Celsius",
    relativeGaugeSize: true,
  });

  monitor.barometer = new JustGage({
    id: "barometer",
    value: 100,
    min: 50,
    max: 150,
    title: "Barometer",
    label: "Pressure/kPa",
    relativeGaugeSize: true,
  });

  monitor.altimeter = new JustGage({
    id: "altimeter",
    value: 10,
    min: 0,
    max: 100,
    title: "Altimeter",
    label: "Meters",
    relativeGaugeSize: true,
  });

  monitor.hygrometer = new JustGage({
    id: "hygrometer",
    value: 10,
    min: 0,
    max: 100,
    title: "Hygrometer",
    label: "Humidity %",
    relativeGaugeSize: true,
  });

  var displays = Object.keys(monitor);

  socket.on("report", function (data) {
    displays.forEach(function (display) {
      monitor[display].refresh(data[display]);
    });
  });
};

Create Server-Side Files and Code

Back in your j5ik directory (not in the app subdirectory), create a new file called .tesselinclude.

This file is used to tell t2-cli that you have additional files and assets that you want to deploy to the board. This is where you identify files like HTML, browser JavaScript and CSS, images, sounds, videos, etc.

.tesselinclude may include any valid glob expressions). For this exercise, you don’t need an in-depth understanding of glob expressions, just type—or copy and paste—the following pattern expressions into your .tesselinclude file:

app/
node_modules/justgage/*.js

With all the “setup” aside, let’s get to the actual program. Create a file called monitor.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your monitor.js file:

language:javascript
var http = require("http");
var os = require("os");
var path = require("path");

var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

var Express = require("express");
var SocketIO = require("socket.io");

var application = new Express();
var server = new http.Server(application);
var io = new SocketIO(server);

application.use(Express.static(path.join(__dirname, "/app")));
application.use("/vendor", Express.static(__dirname + "/node_modules/"));

board.on("ready", () => {
  var clients = new Set();
  var monitor = new five.Multi({
    controller: "BME280",
    elevation: 2,
  });
  var updated = Date.now() - 5000;

  monitor.on("change", () => {
    var now = Date.now();
    if (now - updated >= 5000) {
      updated = now;

      clients.forEach(recipient => {
        recipient.emit("report", {
          thermometer: monitor.thermometer.fahrenheit,
          barometer: monitor.barometer.pressure,
          hygrometer: monitor.hygrometer.relativeHumidity,
          altimeter: monitor.altimeter.meters,
        });
      });
    }
  });

  io.on("connection", socket => {
    // Allow up to 5 monitor sockets to
    // connect to this enviro-monitor server
    if (clients.size < 5) {
      clients.add(socket);
      // When the socket disconnects, remove
      // it from the recipient set.
      socket.on("disconnect", () => clients.delete(socket));
    }
  });

  var port = 3000;
  server.listen(port, () => {
    console.log(`http://${os.networkInterfaces().wlan0[0].address}:${port}`);
  });

  process.on("SIGINT", () => {
    server.close();
  });
});

Try It Out!

Double-check that your j5ik/ directory contains the following:

├── app
│   ├── index.html
│   └── main.js
├── monitor.js
├── node_modules
├── package.json
└── .tesselinclude

There will likely be additional files in your j5ik/ directory from other experiments in this guide, but make sure monitor.js and .tesselinclude are in the j5ik/ directory and that index.html and main.js are inside of j5ik/app.

Type—or copy and paste—the following into your terminal:

t2 run monitor.js

Once the program is bundled and deployed, a URL will be displayed in the terminal. Copy and paste the URL into a browser address bar and press [ENTER].

What You Should See

When the page loads, it should appear similar to this:

alt text

Click on the diagram for a closer look.

Exploring the Code

There is certainly a lot more code in this experiment than in anything we’ve previously looked at!

It may help to first consider what’s going on in the application as a whole:

  • monitor.js contains JavaScript code that is executed on the Tessel 2.
  • app/main.js contains JavaScript that gets executed in your web browser. main.js is included in the index.html page that is delivered to the browser.
  • A web server configured in monitor.js serves HTML (index.html) and JS (app/main.js and a few others included in index.html) to the browser.
  • A web socket connection between monitor.js (the Tessel, or “server-side” JavaScript) and main.js (the “client-side” JavaScript) allows updates to the Multi sensors to be communicated and displayed in-browser in (near) real time.

Monitor.js: The Code That Runs on the Tessel 2

Requiring Some Modules

monitor.js starts out with several require calls, as we bring in our dependencies. The first new dependencies are the built-in—meaning that they come with Node.js and you don’t have to npm install them—http, os and path modules. We’ll see these again as we go.

language:javascript
var http = require("http");
var os = require("os");
var path = require("path");

Following these are our familiar Tessel-io and Johnny-Five dependencies, and a Board instantiation:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

Then, more new third-party modules: the Express framework API and Socket.IO:

language:javascript
var Express = require("express");
var SocketIO = require("socket.io");

Configuring a Web Application, Server and Socket.io

Once the dependencies are available, a new Express application server instance is created for our web application:

language:javascript
var application = new Express();

The resulting application object is then passed as an argument to the instantiation of a new http.Server object:

language:javascript
var server = new http.Server(application);

Huzzah! Now we have the beginnings of a web server.

Now let’s pass that server on to a new SocketIO object (it’s turtles all the way down!):

language:javascript
var io = new SocketIO(server);

All of that boilerplate completes the setup of a fully functional HTTP server with simple routing and an Active WebSocket. Yay, Node.js!

Just before we proceed with registering the ready event handler for the board object, we need to set up some basic routing for our application’s HTTP requests (that is, when we visit our monitor app, this will tell the server where to find the content to deliver).

language:javascript
application.use(Express.static(path.join(__dirname, "/app")));
application.use("/vendor", Express.static(__dirname + "/node_modules/"));

The first line tells the server to serve up static content. It will treat the app directory as the web root and respond to a browser request for /index.html by delivering the file at app/index.html. The second line makes the content in the local node_modules directory available as the URL path /vendor (e.g., a browser request for /vendor/justgage/justgage.js will result in the delivery of the file at node_modules/justgage/justgage.js).

Using a Set to Contain Clients

The last top-level portion of monitor.js is the by-now-very-familiar registration of a ready event handler for the board object:

language:javascript
board.on("ready", () => {
  // ...
});

Once the ready event is emitted, a new variable called clients is created, whose value is a new Set instance object.

language:javascript
var clients = new Set();

While Set may seem much like Array, it’s got its own thing going on. You can’t put the same thing in a Set twice. You can’t access entries in a Set using a numeric index like you do with Arrays. You can only access stuff in a Set by iterating over the Set in order. You can’t change the order of things in a Set once they’re there.

Lest that sound like a lot of rules and “can'ts”, Sets are great when you do want to iterate over things in order, and they have intuitive methods for getting stuff done.

This clientsSet will contain a list of unique connections to our server and allow the program to limit the number of connections to 5. Turns out 5 is a totally arbitrary number to limit connection demands (the more active clients, the more resources the program will use). Nothing goes in the Set just yet.

Handling Changes to the Multi Object

Next, we create a new instance of the Multi class. This time we’re setting a baseline elevation, in meters, which can be obtained by visiting whatismyelevation.com/. This will give us a relative altitude from our current elevation (in meters). If you don’t set this value, the sensor will display relative altitude from the point of the first pressure reading—you’ll be starting from 0!

language:javascript
var monitor = new five.Multi({
  controller: "BME280",
  elevation: 2,
});

We’ll need to respond to changes from the monitor (changes to the values of any of its sensors) and tell all of the connected clients about that so that the freshest values can be displayed. We can do that by triggering (emit-ting) a report event. There’s a small wrinkle to this: emitting a report event causes the gauges displayed on the web page to refresh and re-animate. Doing this too often causes browser performance woes. So we’ll throttle the report events to happen, at most, every five seconds (change events fire pretty frequently). That’s the purpose of the updated variable—to keep track of the last time a report event was emitted.

Once we know we do want to emit a report event, it’s easy to iterate over the clients because, yay, Sets make that handy. So: iterate over the clients, emit the report event on each client entry:

language:javascript
var updated = Date.now() - 5000;

monitor.on("change", () => {
  var now = Date.now();
  if (now - updated >= 5000) {
    updated = now;

    clients.forEach(recipient => {
      recipient.emit("report", {
        thermometer: monitor.thermometer.fahrenheit,
        barometer: monitor.barometer.pressure,
        hygrometer: monitor.hygrometer.relativeHumidity,
        altimeter: monitor.altimeter.meters,
      });
    });
  }
});

Yeah, so where’d these clients (0–5 of ‘em) all come from? That bit comes next:

language:javascript
io.on("connection", socket => {
  // Allow up to 5 monitor sockets to
  // connect to this enviro-monitor server
  if (clients.size < 5) {
    clients.add(socket);
    // When the socket disconnects, remove
    // it from the recipient set.
    socket.on("disconnect", () => clients.delete(socket));
  }
});

Whenever there is a connection event on the io object (io is a SocketIO instance):

  1. Are there fewer than five clients already connected? Good. If so:
    1. add that client (socket) to the clientsSet.
    2. When that new client (socket) later emits a disconnect event, remove (delete) that client from the clientsSet. That frees up room for more connections.

Getting the Web Server Going

All right! Time to kick our web server into gear.

language:javascript
var port = 3000;
server.listen(port, () => {
  console.log(`http://${os.networkInterfaces().wlan0[0].address}:${port}`);
});

That’ll make the server listen on port 3000. It’ll also helpfully log the URL for you so you can view it from a browser (on the same network, anyway).

Respecting the great circle of life, the server also needs to know when it’s time to die. It listens for a SIGINT (SIGnal INTerrupt) on the process object (which represents the actual software process). That is: when the program’s process stops running, close the server.

JavaScript for the Browser: main.js

The main.js script is included in index.html and is the JavaScript that drives the display of the pretty gauges. Most of the stuff going on here uses third-party code (justgages and socket.io).

The server-side code that’s running on the Tessel has a socket server, and now we’ll create the other end of that connection by creating a socket client:

language:javascript
var socket = io();

Then we’re creating new JustGage objects, stored in a monitor object. The options passed to JustGage define details about the gauge: its appearance, range, etc.

language:javascript
var monitor = {};

monitor.thermometer = new JustGage({
  id: "thermometer",
  value: 10,
  min: 0,
  max: 100,
  title: "Thermometer",
  label: "° Celsius",
  relativeGaugeSize: true,
});

monitor.barometer = new JustGage({
  id: "barometer",
  value: 100,
  min: 50,
  max: 150,
  title: "Barometer",
  label: "Pressure/kPa",
  relativeGaugeSize: true,
});

monitor.altimeter = new JustGage({
  id: "altimeter",
  value: 10,
  min: 0,
  max: 100,
  title: "Altimeter",
  label: "Meters",
  relativeGaugeSize: true,
});

monitor.hygrometer = new JustGage({
  id: "hygrometer",
  value: 10,
  min: 0,
  max: 100,
  title: "Hygrometer",
  label: "Humidity %",
  relativeGaugeSize: true,
});

Next, make a list of the monitor gauges, stored in a variable called displays:

language:javascript
var displays = Object.keys(monitor);

Finally, and very importantly, the socket client object registers an event handler called report—this will handle that report event that comes from our server! Inside the handler, iterate all of the entries in displays and refresh each monitor gauge:

language:javascript
var displays = Object.keys(monitor);

socket.on("report", function (data) {
  displays.forEach(function (display) {
    monitor[display].refresh(data[display]);
  });
});

Building Further

  • Build a home-monitoring app with Blynk– Have your phone interact with your Tessel 2 to monitor the temperature and humidity in your home.
  • Report your data to Data.sparkfun.com – Data log to data.sparkfun
  • Log your data to a CSV file using the file system – If you don’t have access to the internet, log your data to a text file using the file system on your Tessel 2.

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using.
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 11: Soil Moisture Sensor

Introduction

In this experiment, you’ll use the SparkFun soil moisture sensor to alert you when your plants are getting sad and need a bit of water to cheer up.

Remember Experiment 6? In that experiment, you built a voltage divider circuit to read light intensity data as voltage from a photoresistor. Good news: the SparkFun moisture sensor has an on-board voltage divider—it does that part for you. All you need to do is power it and read the analog values coming from its signal (third) pin. When the soil is getting dry, we’ll turn on a yellow LED to warn you. Moist and good? Then we’ll turn on a blue LED.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x Soil Moisture Sensor
  • 1x Standard Yellow LED
  • 1x Standard Blue LED
  • 2x 100Ω Resistor
  • 9x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
SparkFun Soil Moisture Sensor

SEN-13322
$4.95
3
LED - Assorted (20 pack)

COM-12062
$2.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introduction to the Soil Moisture Sensor

pic of soil sensor

The SparkFun Soil Moisture Sensor is a simple breakout board for measuring the moisture in soil and similar materials. The soil moisture sensor is straightforward to use. The two large exposed pads function as probes for the sensor, together acting as a variable resistor. The more water that is in the soil, the better the conductivity between the pads will be, which will result in a lower resistance and a higher SIG (output voltage).

To get the SparkFun Soil Moisture Sensor functioning, all you need to do is connect the VCC and GND pins to your Tessel 2. You will receive a SIG out, which will depend on the amount of water in the soil. Oh, and you’ll also need a bit of dirt in a pot to test it all out!

One commonly known issue with soil moisture sensors is their short lifespan when exposed to a moist environment. To combat this, we’ve had the PCB coated in Gold Finishing (ENIG, or Electroless Nickel Immersion Gold).

Hardware Hookup

Let’s get this circuit wired up! Your plants are waiting to tell you if they are thirsty or not.

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Soil Sensor Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

Note: The headers on the soil sensor are a screw-terminal type. You'll need a small (jewelry- or electronics-sized) flat screwdriver. If you don't have one on hand, you can probably still get the jumper wires into the header slots, but they won't be as secure.
  1. Connect three jumper wires to the soil sensor: one each for VCC, GND and SIG (supply voltage, ground, signal out) pins. Connect the power and ground jumper wires to the power rail of the breadboard. Connect the SIG pin to Tessel’s Port A, Pin 7.
  2. Connect the blue and yellow LEDs to the breadboard. Connect a 100Ω to each LED’s anode (longer leg) such that it spans the center notch on the breadboard. Then connect a jumper wire between each of the resistors and Port B, Pin 0 (yellow LED) and Port B, Pin 1 (blue LED). Connect the LED’s cathodes to the ground power rail.
  3. Connect the Tessel’s 3.3V and GND pins to the breadboard power rail using jumper wires.

Monitoring Soil Moisture With Johnny-Five

Open your favorite code editor, create a file called moisture.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your moisture.js file:

language:javascript
var Tessel = require("tessel-io");
var five = require("johnny-five");

var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var dry = new five.Led("b0");
  var wet = new five.Led("b1");
  var both = new five.Leds([dry, wet]);
  var soil = new five.Sensor("a7");

  dry.on();

  soil.on("change", () => {
    /*
      Condition   Low   High
      ----------------------
      Dry           0    300
      Damp        300    700
     */
    if (wet.isOn && soil.value < 300) {
      both.toggle();
    } else {
      if (dry.isOn && soil.value > 300) {
        both.toggle();
      }
    }
  });
});

Put some dry soil into two small containers (paper cups would work great). Pour some water into the soil in one of the containers so that it is nicely damp but not saturated.

Note: No soil on hand? The soil sensor will also react to the moisture content of other materials, like coffee grounds.

Type—or copy and paste—the following into your terminal:

t2 run moisture.js

Move the soil sensor between the dry and wet soil samples to see the LEDs light up.

What You Should See

When the moisture sensor is in a “dry” condition, the yellow LED will be lit. When the moisture sensor is in a “damp” or “wet” condition, the blue LED will light up.

Exploring the Code

Once the board object has emitted the ready event, the program initializes the instance objects that will be used to observe the sensor and output a state based on its condition. For that, you’ll create two Led objects, an Leds collection object that contains those Led objects, and a Sensor object for the soil sensor.

language:javascript
var dry = new five.Led("b0");
var wet = new five.Led("b1");
var both = new five.Leds([dry, wet]);
var soil = new five.Sensor("a7");

Set the “dry” condition indicator LED to be on by default—don’t worry; this program will right itself even if the sensor is initially in a “damp” or “wet” condition.

language:javascript
dry.on();

The last major piece of program initialization is the Sensor’s change event handler. This code indicates that the program wants to be informed whenever the soilSensor reading changes:

language:javascript
soil.on("change", () => {
  // ...
});

Within the “change” handler, the program will determine which indicator LED should be on, based on the value of the sensor:

language:javascript
/*
  Condition   Low   High
  ----------------------
  Dry           0    300
  Damp        300    700
 */
if (wet.isOn && soil.value < 300) {
  both.toggle();
} else {
  if (dry.isOn && soil.value > 300) {
    both.toggle();
  }
}

Led’s toggle method will cause the LED to swap its current state (if it’s off, it will turn on; if it’s on, it will turn off).

The logic above can be written and reasoned about in a narrative form:

If the wet indicator is on and the soil sensor’s value is less than 300, toggle the state of both indicators; otherwise, if the dry indicator is on and the soil sensor’s value is greater than 300, toggle the state of both indicators.

These predicate conditions ensure that the indicators do not toggle on and off wildly as each change event is received. This could happen because analog input sensors are generally very noisy.

Building Further

  • Use a single RGB LED instead of two colored LEDs
  • Have your plant Tweet you when it needs to be watered
  • Build an IFTTT Project to email you when your Tessel 2 detects water/ moisture

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using.
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 12: Using an LCD Screen

Introduction

In this experiment, you’re going to learn how to get characters to display on a 32-character LCD screen (2 lines, 16 characters each). You’ll start with 1s and 0s but quickly progress to “Hello” and displaying the date and time. Finally, you’ll be able to use the LCD to show the current location of satellites in space!

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorial provides in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x Basic 16x2 Character LCD
  • 1x Potentiometer
  • 15x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
Trimpot 10K with Knob

COM-09806
$0.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Basic 16x2 Character LCD - White on Black 3.3V

LCD-09052
$14.95
2

Introducing the LCD screen

alt text

The J5IK includes a Liquid Crystal Display (LCD) screen. This screen is similar to one that you may find in your microwave, on your dashboard in your car, or if you are old enough to remember, a Speak and Spell. LCD screens are a great way to display data or information from your Tessel 2 board without having to have it connected to your laptop.

The LCD screen in this kit can display 16 characters on each of its two rows (32 characters total). The wiring in the diagram can look a little bit like a rat’s nest, but it’s not so bad if you take care with your connections. The potentiometer in the circuit can be used to adjust the display contrast on the LCD.

Hardware Hookup

Are you ready to print some text on your LCD? Let’s get this circuit wired up!

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the LCD Circuit

Note: The LCD board has 16 pins, numbered 1 - 16 from the top as oriented on the breadboard in this experiment.

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Connect the LCD board to the left side of the breadboard.
  2. Connect the LCD board’s pins using jumper wires:
    1. Connect LCD pins 1, 5 and 16 to the ground power rail.
    2. Connect LCD pins 2 and 15 to the supply power rail.
    3. Connect LCD pins to GPIO pins on the Tessel 2:
      1. LCD pin 4 to Port A, Pin 2.
      2. LCD pin 6 to Port A, Pin 3.
      3. LCD pin 11 to Port A, Pin 4.
      4. LCD pin 12 to Port A, Pin 5.
      5. LCD pin 13 to Port A, Pin 6.
      6. LCD pin 14 to Port A, Pin 7.
  3. Connect the potentiometer to the breadboard. Connect jumper wires between its outer two legs and the power rail on the breadboard. Connect its middle leg to the LCD’s pin 3 with a jumper wire.
  4. Connect the Tessel’s 3.3V and GND pins to the breadboard’s power rail with jumper wires.

Printing Characters to an LCD With Johnny-Five

Open your favorite code editor, create a file called lcd.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your lcd.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var lcd = new five.LCD({
    pins: ["a2", "a3", "a4", "a5", "a6", "a7"]
  });

  lcd.cursor(0, 0).print("10".repeat(8));
  lcd.cursor(1, 0).print("01".repeat(8));
});

Type—or copy and paste—the following into your terminal:

t2 run lcd.js

What You Should See

alt text

The LCD should display two rows of zeros and ones:

language:javascript
1010101010101010
0101010101010101

Troubleshooting

Not seeing any digits? Try turning the potentiometer—it adjusts contrast on the LCD.

Exploring the Code

There’s nothing very exciting or interesting about this first example, but try to think of it as a gentle introduction to more robust subsequent fun. As with all Johnny-Five programs, once the board emits the ready event, the program can initialize an LCD object:

language:javascript
var lcd = new five.LCD({
  pins: ["a2", "a3", "a4", "a5", "a6", "a7"]
});

As shown in earlier experiments, this could also be written as:

language:javascript
var lcd = new five.LCD(["a2", "a3", "a4", "a5", "a6", "a7"]);

… Which would have the same meaning. As long as the pins are provided in the following order:

  RS    EN    D4    D5    D6    D7
["a2", "a3", "a4", "a5", "a6", "a7"]

These six pins (RS—Register Select, EN—Enable, and four data pins) are used by Johnny-Five to control the LCD.

The next two lines look nearly identical to each other:

language:javascript
lcd.cursor(0, 0).print("10".repeat(8));
lcd.cursor(1, 0).print("01".repeat(8));

The individual spaces for characters on LCDs are referenced using a grid system. The cursor(row, column) method instructs the lcd object to move the “cursor” to the specified row and column. Both rows and columns are “zero indexed,” which means they start at zero and count up (just like JavaScript Array indices). This means that cursor(0, 0) puts the cursor on the first row, at the left-most column.

The print(message) method tells the lcd to print the provided string message to the display, starting at the present cursor position.

Now is a good time to try printing out different messages. Go ahead and replace those two lines with this:

language:javascript
lcd.cursor(0, 0).print("Hello!");

Type—or copy and paste—the following into your terminal:

t2 run lcd.js

The 1s and 0s should be cleared, and the message “Hello!” should be displayed. Before moving on, try changing that message to a message of your own.

  • What happens when you try to print numbers? For example: lcd.print(123456789)

Variation: Displaying the Date and Time With Johnny-Five

Before we get into the next program, you’ll need to install a module that makes working with date and time less of a chore. Hands down, the most comprehensive module for this task is Moment.js.

Moment.js Parse, validate, manipulate, and display dates in JavaScript.

In your terminal, type—or copy and paste—the following command:

npm install moment

Open your favorite code editor, create a file called lcd-clock.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your lcd-clock.js file:

language:javascript
var moment = require("moment");
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var lcd = new five.LCD({
    //      RS    EN    D4    D5    D6    D7
    pins: ["a2", "a3", "a4", "a5", "a6", "a7"],
  });

  var snapshots = [ "", "" ];

  board.loop(100, () => {
    var updates = [
      moment().format("MMM Do, YYYY"),
      moment().format("hh:mm:ss A"),
    ];

    updates.forEach((update, index) => {
      if (snapshots[index] !== update) {
        snapshots[index] = update;
        lcd.cursor(index, 0).print(update);
      }
    });
  });
});

Type—or copy and paste—the following into your terminal:

t2 run lcd-clock.js

What You Should See

The first row should display the date, and the second row should display the time. For example, today is June 3rd, 2016, and the time is 3:00 p.m. EST (or UTC-0400) and the clock displays:

June 3rd 2016
07:00:53 PM

Wait… 7?? Yes! That’s why we made sure to point out which timezone this was running in. The Tessel 2’s internal clock defaults to UTC; the timezone can be set in a number of different ways, but the easiest (for the purpose of this experiment) is to use the moment().utcOffset("-0400"). Try figuring out where this change should be made in your program!

Exploring the Code

The first thing you will have noticed is that there is a new dependency being required, which you’ve likely guessed is necessary for using Moment.js in your program:

language:javascript
var moment = require("moment");

Moving farther down, past the parts that have not changed, the next new line encountered is this one:

language:javascript
var snapshots = [ "", "" ];

This JavaScript Array keeps track of the characters currently displayed on each of the LCD’s two lines. When we start out, nothing is being displayed on either line (thus, empty strings).

The next line portion sees the return of a familiar method: board.loop(ms, handler). This was used several times in earlier experiments to produce interesting, iterative LED lighting patterns. Here it’s used to check the time every 1/10 of a second to see if an update to the LCD’s display is necessary. The 10Hz timing frequency is arbitrary, and you’re encouraged to experiment with other subsecond periods.

language:javascript
board.loop(100, () => {
  // ...
});

Within the loop(...) call’s handler, the program creates another new temporary Array, this time storing a formatted date and time as the first and second entry, in that order:

language:javascript
var updates = [
  moment().format("MMMM Do YYYY"), // This should be displayed on first line
  moment().format("hh:mm:ss A"), // This should be displayed on second line
];

Then, those new values are iterated with forEach method:

language:javascript
updates.forEach((update, index) => {
  if (snapshots[index] !== update) {
    snapshots[index] = update;
    lcd.cursor(index, 0).print(update);
  }
});

If the update value for a line differs from what is currently displayed on that line (stored in snapshots), that line on the LCD is updated with print. This comparison makes sure we don’t wastefully print to the LCD if nothing has changed.

Variation: Displaying ISS Location With Johnny-Five

OK, here’s the cool part. We’re going to use the LCD to display what’s going on in space. We’re going to display the location of the International Space Station on your LCD’s screen. To do this, we’ll need to install one last new module: iss.

iss a module that, given an ID and a request rate, returns a readable stream that emits location data for the corresponding satellite

In your terminal, type—or copy and paste—the following command:

npm install iss

This module wraps the data that’s made available by Where the ISS At?.

Open your favorite code editor, create a file called lcd-iss.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your lcd-iss.js file:

language:javascript
var iss = require("iss");
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var lcd = new five.LCD(["a2", "a3", "a4", "a5", "a6", "a7"]);

  // ISS Code: 25544
  // Max Requests: 20/s
  iss.locationStream(25544, 20).on("data", (buffer) => {
    var data = JSON.parse(buffer.toString());

    lcd.cursor(0, 0).print(data.latitude);
    lcd.cursor(1, 0).print(data.longitude);
  });
});

Type—or copy and paste—the following into your terminal:

t2 run lcd-iss.js

What You Should See

alt text

The current latitude of the ISS is displayed on the first row and the longitude on the second row!

Exploring the Code

First, your iss dependency is required:

language:javascript
var iss = require("iss");

Then, after the board is “ready” and the LCD is initialized, we call the iss.locationStream(...) function, passing the ISS ID (25544) and Max Requests-Per-Second (20) arguments. The “Max Request” count is a limit on the number of requests (for new location data) to the remote data server.

This call returns a Stream object. If you’re new to JavaScript or programming, Streams may be a big new concept for you. We won’t dive in to the nitty-gritty here, but there are still a few things we can observe.

The ReadableStream returned by iss.locationStream(...) emits data events too—just like our Johnny-Five sensors! The data event handler function receives a Buffer (again, don’t worry if this is new to you). Buffers can be converted to Strings (buffer.toString()) and then parsed into a JSON object (data). That data object has latitude and longitude properties that can be printed to the LCD:

language:javascript
// ISS Code: 25544
// Max Requests: 20/s
iss.locationStream(25544, 20).on("data", buffer => {
  var data = JSON.parse(buffer.toString());

  lcd.cursor(0, 0).print(data.latitude);
  lcd.cursor(1, 0).print(data.longitude);
});

The data event handler will be called every time a new location object is received.

Building Further

  • Use Moment Timezone to control the timezone of your clock application
  • Create a “vertically scrolling” display of the ISS data.

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using.
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 13: Controlling LEDs with a Shift Register

Introduction

This experiment is the first time we’ll use an Integrated Circuit (IC) all by itself with no breakout board or other support. We’ll use a shift register to give you control over an additional eight outputs, while using up only three pins on the Tessel 2. Using the shift register in this experiment, you can control eight—count ‘em, eight!—LEDs. That’s a new record for us!

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorials provide in-depth background on some of the hardware concepts in this article:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x Shift Register
  • 8x Standard LEDs
  • 8x 100Ω Resistor
  • 17x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
LED - Assorted (20 pack)

COM-12062
$2.95
6
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Shift Register 8-Bit - SN74HC595

COM-13699
$0.95
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introducing the Shift Register

alt text

The kind of shift register used in this experiment takes a byte of data (8 bits) and breaks it up, using each bit to determine the logic level of its eight output pins. For example, the message:

01101001

would result in the following states on the shift register’s individual output pins:

LOW-HIGH-HIGH-LOW-HIGH-LOW-LOW-HIGH

Each bit in the sent byte, then, determines the state of its associated output pin. The shift register is able to give you extra outputs (eight, while using only three pins on the Tessel 2) because it takes serial data and converts it to parallel output.

You can think of the inside of a shift register as a big train-switching yard. A train (byte) arrives, and, like all of the other trains that come to this place, it is eight cars long. Each car in the train represents a single bit, and is either full (1) or empty (0). The train is disassembled; each car is switched onto its own track and waits. Once all of the cars are in place and the engine-master gives the all clear, the cars exit the yard on their assigned track (shift register output pin). Full cars (1s) will cause their output pins to go HIGH while empty cars (0s) will cause their output pins to go LOW. Bytes representing different orders of 1s and 0s cause different patterns of LOW and HIGH states from the shift register’s output pins.

If you have eight LEDs connected to the shift register’s output pins, you could turn them all on by sending the message 11111111, or turn them all off by sending the message 0000000.

There are 16 pins on the shift register included with this kit. If you orient the shift register chip with the semi-circular notch upward, the pins are numbered starting from the top-left pin. Pins 1 through 8 run top-to-bottom on the left side of the chip. Pins 9 to 16 run bottom-to-top on the right side. Read that again to avoid confusion: pins on the right are numbered bottom-to-top (pin 16 is the top-right pin).

The pins on the shift register do different things. Pin 15 and pins 1–7 are the output pins—those will get connected to the LEDs. A few pins need to be connected to power and ground. The three connections between the SR and the Tessel 2 are a data connection (to send those trains of bytes), a clock connection (to keep everyone in sync) and a latch (for, in part, controlling when data gets pushed out to output pins). You won’t have to mess around with the clock and latch stuff—other than telling Johnny-Five which Tessel 2 pins are connected to those shift-register pins. You just have to decide what data to send to the shift register.

Hardware Hookup

Does this circuit look a little shifty to you? Fear not! Let’s build it and then master using the shift register.

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

  1. Connect the shift register to the breadboard. Look for the semi-circular divot at one of the ends of the chip. That end of the chip should be oriented toward the top of the breadboard. Plug the shift register in so that it spans the center notch.
  2. Connect the eight LEDs. For each, plug the anode (longer leg) into a terminal row on the breadboard and the cathode (shorter leg) directly into the ground power rail.
  3. Connect the current-limiting resistors for the LEDs. Each 100Ω resistor should span the center notch.
  4. Some of the shift register’s pins need to be connected to power or ground. Using jumper wires, connect shift register pins 16 and 10 to the supply power rail. Connect shift register pins 8 and 13 to the ground power rail.
  5. Connect each of the shift register’s output pins to the LED it will control, using jumper wires. Start by connecting the shift register’s Pin 15 to the first LED. Then connect the shift register’s pins 1–7 to the rest of the LEDS, as shown in the wiring diagram.
  6. Connect the shift register to the Tessel 2. Shift register pins 14, 12 and 11 should be connected with jumper wires to Tessel 2’s Port A, pins 3, 4 and 5, respectively (see wiring diagram).
  7. Use jumper wires to connect the Tessel 2’s 3.3V and GND pins to the power rails of the breadboard.

Using a Shift Register to Display 8-Bit Values With Johnny-Five

Open your favorite code editor, create a file called shift-register-bits.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your shift-register-bits.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var register = new five.ShiftRegister({
    pins: {
      clock: "a5",
      data: "a3",
      latch: "a4",
    }
  });

  var output = 0b10000000;

  board.loop(100, () => {
    output = output > 0 ? output >> 1 : 0b10000000;
    register.send(output);
  });
});

Type—or copy and paste—the following into your terminal:

t2 run shift-register-bits.js

What You Should See

The program cycles through each LED, lighting one at a time, repeating the pattern forever.

Exploring the Code

Once the board object has emitted the ready event, the program initializes a ShiftRegister instance object that will be used to send data to the shift register component in the circuit.

language:javascript
var register = new five.ShiftRegister({
  pins: {
    data: "a3",
    clock: "a5",
    latch: "a4",
  }
});

In Experiment 9: Using an H-Bridge Motor Controller you learned about Johnny-Five’s simplified argument forms, which can applied to every component class constructor; here, we can actually rewrite the above arguments as:

language:javascript
[ "a3", "a5", "a4" ]

Which means:

language:javascript
[ data, clock, latch ]

Therefore, the entire initialization could also be written as:

language:javascript
var register = new five.ShiftRegister([ "a3", "a5", "a4" ]);

Much nicer! These argument forms are illustrated in the Johnny-Five ShiftRegister component initialization API docs.

The next line sets an initial value of 128, represented as Binary Integer Literal:

language:javascript
var bits = 0b10000000;

We briefly looked at Binary Integer Literals in Experiment 3: Reading a Potentiometer, but this time we’ll take a closer look. Open the Node.js REPL by typing node and pressing ENTER in your terminal. Once open, type any of the following, each followed by pressing the ENTER key:

language:javascript
0b0
0b01
0b0101
0b1010
0b1111
0b10000
0b1111111
0b10000000
0b11111111
0b100000000

These are called Binary Integer Literals because they are literally the binary representation (1s and 0s) of an integer. Each 1 and/or 0 represents a single bit. The 0b prefix tells JavaScript to interpret the 0s and 1s that follow as a binary number.

The result of each, in order, must be:

language:javascript
0
1
5
10
15
16
127
128
255
256

As a nasty hack, you could figure out the minimum number of bits necessary to represent, in binary, a given number by writing:

language:javascript
var value = 255;
console.log(value.toString(2).length); // 8

All numbers have a toString(radix) method, which converts a number to a String. The radix argument tells what base to use when translating the number. 2 is binary. 10 is decimal. It can accept any radix between 2 and 36.

Since we can now literally see how many bits are in a number, we can move onto the next piece of code:

language:javascript
board.loop(100, () => {
  output = output > 0 ? output >> 1 : 0b10000000;
  register.send(output);
});

The first line in the looping callback function is assigning a new value to the variable output based on whether the present value of output is greater than zero.

If it is, then shift the actual bits of the present value of output one place to the right (this shoves one of the 0s off of the right side). If it’s not greater than zero, assign the value 128 (shown in binary integer literal form, 0b10000000), which will make the LED pattern start back at the beginning again. The last line of the function sends the output to the shift register.

Here’s the effect of every call to the loop callback, as it would appear over eight iterations:

B7B6B5B4B3B2B1B0
10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001

B means “Bit”, (i.e., Bit 7 = B7). B0 is the right-most bit.

Binary Counting

Since we have eight LEDs, and we know it’s helpful to think of our output in terms of range as 8-bit, let’s visually count out the full range of 8-bit numbers (0–255) using the LEDs! Open your favorite code editor, create a file called shift-register-count.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your shift-register-count.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", function() {
  var register = new five.ShiftRegister([ "a3", "a5", "a4" ]);
  var output = 0b00000000;
  board.loop(100, () => {
    register.send(output);
    output++;
    if (output > 0b11111111) {
      output = 0b00000000;
    }
  });
});

Instead of bit-shifting using the bitwise operator >>, output++increments the value of output by 1 on each iteration. If output gets too big (greater than 255, or 0b11111111), reset it to 0 (0b00000000).

Type—or copy and paste—the following into your terminal:

t2 run shift-register-count.js

What You Should See

The LEDs will be lit to represent each number from 0–255 in its binary form, one number at a time.

Building Further

  • Try using Johnny-Five’s Expander class, with the 74HC595 controller to treat each LED as a single Led instance.

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using:
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Experiment 14: Driving a Seven-Segment Display

Introduction

You’re flush with newfound knowledge about shift registers from Experiment 13: Controlling LEDs with a Shift Register. Now let’s tackle another application of what you’ve learned: using a shift register to control a seven-segment display.

Preflight Check

Whoa there, Turbo! If this is your first experiment with the Johnny-Five Inventor's Kit (J5IK) and the Tessel 2, there are a few things you gotta do first:
  1. Set up your computer
  2. Configure your Tessel 2
Note: These steps only have to be done once, but they are required. Internet connection may be necessary!

Suggested Reading

The following tutorial provides in-depth background on some of the hardware concepts in this experiment:

Parts Needed

You will need the following parts for this experiment:

  • 1x Tessel 2
  • 1x Breadboard
  • 1x Shift Register
  • 1x Seven-Segment Digit
  • 1x 100Ω Resistor
  • 17x Jumper Wires
Using a Tessel 2 without the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
24
Jumper Wires - Connected 6" (M/M, 20 pack)

PRT-12795
$1.95
1
Tessel 2

DEV-13841
$44.95
Shift Register 8-Bit - SN74HC595

COM-13699
$0.95
7-Segment Display - LED (Red)

COM-08546
$0.95
1
Resistor 100 Ohm 1/4th Watt PTH - 20 pack

COM-13761
$0.95

Introducing the Seven-Segment Display

seven seg pic

The seven-segment display is essentially eight LEDs in one. Different combinations of seven individual LEDs can be lit to represent decimal numbers (the eighth LED is a decimal point). This display is a common-anode display. If you flip the display assembly over, you will notice that the display has a whole bunch of pins. These pins (A–G) correspond with each segment of the display, with one (DP) for controlling the decimal point (the display in your kit may have two decimal points, but only one is wired).

These letters correspond with the following pins on the back of the display. You can use the following image and table to figure out the corresponding segment and pins to use for hookup.

alt text

Pin Letter
1 E
2 D
3 +
4 C
5 DP
6 A
7 A
8 + (unused in this experiment)
9 F
10 G

Hardware Hookup

This circuit is leveling you up from Experiment 13; it’s time to get counting!

Pay special attention to the component’s markings indicating how to place it on the breadboard. Polarized components can only be connected to a circuit in one direction.

Build the Seven-Segment Circuit

alt text

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

Note: Your seven-digit display may be larger than indicated in the wiring diagram. It may partially cover the breadboard sockets on one side. You can still connect jumper wires to those slots—you'll just have to gently but firmly push them in as it's a bit of a tight squeeze. But we assure you it can be done!
  1. Connect the shift register to the breadboard. Make sure the semi-circular notch is toward the top of the board.
  2. Connect the seven-digit display to the breadboard, near the bottom, with the decimal point on the right.
  3. Make the connections with jumper wires between the shift register and the seven-segment display as shown. There are eight connections, one for each of the shift register’s output pins. You should have two remaining (non-connected) pins on the seven-segment display.
  4. Connect the middle (third down) pin of the seven-segment’s right (decimal) side to the supply power rail through a 100Ω resistor (recall: this is a shared-anode component; we can use a single current-limiting resistor for all of the eight LEDs). This leaves one pin of the display not connected, which is expected.
  5. Make the connections between the shift register and the Tessel’s GPIO pins. Shift register pins 14, 12 and 11 should be connected with jumper wires to Tessel 2’s Port A, pins 3, 4 and 5, respectively (see wiring diagram).
  6. Connect the shift register to the power rail with four jumper cables (pins 8 and 13 to ground, pins 10 and 16 to supply).

Using a Shift Register to Control a Seven-Segment Digit With Johnny-Five

Open your favorite code editor, create a file called shift-register-digit.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your shift-register-digit.js file:

language:javascript
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel()
});

board.on("ready", () => {
  var register = new five.ShiftRegister({
    pins: [ "a3", "a5", "a4" ],
    isAnode: true,
  });
  var number = 0;

  board.loop(1000, () => {
    register.display(number);

    number++;

    if (number > 9) {
      number = 0;
    }
  });
});

Type—or copy and paste—the following into your terminal:

t2 run shift-register-digit.js

What You Should See

The seven segment display will count from 0 to 9 and start over.

Exploring the Code

Once the board object has emitted the ready event, the program initializes a ShiftRegister instance object that will be used to send data to the shift register component in the circuit. In Experiment 13: Shift Register + LEDs, we covered short-hand initializations, but there’s a new isAnode property here:

language:javascript
var register = new five.ShiftRegister({
  pins: [ "a3", "a5", "a4" ],
  isAnode: true,
});

This tells the ShiftRegister component class to initialize an instance that knows how to encode and decode values for an anode digit display—the isAnode property tells ShiftRegister that we’re working with a common-anode output device.

Unlike Experiment 13: Shift Register + LEDs, we don’t have to get into the weeds about how to form each number from the various individual LEDs. Instead, we can use the display(0-9) method to display a complete number. Johnny-Five does the unglamorous work for us.

language:javascript
var number = 0;

board.loop(1000, () => {
  register.display(number);

  number++;

  if (number > 9) {
    number = 0;
  }
});

Variation: Creating a User Input Display

Instead of having the program simply print out the count, let’s control the display with user input. Since we’re running low on jumper wires, let’s get creative with our input source. Go ahead and install the keypress module:

npm install keypress

This will allow us to respond to user input in the terminal itself and react accordingly.

Open your favorite code editor, create a file called input-display.js and save it in the j5ik/ directory. Type—or copy and paste—the following JavaScript code into your input-display.js file:

language:javascript
var keypress = require("keypress");
var five = require("johnny-five");
var Tessel = require("tessel-io");
var board = new five.Board({
  io: new Tessel(),
  repl: false,
});

keypress(process.stdin);

board.on("ready", function() {
  var register = new five.ShiftRegister({
    pins: [ "a3", "a5", "a4" ],
    isAnode: true,
  });
  var number = 0;

  register.display(number);

  process.stdin.on("keypress", (character, key) => {
    if (key) {
     if (key.name === "q") {
         process.exit(0);
      }

      if (key.name === "up") {
        number++;
      }

      if (key.name === "down") {
        number--;
      }

      if (number > 9) {
        number = 0;
      }

      if (number < 0) {
         number = 9
      }

    } else {
      number = character;
    }

    register.display(number);
  });

  process.stdin.setRawMode(true);
  process.stdin.resume();

  console.log("Press 'q' to quit.");
});

Type—or copy and paste—the following command into your terminal and press enter:

t2 run input-display.js

What You Should See

alt text

When you press the up or down key on your keyboard, the number displayed will increment by one, or decrement by one. When you press a number key, the number will change to that number.

Exploring the Code

The first addition is the newly required keypress module:

language:javascript
var keypress = require("keypress");

Because we’ll be specifying our own handling of user keyboard input, the Board initialization now tells Johnny-Five not to automatically create a REPL, by settng a repl property to false:

language:javascript
var board = new five.Board({
  io: new Tessel(),
  repl: false,
});

And then, within the the board’s ready event handler:

language:javascript
keypress(process.stdin);

This makes keypress pay attention to stuff going on in process.stdin (that’s a stream for standard input, meaning, roughly, in this case, stuff typed into the Tessel’s REPL). Next, we listen for those keypress events and do something with the data from them (hold that thought).

That’s followed by setting process.stdin to raw mode and telling it to resume, which means “treat this as a raw device and keep going: open up the input flow and let ‘er rip.”

language:javascript
process.stdin.on("keypress", (character, key) => {
  // ...
});

process.stdin.setRawMode(true);
process.stdin.resume();

Within the handler, it’s time to do something with the data we have from the keypress event:

language:javascript
if (key) {
  if (key.name === "q") {
    process.exit(0);
  }

  if (key.name === "up") {
    number++;
  }

  if (key.name === "down") {
    number--;
  }

  if (number > 9) {
    number = 0;
  }

  if (number < 0) {
    number = 9
  }
} else {
  number = character;
}

register.display(number);

First, the program checks if the key variable is set—if it is, then it knows it hasn’t received a press from a number. For whatever reason, the keypress module doesn’t treat presses on number keys as a “key,” but only provides them as a character.

So, if the key variable is set, it’s anything but a number; otherwise it is a number.

Now:

  • If it’s not a number, and it’s a press of the “q” key, exit the program.
  • If it’s not a number, and it’s a press of the “up” key, increment by 1.
  • If it’s not a number, and it’s a press of the “down” key, decrement by 1.
  • Then, “wrap” the number at 0 and 9, such that counts over 9 start back at 0 and counts less than 0 start back at 9.
  • Finally, display the new number value on the seven segment device.

Building Further

  • Add another button to make a counter that goes up and a counter that goes down.

Reading Further

  • JavaScript— JavaScript is the programming language that you’ll be using.
  • Node.js— Node.js is the JavaScript runtime where your programs will be executed.
  • Johnny-Five— Johnny-Five is a framework written in JavaScript for programming hardware interaction on devices that run Node.js.

Resources for Going Further

This experiment guide has just touched the surface when it comes to what you can do with JavaScript, Johnny-Five and the Tessel 2. We have collected a number of resources to help you get a deeper understanding of Node.js through other tutorial. We also want you to explore other modules to use and to connect your projects to the larger JavaScript ecosystem. Lastly, we have a number of project tutorials that will get you started with your Tessel 2 and J5IK that go beyond this guide and dive into other concepts a little deeper.

Lastly, we would greatly appreciate you sharing your Tessel and J5IK projects with us on hackster.io. Both Johnny-Five and the J5IK are added to Hackster ready for you to create a new project!

JavaScript and Node.js Tutorials

  • CodeCademy JavaScript Lessons - Online lesson based tutorial system that tracks your progress!
  • W3School Tutorials - A great website for learning the core of JavaScript through interactively playing with the code.
  • NodeSchool Tutorials - JvaScript, Node.js and number of other tools and environment tutorials that are created as command line tutorials downloaded and installed through npm.

Useful Node.js Modules

  • Chalknpm install chalk - Change the color of your console text…for the better!
  • usgs-earthquake-reportsnpm install usgs-earthquake-reports - A module that parses USGS earthquake reports based on a number of given options.
  • tessel-avnpm install tessel-av- A module for using Audio Visual USB accessories (webcam and mic) with the Tessel 2!
  • Requestnpm install request- Make HTTP requests in a simple and easy manner.
  • node-ifttt-makernpm install node-ifttt-maker- A Node.js library for the IFTTT Maker Channel
  • phant-clientnpm install phant-client- Interact with a phant (data.sparkfun.com) stream!
  • openweathermapnpm install openweathermap- A Node.js module for collecting weather data from OpenWeatherMap.
  • geo-toolsnpm install geo-tools- A simple module for geocoding and reverse geocoding (Great to use with a GPS!)

Project Tutorials

Check back soon for updated project tutorials!


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado


Load Cell Amplifier HX711 Breakout Hookup Guide

$
0
0

Load Cell Amplifier HX711 Breakout Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t546

Getting Started

The HX711 load cell amplifier is used to get measurable data out from a load cell and strain gauge. This Hookup Guide will show you how to get started with this amplifier using some of the various load cells we carry at SparkFun.

Sparkfun's HX711 load cell amplifier breakout board

What You Will Need:

For this simple hook up guide we will just be hooking up a load cell with the HX711 amplifier, and showing how you would hook up four load sensors with a combinator board and the HX711 amplifier. To follow along, you’ll need:

If you are planning on using load sensors1 you will need to obtain or purchase four units. We recommend our Combinator Board to make it easy to turn the four strain gauges into a wheatstone bridge type load cell. (Single strain gauge load cells only have three wires instead of four.)

Suggested Reading

If you aren’t familiar with the following concepts, we recommend reviewing them before beginning to work with the HX711 Load Cell Amplifier Board.

1. [Strain gauges are two wired organized metal foil or wires that are set up in such a way that the resistance changes when it is compressed or stretched. When a strain gauge is placed on something (usually metallic in nature) its resistance changes based on the stress experienced by that something. When a single strain gauge is hooked up to a metallic cell, we are calling that a load sensors, which have three output wires. Load cells usually has four strain gauges hooked up in a wheatstone bridge formation, which have four output wires. For more information on load cells, strain gauges, and wheatstone bridges see our tutorial.]

Load Cell Set Up

Four types of strain gauge load cells, two bar load cell and two disc load cells

A selection of different load cells

Depending on the type of load cell you are using, the configuration of how it should be hooked up to plates or surfaces will change. Below are a few different types of setups.

Bar strain gauge load cell set up in a "Z" formation between two plates

Bar load cell between a two plate configuration

S type load cell hooked up to two loops

S load cell configuration

SparkFun's strain gauge load cell combinator board hooked up to a home scale, possible configuration for four disc load cells

Possible four disc load cell configuration in something like a bathroom scale

Two bar strain gauge load cells

Bar strain gauge based load cells

Usually with larger, non-push button bar load cells you will want to hook up the load cell between two plates in a “Z” shape, with fitting screws and spacers so that the strain can be correctly measured as shown below:

Bar strain gauge load cell set up in a "Z" formation between two plates

Note that only one side of the load cell is screwed into each board. This provides a moment of force, or torque, on the strain gauge rather than just compression force, which is easier to measure and much more accurate.

Two disc strain gauge load cells

For smaller, push-button or disc load cells, you will want to make sure to screw in the disc to a bottom plate (or surface you are measuring force against), and center the beam, plate, or whatever else you are wishing to measure the force of onto the “button” on the top. Usually another plate with a hole is used to make sure whatever you are measuring is hitting the same spot on the load cell each time, but it is not necessary.

Make sure to read the datasheet for the load cell you are using and get the correct screws to fit into it.

  • Note: If you are hooking together four of the SparkFun Load Sensors using the Combinator board, you should position the four load sensors equidistant from each other, just like the bathroom scales shown in this tutorial.

Load cell measurements can be off by +/- 5% due to a range of things including temperature, creep, vibration, drift, and other electrical and mechanical interferences. Before you install your scale, take a moment and design your system to allow for easy calibration or be able to adjust the code parameters to account for these variations.

Hardware Hookup

Sparkfun's HX711 load cell amplifier breakout board

The HX711 Load Cell Amplifier accepts five wires from the load cell. These pins are labeled with colors; RED, BLK, WHT, GRN, and YLW. These colors correspond to the conventional color coding of load cells, where red, black, green and white wires come from the strain gauge on the load cell and yellow is an optional ground wire that is not hooked up to the strain gauge but is there to ground any small outside EMI (electromagnetic interference). Sometimes instead of a yellow wire there is a larger black wire, foil, or loose wires to shield the signal wires to lessen EMI.

Load cell wiring, wheatstone bridge formation

Four strain gauges (SG1 through 4) hooked up in a wheatstone bridge formation

Different strain gauge load cell output wires

Here we have a large black wire, some loose wires, and foil and loose wires respectively as EMI buffers

In General, each load cell has four strain gauges that are hooked up in a wheatstone bridge formation as shown above.

The four wires coming out from the wheatstone bridge on the load cell are usually:

  • Excitation+ (E+) or VCC is red
  • Excitation- (E-) or ground is black.
  • Output+ (O+), Signal+ (S+)+ or Amplifier+ (A+) is white
  • O-, S-, or A- is green or blue

Some load cells might have slight variations in color coding such as blue instead of green or yellow instead of black or white if there are only four wires (meaning no wire used as an EMI buffer). You might have to infer a little from the colors that you have, but in general you will usually see these colors.

If the readings from the HX711 are opposite of what you are expect (for example the values decrease as you increase weight) simply reverse the O+/O- wires.

Once the load cell is is hooked up to the amplifier, you can hook up VDD, VCC, DAT, CLK, and GND to a microcontroller such as a RedBoard or Arduino board.

Note VCC is the analog voltage to power the load cell. VDD is the digital supply voltage used to set the logic level.

PRO TIP: In many cases, you can just short VCC and VDD together. If your microcontroller uses 3.3V logic however, you'll want to connect VCC to 5V and VDD to 3.3V.

Strain gauge load cell hooked up to SparkFun's HX711 amplifier breakout board

Load cell wires hooked up to the HX711 Amplifier board

The example code has DAT and CLK hooked up to pin 3 and 2 respectively, but this is easily changed in the code. Any GPIO pin will work for either. Then VCC and VDD just need to be hooked up to 2.7-5V and GND to ground on your microcontroller.

Fritzing diagram of HX711 amplifier connected to a redboard

Fritzing diagram of HX711 amplifier connected to a RedBoard

Now, if you would like to set up four single load sensors with our combinator board and amplifier, connect the five pins labeled RED, BLK, WHT, GRN, YLW to the matching pins on the HX711. Next, connect each of the four load sensors to the following pins:

  • Red → +
  • Black → -
  • White → C

SparkFun's strain gauge load cell combinator board

The combinator board also has room for an 8 pin RJ45 socket, which can be used to connect your project via Ethernet cables for long distance applications.

Another nice thing about our combinator board is that most home scales use four single strain gauge load sensors, so this is a handy board for hacking your own scales at home!

SparkFun's strain gauge load cell combinator board hooked up to a home scale

Hacked home scale’s four load sensors hooked up to our combinator board

alt text

Example of a single strain gauge, or load sensor. Here RED is the center tap

For load sensors, there isn’t a set color coded standard. Comparing the scale pictured above with the load sensor schematic, while the black wires matched, the red and white wires were swapped. Also, only two of the four sensors used a white wire for the ‘center tap’ of the load sensor, the other two used green. I connected the black wires to “-”, the red to “+”, and the white and green wires to “C”.

To determine how to hook up your single strain gauge load cells to the combinator, measure the resistance between the three wires. You should find a larger resistance (close to double) between a pair. In our example the resistance between red and black was 1.6 kΩ, and the resistance between white/green and red was 800 Ω. Therefore, the center tap to the strain gauge is the white/green wire. The center tap or center pin of your strain gauge connects to the “C” pin on the combinator. The larger resistance wires (red and black in this example) connect to the “+” and “-” pins on the combinator.

The combinator board hooks up the four load sensors in such a way that two resistors in the wheatstone bridge configuration are constant values and the other two are variable in this way:

alt text

To hook up the combinator board to the HX711 match the RED, BLK, WHT, and GRN pins

Once you have the combinator board successfully soldered to the twelve wires, you can now connect it to the HX711 amplifier board via the 4 standard load cell wires. You can use short jumper wires or if your electronics are a long distance away from your scale consider using an RJ45 connector and an ethernet cable to connect the combinator to the HX711 amplifier.

Arduino Code

Now that you have your load cell, amplifier, and microcontroller hooked up, you can add your code and start calibrating your setup.

You can download the most up-to-date code and libraries from the link below.

GitHub Repository

If you have never worked with downloading Arduino libraries or need a quick reminder you might want to take a look at our tutorial on Installing Arduino Libraries.

Or you can easily get started and running with everything in Codebender!

The first thing you will want to work with is the calibration code: “SparkFun_HX711_Calibration”:

Once you have calculated your calibration factor of your load cell set up, you can move on to other code, such as the simple scale output example code, “SparkFun_HX711_Example”:

Check out the other example code in the Github repo, or Codebender for powering down the HX711 (github, codebender) and known zero startup (github, codebender).

Resources and Going Further

Want to know more? Check out this tutorial if you haven’t already:

Getting Started with Load Cells

June 11, 2015

A tutorial defining what a load cell is and how to use one.

Need even more? Check out this awesome article wheatstone bridges and load cell types.


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

OpenScale Applications and Hookup Guide

$
0
0

OpenScale Applications and Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t374

Overview

The SparkFun OpenScale makes reading load cells easy. Attach a four-wire or five-wire load cell of any capacity, plug OpenScale into a USB port, open a terminal window at 9600bps, and you’ll immediately see mass readings. To learn more about load cells see our tutorial on Getting Started with Load Cells. This board also has the Load Cell Combinator built in so you’ll be able to read four load sensors as 1 load cell as well.

OpenScale

OpenScale combines the HX711 breakout board with an Atmega328P running Arduino and extensive pre-loaded configuration firmware to create an off-the-shelf solution for load cell reading.

OpenScale was designed for projects and applications where the load was static (for example a bee hive) or where constant readings are needed without user intervention (for example on a conveyor belt system). A load cell with OpenScale can remain in place for months without needing user interaction.

OpenScale makes it easy to zero and calibrate your scale via a simple to use configuration menu. Serial output and control is available through the mini-B USB port or through an FTDI compatible connection. This allows OpenScale to be attached seamlessly with a datalogger (OpenLog) or to a wireless Bluetooth transmitter (such as SparkFun Bluetooth Mate Silver). In the bee cale application , OpenScale is hooked up to Blynk Board and the data collected is pushed to data.sparkfun.com.

A precision digital temperature sensor is included on OpenScale to report the local temperature. An external connection is also available for a DS18B20 compatible temperature sensor to take temperature readings of the load cell. Please note that OpenScale reports the local and remote temperature readings but it does not alter the scale reading due to temperature fluctuations. It is up to the user to properly calibrate and post process these temperature readings to get the maximum scale accuracy.

OpenScale is fully open source hardware and software. OpenScale comes with a Arduino Uno compatible bootloader (STK500, 115200bps, 16MHz). Making modifications to the firmware is as easy as loading new code onto an Arduino. You can find the all the source in the OpenScale repository on github.

Interface Specifications

OpenScale communicates at TTL level 9600bps 8-N-1 by default. The baud rate is configurable from from 1200bps to 1,000,000bps. Most users will use the USB mini-B connection to connect to a computer. See How to Install FTDI Drivers tutorial for more information. Users may also communicate via the 6-pin serial interface:

alt text

6-pin connector on the edge of OpenScale

This is the common FTDI-type pinout. This interface is useful if you need to attach OpenScale to an embedded system that does not support USB host. The minimum connection is three wires: 5V, GND and TX.

OpenScale is configured via visible ASCII characters and a text menu system. Attach OpenScale via USB and use your favorite terminal software to open the COM port that OpenScale is connected to. By default OpenScale communicates at 9600bps 8-N-1. You should see the following displayed every few hundred miliseconds:

OpenScale output

Pressing ‘x’ at any time will bring up the configuration menu.

Attaching the Load Cell

alt text

DS18B20 external temperature sensor

alt text

200kg load cell

OpenScale uses 3.5mm screw terminals to connect to the load cell wires and external temperature sensor. The SparkFun Mini Screwdriver fit the screws well as does the Pocket Screwdriver Set.

alt text

Sparkfun Load Cells follow the general color convention described below

Most load cells will have a Red/Black/White/Green wire color configuration. Insert these wires into the screw terminal and tighten the terminal to finger tight. A few load cells use a blue wire in place of the green wire - don’t worry, it will still work! Load cells with a large capacity or a long connecting cable may have an additional yellow wire that is used to shield the four signal wires. If you have this wire available attach it as well.

Three wire load sensor

This load sensor has only three wires

If you are using discrete strain gauges (for example our 50kg load sensor) you will need to use the Load Cell Combinator to combine four strain gauges into a wheat stone bridge configuration. See the Load Cell Combinator Hookup Guide for more information. Openscale also has the Load Cell COmbinator built-in. The markings UL, UR, LL and LR stand for upper left, upper right, lower left and lower right respectively. Just like you would see in a bathroom scale. The C mark is for the “center tap” which is explained in the strain gauge tutorial.

alt text

Load Cell Combinator

Physical Characteristics

Dimensions

alt text

OpenScale is approximately 1.8 by 2.25”.

Voltage

OpenScale is designed to be powered over USB but can be externally powered from a regulated 5V source.

Current Consumption

Different types of load cells will utilize different sized resistors in its wheatstone bridge. The smaller the resistors the greater the current at 5V. Additionally, OpenScale will attempt to power cycle the load cell to reduce localized strain gauge heating and overall power consumption. The status LED and USB-to-Serial ICs will also affect the current usage. Those factors in mind, the user can expect around 80 to 100mA at 5V for a regular setup.

The base current consumption is approximately 18mA under the following conditions:

  • 5V regulated into 5V pin on FTDI connector (no USB connected)
  • No load connected
  • Status LED disabled

It is recommended to use the Serial Trigger mode of OpenScale for low power applications. This mode will allow OpenScale to power down the instrumentation amplifier and enter the lowest possible power state.

Configuration

Once OpenScale is connected and reporting to your terminal window press ‘x’ to bring up the configuration menu.

All settings are stored in non-volatile EEPROM and loaded during power up.

Text configuration menu

Press the corresponding letter or number to control that setting.

Note: If you get OpenScale into an unknown configuration you can reset the board to safe defaults. Power down OpenScale, attach a jumper from RX to GND on the serial connector, then power up OpenScale. You should see the status LED blink rapidly for two seconds then at 1Hz. This indicates OpenScale has been reset to 9600bps. This will also reset all system settings to safe defaults.

Tare Scale to Zero

Use this to tell OpenScale what the base reading is. Remove everything from the scale that will not be there permanently and tare scale to zero. OpenScale will take a series of readings, average them, and store this value in non-volatile EEPROM. At each power-up OpenScale will use this value as ‘zero’.

Calibrate Scale

Use this to calibrate your scale to a known value. First remove everything from the scale that will not be there permanently and tare the scale to zero (see ‘Tare scale to zero’). Next place an accurate and known mass onto your scale. If you are looking for sub +/-5% accuracy of your scale we recommend you leave this mass in place for around 30 minutes to allow for load cell creep (see ‘Calibration Suggestions’ for more information). Next select ‘Calibrate scale’ from the configuration menu.

Calibration sub menu

Calibrating to a 45 pound known mass

Next use the ‘a’ and ‘z’ keys to increase or decrease the reading to match your mass. Holding ‘a’ or ‘z’ will change the calibration factor at a faster rate. Press ‘x’ once the reading closely matches the known weight.

Timestamp

This will enable or disable the millisecond timestamp shown at the start of every reading. The default is to show a timestamp.

Set Report Rate

This controls how often OpenScale reports a reading. This is handy if you need a very accurate amount of time between readings or wish to limit the number of data points. Once selected from the configuration menu use the ‘a’ and ‘z’ keys to increase or decrease the time between readings. The default is 5Hz or 200ms between reports.

The report rate is calculated at power up and when the user selects ‘Set report Rate’ from the configuration menu. The fastest possible report rate is about 10.98Hz or 91ms between reports. This rate is affected by many things:

  • Faster baud rates (115200bps) allows for faster printing of text
  • Turning off time stamp and temperature readings require less characters to be printed
  • Lowering the ‘average amounts’ setting will decrease the amount of time it takes to read the load cell.
  • If attached, the remote temperature sensor takes around 19ms to read
  • Decreasing the number of decimals decreases the number of characters to print

Set Baud Rate

This controls the baud rate that OpenScale communicates. OpenScale runs at 9600bps by default. Type in the baud rate you would like and press return. OpenScale will immediately go to this baud rate. This is configurable from 1200 to 1,000,000bps but standard baud rates (multiples of 1200: 9600, 57600, 115200, etc) are recommended. OpenScale will attempt to go to the user inputted baud rate but the timing errors for exotic baud rates may become significant enough to make communication impossible.

Note: If you get OpenScale into an unknown configuration you can reset the board to safe defaults. Power down OpenScale, attach a jumper from RX to GND on the serial connector, then power up OpenScale. You should see the status LED blink rapidly for two seconds then at 1Hz. This indicates OpenScale has been reset to 9600bps. This will also reset all system settings to safe defaults.

Change Units of Measure

This toggles the measurements between pounds (lbs) and kilograms (kgs). Setting the units from lbs to kgs will change the calibration factor to properly convert units. This will also change the text displayed with each report. The default is pounds.

The units are arbitrary and are displayed to make the output easier to visually parse. If you have a very large or very small load cell you may need to calibrate your scale with a different unit (grams for example). To do this follow the standard method for calibration ignoring the displayed units.

Decimals

This controls the number of decimals displayed. The default is two.

Average amount

This controls how many readings to average across. The default is four. Decreasing the average amount will allow for faster report rates but will increase the noise in reports.

Local Temp

This controls reading of the on board temperature sensor. The default is to show the local temperature. This is helpful if you need to calibrate your scale readings with local temperature readings. The onboard sensor is the TMP102 digital temperature sensor. It is very precise but will need calibration by the end user.

Please note that the scale readings do not take the local or remote temperature readings into account. It is up to the user to post process these temperature readings to get the maximum scale accuracy.

Remote Temp

This controls the reading of the off board temperature sensor. The default is to show the remote temperature if a sensor is detected at power on. A DS18B20 one-wire temperature sensor can be connected to the board to read the temperature of the load cell if further accuracy is needed. It is very precise but will need calibration by the end user.

Please note that the scale readings do not take the local or remote temperature readings into account. It is up to the user to post process these temperature readings to get the maximum scale accuracy.

Enable Status LED

By default the onboard status LED blinks with every other reading. This can be turned off to conserve power and users’ eyesight.

Serial Trigger

Once powered OpenScale will report a weight reading after each report period has passed (see Set Report Rate). Once the serial trigger option is enabled OpenScale will stop reporting and wait to be triggered by an incoming serial character. Any incoming character will cause OpenScale to wake up, take a reading, report, and return to low-power sleep. This setting is valuable for remote applications where power saving is important. To maximize power savings it is recommended that the Status LED be disabled as well. The default is to not be triggered by incoming serial characters.

Hardware Features

alt text

Power Cycling

When the report rate is above 500ms OpenScale will automatically turn off the power to the load cell between readings. This saves power and limits the amount of localized heating of the strain gauges. The HX711 requires around 500ms after power-up to stabilize. If the report rate is set below 500ms OpenScale will keep the HX711 on all the time. This will not damage the load cell but it may affect the accuracy of the readings over multiple hours of consecutive readings.

Rate Jumper

alt text

The Rate jumper selects between two rates: 10 samples per second (SPS) or 80 samples per second. By default there is a short between the two pads on the board connecting the HX711 RATE pin to ground and setting the rate at 10SPS. This decreases the sample input noise to 50nV (makes the readings less noisy) but increases the startup time (from power save mode) to 400ms.

Opening the jumper will set the sample rate to 80SPS, increasing the noise to 90nV, and decreasing the startup time to 100ms. Open the jumper by cutting this jumper with a hobby knife. The jumper can be closed again with solder if necessary.

Local Temperature Sensor

alt text

OpenScale has a built-in TMP102 digital temperature sensor. When enabled via the configuration menu OpenScale will print the temperature in Celsius with the user selected number of decimals. The TMP102 sensor is very precise but calibration will be needed for the greatest accuracy.

External Temperature Sensor

alt text

There is a 3-pin 0.1” spaced footprint to connect a DS18B20 compatible sensor. A 4.7k Ohm resistor is connected between VCC and the signal pin to allow one-wire communication. The Waterproof DS18B20 Sensor is an excellent way to detect temperatures of a remote load cell.

Please note that the scale readings do not take the local or remote temperature readings into account. It is up to the user to post process these temperature readings to get the maximum scale accuracy.

Fixed and Adjustable Gain

The HX711 features an active low noise programmable gain amplifier with gains of 32, 64 and 128. Use channel B inputs for A+ and A- and you will get an automatic gain of 32. Please refer to the data sheet for specifications and diagrams.

alt text

Calibration Suggestions

Creep is the change in load cell signal occurring with time while under constant load and with all environmental conditions and other variables also remaining constant. Load cells tend to creep meaning they will change their output slightly over time when a weight is left on the scale for long (30+ minutes) periods of time. To calibrate for something such as a bee hive that will be permanently left on a scale:

  • Place everything on the scale that will be the zero state (the hive plus any static ballast)
  • Leave the scale for 30+ minutes
  • Tare the scale with these weights
  • Place two calibration weights onto the scale
  • Leave the scale for 30+ minutes
  • Calibrate the scale to this combined weight
  • Remove one of the calibration weights and verify scale output

More information about load cells and creep can be found here. Creep is also load cell specific. You will find a section on creep in the data sheet for your specific load cell. This calibration method may need to be repeated every season with changing temperatures and humidity.

Upgrading the Firwmare

From time to time there will be new features for OpenScale. Using the Arduino IDE it is very easy to load new firmware or your own custom firmware onto OpenScale.

OpenScale ships with the Optiboot serial bootloader (115200bps, 16MHz). This allows the board to be reprogrammed under the Arduino IDE by selecting ‘Arduino Uno’ on the boards submenu.

To compile and load the latest version of firmware onto your OpenScale:

  • Connect OpenScale to your computer over USB. Install any needed FTDI drivers and verify that a new COM Port has appeared on your computer
  • Download the Arduino IDE version 1.6.3 but the latest Arduino IDE version should also work
  • Download the OpenScale firmware either directly from the GitHub repo or by checking out the repository (more advanced and not necessary for most people)
  • Download and install bogde’s HX711 library. Read How to install an Arduino library for more information.
  • Open the OpenScale.ino sketch located in the /firmware/OpenScale/ directory and hit Verify
  • Select the “Arduino Uno” under the Tools->Boards sub menu.
  • Select the right COM port under the Tools->Port submenu
  • Upload the code
  • High five your nearest neighbor

OpenScale Firmware

The OpenScale firmware is open source and is available on GiHub on the SparkFun account. Please consider contributing or recommending future features by using the GitHub issue tracker.

Resources and Going Further

Google is your friend. Checkout the Scale Manufacturer’s Load Cell Application Guide. Also search for ‘beehive load cell’ to see how users are monitoring the growth and health of beehives.

Please report typos, inaccuracies, and especially unclear explanations to us by commenting on the tutorial. Suggestions for improvements are welcome and greatly valued. For firmware requests or bugs please post an issue on the github issues page of the OpenScale repo.

Rabbit Research

alt text

For this Hook-up Guide you will the following parts:

SparkFun OpenLog

DEV-13712
$14.95
4
SparkFun OpenScale

SEN-13261
$29.95
MicroSD Card with Adapter - 8GB

COM-11609
$13.95
2
Load Cell - 10kg, Straight Bar (TAL220)

SEN-13329
$6.95
3

I moved to Colorado about seven months ago from Las Vegas, NV. I’ve never had grass. I had rocks and pavement. My home in Loveland has a 1/3rd of an acre of grass and we love it (Moose too). At first I though the 4 rabbits were cute but they started to reproduce and now I’ve got more than 10. My grass has become patchy from their insatiable tastes for backyard greens. I won’t even bring up all the tiny turds I sweep on the regular but I just did. I am determined to put an end their grass lust.

Enter OpenScale. My plan is to create a inviting and friendly trap with an old dog house, fill it with rabbit food, keep a scale under the feeder and log and use the weight measurement along with the time stamp to track when the little varmints feed. After a sufficient amount of data is collected, I will remove the dog house and set my sprinklers to go off during feeding times in an effort to deter these adorable lawn destroyers. In the event there is no pattern to their feed times I will give up, add an additional dog house with gourmet food and hope they keep off the grass.

alt text

An $8.00 kitchen scale found on Amazon.com

alt text

Opened it up to show that it is simply a 10kg load cell mounted really well

This is a kitchen scale, ripped apart and put back together with OpenScale. You can see in the picture above that inside is just simple a 10kg load cell, like the Load Cell SparkFun sells. I didn’t want to change the mounting of the load cell since that is the trickiest part. so I added some colored wire to easily hook up to OpenScale’s screw terminals.

Hardware

alt text

The connections are straightforward. The load cell is hooked up by matching the colored wires to the corresponding screw terminal on OpenScale. OpenLog is connected through the “Serial Out” port although only TX to RX, 5V to VCC and GND to GND (OpenScale to OpenLog order) are necessary for logging the data. Power through USB and open a serial terminal at a baud rate of 9600. It also helps to change the setting at the bottom to “No Line Ending” to keep the config menu from popping up a couple of times. From here you can tare, callibrate and weigh. To get your application mobile add an external power supply with a rechargeable battery pack, solar cell along with the Sunny Buddy and your offsite weigh scale will be self sustaining.

Software

There is no additional software needed! But there are some steps in the config menu that need to be completed. When your project is put together, power the OpenScale through USB and open a serial terminal window. I just use the terminal in Arduino. To keep the config menu from popping up several times in the monitor change the setting at the bottom right to “No line ending”. Send the command “1” to tare to scale and send the command “2” to calibrate and you’ll be ready to go.

alt text

Calibrating

Final Thoughts

OpenSale is versatile product with the capabilities to solve real world problems. Tim, the Enchanter, could have used OpenScale to trigger a catapult or tiny guillotine. It could have prevented all the blood shed.


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Connectivity of the Internet of Things

$
0
0

Connectivity of the Internet of Things a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t534

Communication Protocols for Internet of Things

Connectivity

Source

Connectivity, it is one of the main things to keep in mind while developing any Internet-of-Thiongs (IoT) project.

The first few questions that pop up in my head when I embark on any new IoT project are:

  • How do I want it to be connected?
  • Do I have any power or range constraints?
  • What would be my data rate?
  • What network infrastructures are currently available?

I am sure a lot of you would have the same questions when starting any IoT project. Sometimes you have an idea about what communication protocol you want to use, but it doesn’t hurt to do your research and make sure that would be the most suitable for your application.

Fortunately, there are a bunch of network infrastructures and communication protocols available. Unfortunately, there are so many that they might render you confused.

In this tutorial, we will discuss all (well, most) of the popular communication protocols and how to pick the most suitable one for your project. We will also go into detail about the pros and cons of each:

  1. WiFi
  2. Thread
  3. ZigBee
  4. Bluetooth
  5. RFID and NFC

This is not the full list of connection types, but these will help you get started with most any IoT project.

Network Topology

It is important to understand the various network protocols we will mention.

Network topology is the way in which various elements are arranged in any network. It defines physically or logically the structure of the network. I like to view it as a pictorial representation of the network elements and how data moves through them.

AllTopology

Source:www.wikipedia.com

Again, there are a bunch of possible network topologies, but we will keep our scope limited to the ones you would see most often when dealing with IoT-based communication protocols:

  • Point to Point (P2P)
  • Star
  • Mesh
  • Hybrid

Point to Point

P2P

P2P is the simplest topology and has a permanent link between two endpoints. The simplest example of P2P would be the connection in the paper cup-and-string telephones that you might have had fun with as kids, where two nodes (or endpoints) have a dedicated channel for communication. Using switching technologies, P2P can be set up dynamically. Switched P2P topology was the basis of the early telephony.


Star

Star

Source:www.wikipedia.com

In the star network configuration, every node (endpoint) connects to a single central device. The nodes cannot directly communicate with each other; they communicate through the central device. The central device acts as a server, whereas the nodes act as the clients. This is one of the most common configurations and one of the easiest to set up. It is simple to add and remove devices without disrupting the network. The biggest challenge with this kind of network is it has a single point of failure (i.e., the central computer); if the central computer fails, the network fails.


Mesh

FullMeshHalfMesh

Source:www.wikipedia.com

Mesh is the type of network where each node is connected to every other node. A mesh network provides a high amount of redundancy when it comes to network links. Even if one link fails, the nodes can communicate using another link. This is not the most commonly used network topology for obvious reasons of increased costs to establish the redundant links and the complicated nature of the network.


Hybrid

Hybrid networks, as the name suggests, are combinations of two or more basic network topologies. It could be a star-mesh network or a star-ring network. Hybrid networks prove to be more flexible and reliable, as they come with the best of both worlds. But at the same time, they have increased complexity, which makes them expensive to set up and difficult to manage. However, hybrids have their benefits when we require a network with the capabilities of more than one network topology.

Infrastructure and Ad-hoc Networks

Since we are going to talk about wireless networks today, we need to discuss the two basic modes (also referred to as topologies) in which wireless networks operate.


Infrastructure and Ad-hoc Networks

IF-Ad-Hoc

Source

Infrastructure mode is when the wireless network requires a physical structure to support it. This essentially means there should be a medium handling the network functions, creating an infrastructure around which the network sustains.

It performs these typical functions:

  • Providing access to other networks
  • Forwarding
  • Medium access control

In infrastructure-based wireless networks, the communication takes place between the wireless nodes (i.e., endpoints in the network such as your computer, your phone, etc.) and the access points (i.e., the router) only.

There can be more than one access point on the same network handling different wireless nodes.

A typical example of an infrastructure network would be cellular phone networks. They have to have a set infrastructure (i.e., network towers) to function.

When to use an infrastructure network:

  • If you can easily add more access points to boost the range
  • If you want to set up a more permanent network
  • If you will need to bridge to other types of networks (e.g., you can connect to a wired network if required)
The one major downfall with infrastructure networks is that they are costly and time consuming to set up once. So, if you need your device to operate in remote areas where the infrastructure is weak or nonexistent, you cannot rely on infrastructure networks.

Ad-hoc wireless networks, on the other hand, do not require a set infrastructure to work. In ad-hoc networks, each node can communicate with other nodes, so no access point that provides access control is required.

Whereas the routing in infrastructure networks is taken care of by the access point, in ad-hoc networks the nodes in the network take care of routing.

Routing is to find the best possible path between the source and destination nodes to transfer data.

All the individual nodes in an ad-hoc network maintain a routing table, which contains the information about the other nodes. As the nature of the ad-hoc network is dynamic, this results in ever-changing router tables. One important thing to note is that an ad-hoc network is asymmetric by nature, meaning the path of data upload and download between two nodes in the network may be different.

A typical example of an ad-hoc network is connecting two or more laptops (or other supported devices) to each other directly without any central access point, either wirelessly or using a cable.

When to use an ad-hoc network:

  • If you want to quickly set up a peer-to-peer (P2P) network between two devices
  • When creating a quick temporary network
  • If there is no network infrastructure set up in the area (ad-hoc is the only network mode that can be used in areas like this)
As the routing is handled by each node in the network, this uses more resources; as the number of devices connected in an ad-hoc network increases, the network interference increases, which may lead to slower networks.

WiFi

alt text

Source:commons.wikimedia.org

WiFi is one of the most common communication protocols. You probably couldn’t imagine your life without it. From the comfort of our homes to classrooms, cafés and airports, we see WiFi everywhere. The extent of WiFi’s influence in our lives has been so great that now it harbors a source of good SSID puns like this! (Sometimes, mostly they’re bad.)

SSID_Pun


WiFi essentially uses an infrastructure network, which additionally supports ad-hoc networking in infrastructure mode.

Infrastructure mode of wireless communication provides a bridge to other networks, medium access control and forwarding. The network handling functions are placed into the access point (router), and the clients can remain simple (in context of network).

Also, WiFi is a star-based network. The communication goes from wireless nodes (devices) to a wireless access point (router or network controller).

The current standard being used is 802.11ac, which was released in 2013, although the version 802.11n, which was released in 2009, is still prevalent. The 802.11ac offers speeds up to 800Mbit/s whereas 802.11n offered up to 150Mbits/s.

You might have also seen devices that have even older standards of 802.11a/b/g, which are now called legacy devices. However, since WiFi has downward compatibility, old devices continue to work with devices that have new standards.

The range of your device’s WiFi depends on a few factors:

  • Which WiFi standard the device is running. The latest standards obviously offer more range than the older versions.
  • Physical obstructions like walls also play a critical role in determining the range. Therefore, in open spaces the range of the WiFi network would be more than in enclosed spaces with walls and other interfering objects.

To address the weakness of WiFi over other low-powered technologies, an activity was started to standardize low-power WiFi (IEEE 802.11ah). The development of this protocol is being worked on, but its worldwide adaptation is doubtful. One of the main reasons is this is not backward compatible to the existing 802.11bgn networks.

Advantages of WiFi:

  • WiFi has a decent range coverage and can penetrate walls and other obstacles in the way.
  • Adding and removing devices in a WiFi network is a piece of cake.

Disadvantages of WiFi:

  • Obviously, the lack of wires comes at a cost of lower bandwidth. The radio waves of the network might interfere with other equipment.
  • Most importantly, security of WiFi is weaker than its wired counterparts

Now thinking about your project, WiFi is ideal when we want to set up a quick connection between our device (should be WiFi compatible) and the internet. WiFi is designed around the goal of keeping its power consumption limited, so you can run your project on a dedicated battery as well. WiFi should be used when you do not care much about how and when exactly your device should connect and communicate with your server and all you are looking for is hassle-free connection to the internet.

SparkFun has a lot of WiFi-based development boards available for you to explore.

Here are a few project tutorials that walk you through the development of an IoT project using WiFi as a communication protocol:


Internet Datalogging With Arduino and XBee WiFi

How to combine an Arduino, XBee WiFi module, and handful of sensors to create a live stream of "Office Conditions". Storing light, temperature, carbon-monoxide, and methane (for science!) readings on the Internet.

SparkFun Inventor's Kit for Photon Experiment Guide

Dive into the world of the Internet of Things with the SparkFun Inventor's Kit for Photon.

ESP8266 WiFi Shield Hookup Guide

Interface your Arduino with an ESP8266 to give it inexpensive access to your WiFi network and the Internet!

Getting Started with the SparkFun Blynk Board

How to provision a Blynk Board - get it connected to Wi-Fi and Blynk, so you can start Blynking!

Thread

Thread is an open standard for reliable, cost-effective, low-power, wireless D2D (device to device) communication. It was designed specifically for connected home applications.

It came into existence in 2014, when the Thread Group was formed. It now has big organizations like Google, Samsung, Qualcomm, and ARM to design and develop the Thread protocol.

Thread

Source: thread.org

Nest uses Thread network for its Thermostat and Nest Cam products. Thread is designed while keeping in mind the home automation space – to have devices set up and connect easily, have low power consumption for longer battery life and be secure!

It is based on the standard 802.15.4 (6loWPAN) architecture. The best part about Nest is that it is an open protocol that has Internet Protocol version 6 (IPv6) built in.

Devices in Thread

The Thread protocol defines the three main types of devices in the network:

  • Border routers
  • Routers and router-eligible end devices
  • Sleepy end devices

ThreadTopology

Source: Thread Stack Fundamentals 2015


Border Router

Thread has a system with a special type of router called the border router, which provides connectivity from the 802.15.4 network to adjacent networks on different physical layers (e.g., WiFi, ethernet). If one border router fails, another router in the network can assume the role of a border router, ensuring the robustness of the Thread protocol.

Routers

Routers, as the name suggests, provide routing services to the network devices. They are used in commissioning new devices to the network. Generally routers are always active, but they can downgrade to become REEDs (Router-Eligible End Devices). These devices are not used in routing or data transfer in the Thread network but as a redundant end point that can be called to assume the role of a router when needed.

Sleepy End Devices

These are the end points of a Thread network, also called host devices. Host devices are the individual IP-addressed functional equipment like thermostats, security cameras, heaters, etc. These devices can also be referred to as a sleepy child or sleepy node. The router paired directly to the sleepy device is called the parent. The sleepy devices (end points) spend most of their time in the sleep mode and only wake up to transmit data. They only communicate through the parent device (e.g., the Nest thermostat is a sleepy end device).

A typical send cycle for a device might be:
  • Wake from sleep mode.
  • Perform any required startup and radio initialization.
  • Go into receive mode and check if clear to transmit.
  • Go into transmit mode.
  • Transmit data.
  • Get acknowledgment as applicable.
  • Sleep.

In contrast to WiFi, which uses infrastructure mode, Thread uses the ad-hoc mode of networking.


Advantages:

  • IP based, so easier to connect to other IP-based networks. Since it’s based on 802.15.4, existing devices like ZigBee and 6loWPAN can easily migrate to Thread.
  • No single point of failure by architecture, as it is capable of adjusting to network conditions. It supports full mesh-based network topology.
  • Low-power operation, as it offers sleeping devices
  • Secure

Note: Although there is no single point of failure by architecture in Thread networks, a single point of failure may exist due to poor network design.

Disadvantages:

  • Not a very DIY-friendly protocol because of its complexity. Aims at the high-volume home-automation market.
  • Still a very new network protocol that needs time to establish itself

As Silicon Labs and NXP are part of the Thread Alliance, they are pushing development boards that support Thread protocol.

ZigBee

alt text

Source: Zigbee.org

Zigbee, like thread is an alliance of over 200 companies which have collaborated to develop a robust and simple network for home and industrial automation.

Zigbee Design Goals

Zigbee was created for the sole purpose of serving the home and industrial automation, so the design goals are set in accordance to that:

  • Low-power
  • Security
  • Co-existence with other radio networks which use the ISM band.
  • Standardization
  • Low-cost

Similar to Thread, ZigBee is built on top of the IEEE 802.15.4 standard.

ZigbEE specifications fills in the gap left by the 802.15.4 to create a true mesh network but also supports other topologies like Star and Tree.

alt text

Source - AMX - Zigbee White Paper

Devices in a Zigbee Network

There are three types of devices as defined by the Zigbee protocol:

  • Zigbee Coordinator
  • Zigbee Router
  • Zigbee End Device (Node)

Zigbee Coordinator

The coordinator is the brains of the Zigbee network, it commissions devices to the network, stores the security keys and also bridges to other networks. There is only one Zigbee Coordinator in any network.

Zigbee Router

Zigbee Networks may have several routers to serve as intermediate routers or to transmit data within the network.

Zigbee End Device

The end device can only talk to the parent node ( router or coordinator). It cannot talk to other end devices directly. Similar to Thread, these devices are designed by keeping in mind that they spend most of their life times in sleep mode and only wake up to transmit data to the parent.

ZigBee assumes the channels from 11-26 in the 2.4GHz radio band used by most radios. The ZigBee channels have been specifically spaced as to co-exist with Wi-Fi channels without interference, if the channel assignments of both the networks are properly.

alt text

Source - eetimes.com

Note: The best spectral usage for both is achieved by setting the Wi-Fi channels to 1, 6, 11 and Zigbee channels to 15, 20, 25.

Zigbee vs Thread

ZigBee standard faced a big challenge when Thread came into existence in 2014. The ZigBee Alliance has then pushed to introduce their newest protocol called the ZigBee 3.0. They have tried to address the areas, where thread and other networks were better alternatives in the home automation space.

alt text

ZigBee 3.0 came with additional features such as ZigBee RF4CE and ZigBee Green Power.

ZigBee RF4CE - was developed to replace the IR remote with radio based remotes. This is aimed at making an universal remote controller that could be used to control your remote and as well as lights, lamps etc. Also this does away with the point and shoot limitation of IR.

ZigBee Green Power - was developed as an ultra-low power standard to support energy harvesting devices. It ensures very low power consumption by managing the network as such that these devices can be off for the most time.

One major feature that put ZigBee behind thread was IP compatibility. ZigBee 3.0 on the other hand is fully IP compatible. So you can now connect your ZigBee devices to the internet via a router.

Advantages: Pretty much the same as thread

Disadvantages: Short range, Low data speeds

Xbee’s by Digi International are radio communication modules which support the Zigbee Protocol. They can also be loaded with firmwares to support Zigbee Pro and DigiMesh.

To get a quick taste of Xbee, you can check out the following tutorials.

XBee Shield Hookup Guide

How to get started with an XBee Shield and Explorer. Create a remote-control Arduino!

Exploring XBees and XCTU

How to set up an XBee using your computer, the X-CTU software, and an XBee Explorer interface board.

Teensy XBee Adapter Hookup Guide

Getting started with the Teensy 3.1 and XBee. Establishing a serial link.

Bluetooth

alt text

Source: wikimedia.org

Here we will discuss the evergreen Bluetooth Classic radio, as well as the new and coming Bluetooth Low Energy (BLE), which is specifically designed around low-powered devices used in IoT.

Our discussion will be more focused on the BLE part. For a general overview of Bluetooth Classic, check out this awesome tutorial covering the basics of the technology:

Bluetooth Basics

An overview of the Bluetooth wireless technology.
Like other radio technologies. Bluetooth uses the 2.4GHz spectrum in the ISM band. It has a range from 10m up to 100m (at higher transmit powers, and that means higher power consumption!). Bluetooth is again an ad-hoc type of network and provides point to point (P2P) connections.

Bluetooth Classic supports up to one master and seven slaves in one piconet. It also follows the star network topology, which means that other peripherals cannot talk to each other.

A few key things to note are: A master in one piconet cannot be a master in another but a master in one piconet can be a slave in another. Bluetooth Classic can be used to transmit audio, data but not video.

We will now focus our discussion on the BLE protocol and how Bluetooth has evolved because of this technology.


Three Flavors of Bluetooth

Bluetooth Low Energy is a complete divergence from Bluetooth Classic radio. It was designed with a new protocol stack, new profile architecture and to specifically be able to run on low-power sources such as a coin cell battery.

We need to understand that this radio technology has not taken over or replaced the existing Bluetooth Classic radio. This has led to a species of different flavors of Bluetooth, which correlate with each other.

alt text

Source: Bluetooth SIG

Bluetooth technology can be classified into three types of devices:

  • Bluetooth Classic– The traditional Bluetooth having a higher throughput, mostly used for wireless audio and file transmission. The ‘classic’ radio has support for Bluetooth Smart.
  • Bluetooth Smart– Bluetooth Low Energy has been branded as Bluetooth Smart and transmits just state information. It was designed specifically for applications with low-duty cycles (i.e., the radio is effectively on for a short period of time). Bluetooth Smart devices cannot communicate with Bluetooth Classic devices.
  • Bluetooth SmartReady– These devices are essentially the “hub” devices such as computers, smartphones, etc. They support both the “classic” and “smart” devices, just as our smartphones can connect to a Bluetooth speaker to transmit audio and also communicate to a fitness tracker.

Classic vs. Low Energy

BLE uses the same 2.4GHz ISM band as other wireless protocols. In contrast to Bluetooth Classic’s 79, 1MHz wide channels, Bluetooth Low Energy just has 40 Channels, which are 2MHz wide.

alt text

Source

BLE also uses a 1Mbps GFSK modulation, which gives it a higher range than Bluetooth Classic.

BLE uses an adaptive frequency-hopping algorithm to hop amongst the available channels, where only a subset of available frequencies are used and it can quickly recover from loss of packets due to a bad channel. This technique ensures lower energy consumed in the radio. Bluetooth Classic uses a pseudo random hope sequence, changing the transmission frequency 1,600 times a second.

One main thing to note is that BLE allows up to 128 devices to be connected to a single master, in contrast with just seven in classic.


BLE compared with other wireless protocols in respect to wireless application

alt text

Source: Cambridge Silicon Radio


BLE Stack

The BLE stack was specifically designed with low-powered applications in mind.

alt text

Source: blueradios.com


The core of BLE rests in the GAP and GATT profiles. We will limit our discussion to just these today.

Think of Generic Access Profile (GAP) and Generic Attribute Profile (GATT) as analogous to the basic way we communicate and network with the people around us. When you meet someone, you may announce yourself and offer basic information about yourself. If you want to connect with that person, you then exchange other personal information, such as a phone number or email address, to be able to communicate. You no longer need to identify or announce yourself when you meet the person again and can start sharing other information. GAP is the initial meeting phase, when you introduce yourself, and GATT is the phase when you establish a connection with the person and start communication.

Generic Access Profile (GAP)

The GAP defines the mechanisms a BLE device can use to communicate with the outside world.

Advertising

In this phase the device can be in either of the two phases:

  • Broadcasting Phase: Where the device broadcasts public advertising data packets such as device name, signal strength, manufacturing details, etc.
  • Observing Phase: Where the device listens to the advertising packets. There is still no connection between the devices. There can be more than one device observing the same advertiser.

In the process of establishing connection, the devices also assume roles, namely:

  • Peripheral: The broadcasting device assumes the role of the peripheral, forming a pseudo connection to the device and responding to connection request of the central device to provide it with more information before connecting.

  • Central: The observer, when initiating a connection to the advertising device, assumes the role of central device. It can also be considered the master and can connect to more than one peripheral at a time.

Once the connection is established between the peripheral and central devices, the advertising packet is no longer sent. Now the GATT profile has to be utilized to communicate in both directions.

Generic Attribute (GATT) Profile

GATT profile defines the way two BLE devices communicate with each other using attributes such as services and characteristics, which are defined in the attribute protocol.

Similar to GAP, there are certain defined roles that the communicating devices assume:

  • Client: Usually, the central device assumes the role of the client. It typically sends a request to the GATT server. It can read and/or write attributes in the server.
  • Server: Usually, the peripheral assumes the role of the server. It is called the server as it stores these attributes. The server responds to client request and sends the required attributes to it.

Peripheral or central can both act as a server or client, depending on the data flow.

When the connection is being established the central and peripheral decide upon a “connection interval,” which is the time between different connection events.

Further information can be found on the Bluetooth SIG pages listed below:


You can go through the following tutorials and blog posts we already have on Bluetooth and BLE, to get a better understanding of using them directly into your Bluetooth-based IoT project.

RN-52 Bluetooth Hookup Guide

A hookup guide to get you started with the RN-52 Audio Bluetooth Module Breakout Board.

Understanding the BC127 Bluetooth Module

SparkFun has two boards using the BC127; here's what you need to know to use them.

Simblee LilyPad Hookup Guide

The Simblee LilyPad lets you easily integrate Bluetooth Low Energy and mobile apps into your e-textiles projects.

Simblee Concepts

The Simblee module is a powerful but easy to use Bluetooth 4.0 device which allows you to create a GUI from directly within your Arduino code!

RFID and NFC

RFID

alt text

Radio-Frequency Identification (RFID) is a communication method used for tracking and identifying objects wirelessly.

As complicated as it may seem, it is one of the simplest communication methods, which is what makes it ubiquitous and yet invisible. It is used not only in tracking consumer products worldwide, but also in tracking vehicles for toll collection. Hospitals use it to track their patients, and farmers to track their cattle. RFID technology has become a part of our lives, and we might not even be aware of how it affects us.

Simply put, we can think of RFID tags as a close replacement to Universal Product Code or the bar code. But they are more efficient.

The RFID tags have read and write capabilities over traditional bar codes. They can be updated, changed and locked.

RFID technology includes tags and readers.

Tags

The tags are the end points in an RFID system. They store identity information along with other information as required by the purpose of the tag. There are two types of tags:

  • Active Tags: These tags have an on-board power source of some sort, usually a battery, which means they can transmit stronger signals and therefore have more range. This type of tag can periodically transmit a signal irrespective of a reader.

  • Passive Tags: These tags do not have any internal power source and get activated in the vicinity of a reader. Your metro or bus pass is generally a passive tag, which gets activated when you touch it to the reader. These tags harvest the radio energy transmitted by the reader.


Inside of an active RFID tag – note the on-board battery

alt text

Source

A passive tag – note the small size of the tag in comparison

alt text

Source: http://www.harlandsimon.co.uk

Passive RFID tags primarily operate at three frequency ranges:

* Low Frequency (LF) 125 to 134 kHz
* High Frequency (HF) 13.56 MHz
* Ultra High Frequency (UHF) 856 MHz to 960 MHz

Readers

Readers have a similar construction to an RFID tag. They have an antenna to receive and transmit signals to/from the tags. They might be either battery powered or plugged in to a wall outlet, as a reader requires strong RF signals to activate the tag (for passive) when it comes in the vicinity of the reader. The reader is connected to a reader controller, which manages the information read by the reader. The reader may also write or update a tag depending on the application. For example, the reader in subway stations is at the entry point. When the rider places a card (tag) on the reader, it reads the available money in the card and grants the user entry. At the passenger’s exit, it calculates the fare and updates the amount on the card.

RFID tags can have three main components:

  • An Integrated Circuit (IC) for storing identity information, processing it and modulating/demodulating the RF signals
  • An antenna to receive and send the radio signals
  • A power source (battery) if an active tag

The reader, along with the tags, form an RFID system.

Basic RFID System

alt text

Source: www.impinj.com

The image above shows a very basic RFID system. The tag chip is the Integrated Circuit in the RFID Tag. This IC delivers computation, memory and extended features to the tag. The tag chip has an antenna to receive or transmit the information of the tagged item. The receiver’s antenna receives the RF signal and might also provide excitation to a passive RFID tag. The read information is fed to a reader control and management software.

NFC

alt text

Source: techradar.com

Near-Field Communication (NFC) is an RF-based communication protocol. It is a subset of the RFID protocol, which is why it is similar to RFID but has significant differences. NFC has also become a very popular technology, and 9 out of 10 smartphones today are shipped with NFC capabilities. This has enabled contact-less payments such as Apple Pay and Google Wallet.

NFC smartphones pass along information from one smartphone to the other by tapping the two devices together, which turns sharing data such as contact info or photographs into a simple task. Applications like Android Beam facilitate this, whereas in Apple phones NFC can only be used for Apple Pay as of now.

NFC is being used to open car doors in NFC-enabled car keys with car manufacturers such as BMW. You might have also come across advertisements and marketing content that requires you to tap or wave your NFC-enabled smartphone to download an application or get more information about a product.

NFC is designed for very short-range communication (a few centimeters). It is one of the most power-efficient communication protocols. NFC also operates in the 13.56 MHz band, which is used by high-frequency RFID as well. Therefore, NFC can also read HF RFID tags.

NFC has two types of devices (one thing to note is that, in NFC, the device can act as a tag or a reader):

  • Initiator: The device that initiates the communication is labeled as the initiator. It actively generates an RF field that can power the passive target.
  • Target: This is the device that receives the information from the initiator. The target can either be passive (in the case of simple NFC tags) or active for peer to peer communication, such as in smartphones.

RFID vs. NFC

Due to the inherent similarity between these two communication protocols, we often find ourselves asking the differences in the technologies.

RFIDvsNFC

Source: RFIDinsider

Since both NFC and RFID are omnipresent technologies, used with a large set of objects and devices around us, they both are useful protocols when it comes to IoT. These protocols provide a bridge to various objects around us by not just communicating within the tag and the reader but connecting all of them to the internet.

Here are links to a few tutorials and blog posts you might want to review to learn more:


SparkFun RFID Starter Kit Hookup Guide

Learn the basics of Radio Frequency Identification (RFID) and how to get started with the SparkFun RFID Starter Kit.

Going Further

We have witnessed how the internet revolutionized how we communicate and collaborate. The new era of internet is not just about people. It is about the world around us. It is about intelligent connected devices.

The protocols we just reviewed were not all designed with Internet of Things in mind, but still they have proved to adapt quite well to IoT applications.

With the growth of IoT, it is inevitable that newer and tailor-made protocols are in the works specifically to cater to IoT networks. These connected smart devices have requirements different from today’s human-centric internet.

There are three different types of connections in these protocols:

  • Device to Device (D2D) – Where devices must communicate with each other
  • Device to Server (D2S) – Where device data is collected and sent to a server
  • Server to Server (S2S) – Where the server data is shared amongst other servers for analysis or to send back to the device.

alt text

Source: electronicdesign.com

We will talk about four such protocols, touching on all the different types of connections as mentioned above:

  • MQTT (Message Queue Telemetry Transport) – a protocol for collecting device data and transmitting to the servers
  • XMPP (Extensible Messaging and Presence Protocol) – a protocol for connecting devices to people who are connected to servers
  • DDS (Data Distribution Service) – a protocol for fast communication between intelligent devices
  • AMQP (Advanced Message Queuing Protocol) – a protocol designed for effective communications between different servers

MQTT

alt text

MQTT.org offers this definition of MQTT: a machine-to-machine (M2M) IoT connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium. For example, it has been used in sensors communicating to a broker via satellite link, over occasional dial-up connections with health care providers, and in a range of home-automation and small-device scenarios. It is also ideal for mobile applications because of its small size, low power usage, minimized data packets and efficient distribution of information to one or many receivers.

MQTT’s goal is to collect data from many devices and transport the data to the IT infrastructure. It can be one of the best solutions where sensor data from thousands of sensors has to be transported to a single location for analysis.

More information about the MQTT protocol can be found here.

XMPP

alt text

XMPP.org describes it as: the Extensible Messaging and Presence Protocol, a set of open technologies for instant messaging, presence, multiparty chat, voice and video calls, collaboration, lightweight middleware, content syndication, and generalized routing of XML data.

Think of XMPP as a means for the connected devices to discover each other and start chatting – that is, to start exchanging information as we do!

More information on the XMPP-IoT can be found here.

DDS

alt text

Different from MQTT and XMPP, which are device-to-server protocols, DDS uses devices that directly utilize the device data. It is a protocol to distribute the data of one device to another. DDS can effectively deliver millions of messages per second to many simultaneous receivers.

DDS is peer-to-peer communication. Elimination of servers and message brokers simplifies communications, minimizes latency and reduces complexity. It is reliable for IoT applications that require a reliable and high-performance architecture.

More information on DDS can be found here.

AMQP

alt text

AMQP is a server-to-server type of protocol. It sends transactional messages between servers. The main feature of AMQP is reliability, and it is capable of sending thousands of queued transactions without losing any data.

AMQP.org defines the protocol as: an open standard for passing business messages between applications or organizations. It connects systems, feeds business processes with the information they need and reliably transmits onward the instructions that achieve their goals.

It was initially developed for the banking industry as a middleware for tracking and delivering highly important messages. In the IoT paradigm, AQMP is most suitable for server-based analysis functions, where data from different servers need to be communicated for effective analysis.


In conclusion, there is no set best protocol for IoT, which is still in a phase where we cannot standardize it and may never be able to do so. Its diverse nature of applications and millions of different types of connected devices make it unique.

So, the best protocol would be application specific. You may wish to read this blog post exploring MQTT and CoAP protocols for IoT in more detail.


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

MPU-9250 Hookup Guide

$
0
0

MPU-9250 Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t550

Introduction

The MPU-9250 is the latest 9-axis MEMS sensor from InvenSense®. This replaces the popular EOL’dMPU-9150. InvenSense® lowered power consumption and decreased the size by 44% compared to the MPU-9150. “Gyro noise performance is 3x better, and compass full scale range is over 4x better than competitive offerings.” The MPU-9250 uses 16-bit analog-to-digital converters (ADCs) for digitizing all 9 axes.

MPU-9250

The System in Package (SiP) combines two chips: the MPU-6500, which contains a 3-axis gyroscope, a 3-axis accelerometer, and the AK8963, a 3-axis magnetometer.

Suggested Reading

Before getting started, you may find the following links useful:

Board Overview

MPU-9250 <abbr title="printed circuit board">PCB</abbr>

The MPU-9250 Breakout as you will receive it

The board is designed to be smaller than some of our other offerings to fit in smaller projects. To achieve this, the PTHs are wrapped around the boarder of the PCB in three rows of three or four. The top row (J1) is all one need to get most of the functionality of the IMU. These include the I2C and power interface. If space were really tight, one could take a saw and carefully remove all of the other PTHs.

The second most likely to be used set of PTHs are found along the bottom (J3). This includes the address pin, the interrupt pin, and the IO voltage supply for easy interface with a more modern 1.8V processor.

The third, non-breadboard-compatible row (J2) is used for features like running other I2C devices as slaves to this one. For prototyping with these connections, throw your connections on top like you would with an Arduino Pro Mini or similar product.

PTH Connections

The following table summarizes all of the plated through hole (PTH) connections on the breakout board in order found on the board stating in the upper-left corner and wrapping clockwise:

Pin LabelPin FunctionNotes
SCLI2C serial clock
SPI serial port clock
100 or 400 kHz I2C
Up to 1 MHz SPI (20 MHz in certain cases)
SDAI2C serial dataCan also be used for SPI serial data input (SDI)
VDD Power supply+2.4V to +3.6V
GNDGround reference+0V
AUXDAGround reference I2C master serial data, for connecting to external sensors
FSYNCGround referenceFrame synchronization digital input. Connect to GND if unused.
AUXCLGround referenceI2C Master serial clock, for connecting to external sensors
INTInterrupt signalInterrupt digital output (totem pole or open-drain)
CSChip selectChip select (SPI mode only)
VDDIOPower supply for I/O pins+1.71V up to VDD
AD0/
SDO
Address selectionI2C Slave Address LSB (AD0):
   Low: 0b1101000 ➫ 0x68
   High: 0b1101001 ➫ 0x69
SPI serial data output (SDO)

Jumpers

The MPU-9250 Breakout has two solder jumpers, SJ1 and SJ2.

SJ1 comes pre-soldered to short VDD and VDDIO. This reduces the number of power supplies to one with out requiring an external jumper. If the core and IO need to be supplied with different voltages, remove the solder from SJ1.

SJ2 is a two way jumper that comes pre-soldered to connect AD0 to ground. This sets the I2C address to 0x68. It also leaves the PTH for AD0 disconnected and floating. If the solder is moved to connect the center pad with the pad on the left, then the AD0 PTH needs to be connected high or low to chose the I2C address.

Reducing size

As stated earlier, one of the design goals for this breakout was to make the board small. Some projects will require mounting holes, so we threw them on the right side of some v-score on this board. Since the board is only ⅔“ wide and there isn’t enough mass to the left of the mounting holes, there isn’t much of a bending moment.

If you plan to use a breadboard, or secure the IMU securely to a project with something like epoxy, the mounting holes can be snapped off. As shown in the following image. The pliers I had on hand made super easy work of this. The edge of a table should work fine too.

PCB held in pliers ready to be snapped

Board was held with pliers and easily broke hand pressing the other side

PCB snapped in two parts

PCB snapped in two parts

Hardware Connections

The MPU-9250 breakout board runs on 3.3 VDC, so a 3.3V USB to UART bridge such as the SparkFun FTDI Basic Breakout - 3.3V or the SparkFun Beefy 3 - FTDI Basic Breakout can be used to power and bridge communication with a micro controller. In this case an Arduino Pro Mini 328 - 3.3V/8MHz was chosen so logic level translation isn’t needed.

Fritzing diagram of setup

Fritzing diagram of setup

Only 4 connections are needed for I2C communication.

Snapped PCB next to 0.1" header

Minimum parts for a breadboard compatible setup

For stability in the breadboard, another four pins were soldered on: VDDIO, AD0/SDO, CS, and INT.

PCB with breadboard compatible male headers soldered on

PCB with breadboard compatible male headers soldered on

Here is the final setup used for testing.

Setup used for testing

Setup used for testing

Library and Example Code

The example sketch and library are HEAVILY based on the work of Kris Winer. His original work can be found here on GitHub. Our version is mostly a conversion to make it follow the Arduino library format. This is a link to information on the algorithms Kris used for the attitude and heading reference system (AHRS).

To install our library manually grab a copy here, or just use the library manager as detailed in this tutorial.

language:c
/* MPU9250 Basic Example Code
 by: Kris Winer
 date: April 1, 2014
 license: Beerware - Use this code however you'd like. If you
 find it useful you can buy me a beer some time.
 Modified by Brent Wilkins July 19, 2016

 Demonstrate basic MPU-9250 functionality including parameterizing the register
 addresses, initializing the sensor, getting properly scaled accelerometer,
 gyroscope, and magnetometer data out. Added display functions to allow display
 to on breadboard monitor. Addition of 9 DoF sensor fusion using open source
 Madgwick and Mahony filter algorithms. Sketch runs on the 3.3 V 8 MHz Pro Mini
 and the Teensy 3.1.

 SDA and SCL should have external pull-up resistors (to 3.3V).
 10k resistors are on the EMSENSR-9250 breakout board.

 Hardware setup:
 MPU9250 Breakout --------- Arduino
 VDD ---------------------- 3.3V
 VDDI --------------------- 3.3V
 SDA ----------------------- A4
 SCL ----------------------- A5
 GND ---------------------- GND
 */

#include "quaternionFilters.h"
#include "MPU9250.h"

#ifdef LCD
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

// Using NOKIA 5110 monochrome 84 x 48 pixel display
// pin 9 - Serial clock out (SCLK)
// pin 8 - Serial data out (DIN)
// pin 7 - Data/Command select (D/C)
// pin 5 - LCD chip select (CS)
// pin 6 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(9, 8, 7, 5, 6);
#endif // LCD

#define AHRS true         // Set to false for basic data read
#define SerialDebug true  // Set to true to get Serial output for debugging

// Pin definitions
int intPin = 12;  // These can be changed, 2 and 3 are the Arduinos ext int pins
int myLed  = 13;  // Set up pin 13 led for toggling

MPU9250 myIMU;

void setup()
{
  Wire.begin();
  // TWBR = 12;  // 400 kbit/sec I2C speed
  Serial.begin(38400);

  // Set up the interrupt pin, its set as active high, push-pull
  pinMode(intPin, INPUT);
  digitalWrite(intPin, LOW);
  pinMode(myLed, OUTPUT);
  digitalWrite(myLed, HIGH);

#ifdef LCD
  display.begin(); // Ini8ialize the display
  display.setContrast(58); // Set the contrast

  // Start device display with ID of sensor
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(0,0); display.print("MPU9250");
  display.setTextSize(1);
  display.setCursor(0, 20); display.print("9-DOF 16-bit");
  display.setCursor(0, 30); display.print("motion sensor");
  display.setCursor(20,40); display.print("60 ug LSB");
  display.display();
  delay(1000);

  // Set up for data display
  display.setTextSize(1); // Set text size to normal, 2 is twice normal etc.
  display.setTextColor(BLACK); // Set pixel color; 1 on the monochrome screen
  display.clearDisplay();   // clears the screen and buffer
#endif // LCD

  // Read the WHO_AM_I register, this is a good test of communication
  byte c = myIMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);
  Serial.print("MPU9250 "); Serial.print("I AM "); Serial.print(c, HEX);
  Serial.print(" I should be "); Serial.println(0x71, HEX);

#ifdef LCD
  display.setCursor(20,0); display.print("MPU9250");
  display.setCursor(0,10); display.print("I AM");
  display.setCursor(0,20); display.print(c, HEX);
  display.setCursor(0,30); display.print("I Should Be");
  display.setCursor(0,40); display.print(0x71, HEX);
  display.display();
  delay(1000);
#endif // LCD

  if (c == 0x71) // WHO_AM_I should always be 0x68
  {
    Serial.println("MPU9250 is online...");

    // Start by performing self test and reporting values
    myIMU.MPU9250SelfTest(myIMU.SelfTest);
    Serial.print("x-axis self test: acceleration trim within : ");
    Serial.print(myIMU.SelfTest[0],1); Serial.println("% of factory value");
    Serial.print("y-axis self test: acceleration trim within : ");
    Serial.print(myIMU.SelfTest[1],1); Serial.println("% of factory value");
    Serial.print("z-axis self test: acceleration trim within : ");
    Serial.print(myIMU.SelfTest[2],1); Serial.println("% of factory value");
    Serial.print("x-axis self test: gyration trim within : ");
    Serial.print(myIMU.SelfTest[3],1); Serial.println("% of factory value");
    Serial.print("y-axis self test: gyration trim within : ");
    Serial.print(myIMU.SelfTest[4],1); Serial.println("% of factory value");
    Serial.print("z-axis self test: gyration trim within : ");
    Serial.print(myIMU.SelfTest[5],1); Serial.println("% of factory value");

    // Calibrate gyro and accelerometers, load biases in bias registers
    myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias);

#ifdef LCD
    display.clearDisplay();

    display.setCursor(0, 0); display.print("MPU9250 bias");
    display.setCursor(0, 8); display.print(" x   y   z  ");

    display.setCursor(0,  16); display.print((int)(1000*accelBias[0]));
    display.setCursor(24, 16); display.print((int)(1000*accelBias[1]));
    display.setCursor(48, 16); display.print((int)(1000*accelBias[2]));
    display.setCursor(72, 16); display.print("mg");

    display.setCursor(0,  24); display.print(myIMU.gyroBias[0], 1);
    display.setCursor(24, 24); display.print(myIMU.gyroBias[1], 1);
    display.setCursor(48, 24); display.print(myIMU.gyroBias[2], 1);
    display.setCursor(66, 24); display.print("o/s");

    display.display();
    delay(1000);
#endif // LCD

    myIMU.initMPU9250();
    // Initialize device for active mode read of acclerometer, gyroscope, and
    // temperature
    Serial.println("MPU9250 initialized for active data mode....");

    // Read the WHO_AM_I register of the magnetometer, this is a good test of
    // communication
    byte d = myIMU.readByte(AK8963_ADDRESS, WHO_AM_I_AK8963);
    Serial.print("AK8963 "); Serial.print("I AM "); Serial.print(d, HEX);
    Serial.print(" I should be "); Serial.println(0x48, HEX);

#ifdef LCD
    display.clearDisplay();
    display.setCursor(20,0); display.print("AK8963");
    display.setCursor(0,10); display.print("I AM");
    display.setCursor(0,20); display.print(d, HEX);
    display.setCursor(0,30); display.print("I Should Be");
    display.setCursor(0,40); display.print(0x48, HEX);
    display.display();
    delay(1000);
#endif // LCD

    // Get magnetometer calibration from AK8963 ROM
    myIMU.initAK8963(myIMU.magCalibration);
    // Initialize device for active mode read of magnetometer
    Serial.println("AK8963 initialized for active data mode....");
    if (SerialDebug)
    {
      //  Serial.println("Calibration values: ");
      Serial.print("X-Axis sensitivity adjustment value ");
      Serial.println(myIMU.magCalibration[0], 2);
      Serial.print("Y-Axis sensitivity adjustment value ");
      Serial.println(myIMU.magCalibration[1], 2);
      Serial.print("Z-Axis sensitivity adjustment value ");
      Serial.println(myIMU.magCalibration[2], 2);
    }

#ifdef LCD
    display.clearDisplay();
    display.setCursor(20,0); display.print("AK8963");
    display.setCursor(0,10); display.print("ASAX "); display.setCursor(50,10);
    display.print(myIMU.magCalibration[0], 2);
    display.setCursor(0,20); display.print("ASAY "); display.setCursor(50,20);
    display.print(myIMU.magCalibration[1], 2);
    display.setCursor(0,30); display.print("ASAZ "); display.setCursor(50,30);
    display.print(myIMU.magCalibration[2], 2);
    display.display();
    delay(1000);
#endif // LCD
  } // if (c == 0x71)
  else
  {
    Serial.print("Could not connect to MPU9250: 0x");
    Serial.println(c, HEX);
    while(1) ; // Loop forever if communication doesn't happen
  }
}

void loop()
{
  // If intPin goes high, all data registers have new data
  // On interrupt, check if data ready interrupt
  if (myIMU.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01)
  {
    myIMU.readAccelData(myIMU.accelCount);  // Read the x/y/z adc values
    myIMU.getAres();

    // Now we'll calculate the accleration value into actual g's
    // This depends on scale being set
    myIMU.ax = (float)myIMU.accelCount[0]*myIMU.aRes; // - accelBias[0];
    myIMU.ay = (float)myIMU.accelCount[1]*myIMU.aRes; // - accelBias[1];
    myIMU.az = (float)myIMU.accelCount[2]*myIMU.aRes; // - accelBias[2];

    myIMU.readGyroData(myIMU.gyroCount);  // Read the x/y/z adc values
    myIMU.getGres();

    // Calculate the gyro value into actual degrees per second
    // This depends on scale being set
    myIMU.gx = (float)myIMU.gyroCount[0]*myIMU.gRes;
    myIMU.gy = (float)myIMU.gyroCount[1]*myIMU.gRes;
    myIMU.gz = (float)myIMU.gyroCount[2]*myIMU.gRes;

    myIMU.readMagData(myIMU.magCount);  // Read the x/y/z adc values
    myIMU.getMres();
    // User environmental x-axis correction in milliGauss, should be
    // automatically calculated
    myIMU.magbias[0] = +470.;
    // User environmental x-axis correction in milliGauss TODO axis??
    myIMU.magbias[1] = +120.;
    // User environmental x-axis correction in milliGauss
    myIMU.magbias[2] = +125.;

    // Calculate the magnetometer values in milliGauss
    // Include factory calibration per data sheet and user environmental
    // corrections
    // Get actual magnetometer value, this depends on scale being set
    myIMU.mx = (float)myIMU.magCount[0]*myIMU.mRes*myIMU.magCalibration[0] -
               myIMU.magbias[0];
    myIMU.my = (float)myIMU.magCount[1]*myIMU.mRes*myIMU.magCalibration[1] -
               myIMU.magbias[1];
    myIMU.mz = (float)myIMU.magCount[2]*myIMU.mRes*myIMU.magCalibration[2] -
               myIMU.magbias[2];
  } // if (readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01)

  // Must be called before updating quaternions!
  myIMU.updateTime();

  // Sensors x (y)-axis of the accelerometer is aligned with the y (x)-axis of
  // the magnetometer; the magnetometer z-axis (+ down) is opposite to z-axis
  // (+ up) of accelerometer and gyro! We have to make some allowance for this
  // orientationmismatch in feeding the output to the quaternion filter. For the
  // MPU-9250, we have chosen a magnetic rotation that keeps the sensor forward
  // along the x-axis just like in the LSM9DS0 sensor. This rotation can be
  // modified to allow any convenient orientation convention. This is ok by
  // aircraft orientation standards! Pass gyro rate as rad/s
//  MadgwickQuaternionUpdate(ax, ay, az, gx*PI/180.0f, gy*PI/180.0f, gz*PI/180.0f,  my,  mx, mz);
  MahonyQuaternionUpdate(myIMU.ax, myIMU.ay, myIMU.az, myIMU.gx*DEG_TO_RAD,
                         myIMU.gy*DEG_TO_RAD, myIMU.gz*DEG_TO_RAD, myIMU.my,
                         myIMU.mx, myIMU.mz, myIMU.deltat);

  if (!AHRS)
  {
    myIMU.delt_t = millis() - myIMU.count;
    if (myIMU.delt_t > 500)
    {
      if(SerialDebug)
      {
        // Print acceleration values in milligs!
        Serial.print("X-acceleration: "); Serial.print(1000*myIMU.ax);
        Serial.print(" mg ");
        Serial.print("Y-acceleration: "); Serial.print(1000*myIMU.ay);
        Serial.print(" mg ");
        Serial.print("Z-acceleration: "); Serial.print(1000*myIMU.az);
        Serial.println(" mg ");

        // Print gyro values in degree/sec
        Serial.print("X-gyro rate: "); Serial.print(myIMU.gx, 3);
        Serial.print(" degrees/sec ");
        Serial.print("Y-gyro rate: "); Serial.print(myIMU.gy, 3);
        Serial.print(" degrees/sec ");
        Serial.print("Z-gyro rate: "); Serial.print(myIMU.gz, 3);
        Serial.println(" degrees/sec");

        // Print mag values in degree/sec
        Serial.print("X-mag field: "); Serial.print(myIMU.mx);
        Serial.print(" mG ");
        Serial.print("Y-mag field: "); Serial.print(myIMU.my);
        Serial.print(" mG ");
        Serial.print("Z-mag field: "); Serial.print(myIMU.mz);
        Serial.println(" mG");

        myIMU.tempCount = myIMU.readTempData();  // Read the adc values
        // Temperature in degrees Centigrade
        myIMU.temperature = ((float) myIMU.tempCount) / 333.87 + 21.0;
        // Print temperature in degrees Centigrade
        Serial.print("Temperature is ");  Serial.print(myIMU.temperature, 1);
        Serial.println(" degrees C");
      }

#ifdef LCD
      display.clearDisplay();
      display.setCursor(0, 0); display.print("MPU9250/AK8963");
      display.setCursor(0, 8); display.print(" x   y   z  ");

      display.setCursor(0,  16); display.print((int)(1000*myIMU.ax));
      display.setCursor(24, 16); display.print((int)(1000*myIMU.ay));
      display.setCursor(48, 16); display.print((int)(1000*myIMU.az));
      display.setCursor(72, 16); display.print("mg");

      display.setCursor(0,  24); display.print((int)(myIMU.gx));
      display.setCursor(24, 24); display.print((int)(myIMU.gy));
      display.setCursor(48, 24); display.print((int)(myIMU.gz));
      display.setCursor(66, 24); display.print("o/s");

      display.setCursor(0,  32); display.print((int)(myIMU.mx));
      display.setCursor(24, 32); display.print((int)(myIMU.my));
      display.setCursor(48, 32); display.print((int)(myIMU.mz));
      display.setCursor(72, 32); display.print("mG");

      display.setCursor(0,  40); display.print("Gyro T ");
      display.setCursor(50,  40); display.print(myIMU.temperature, 1);
      display.print(" C");
      display.display();
#endif // LCD

      myIMU.count = millis();
      digitalWrite(myLed, !digitalRead(myLed));  // toggle led
    } // if (myIMU.delt_t > 500)
  } // if (!AHRS)
  else
  {
    // Serial print and/or display at 0.5 s rate independent of data rates
    myIMU.delt_t = millis() - myIMU.count;

    // update LCD once per half-second independent of read rate
    if (myIMU.delt_t > 500)
    {
      if(SerialDebug)
      {
        Serial.print("ax = "); Serial.print((int)1000*myIMU.ax);
        Serial.print(" ay = "); Serial.print((int)1000*myIMU.ay);
        Serial.print(" az = "); Serial.print((int)1000*myIMU.az);
        Serial.println(" mg");

        Serial.print("gx = "); Serial.print( myIMU.gx, 2);
        Serial.print(" gy = "); Serial.print( myIMU.gy, 2);
        Serial.print(" gz = "); Serial.print( myIMU.gz, 2);
        Serial.println(" deg/s");

        Serial.print("mx = "); Serial.print( (int)myIMU.mx );
        Serial.print(" my = "); Serial.print( (int)myIMU.my );
        Serial.print(" mz = "); Serial.print( (int)myIMU.mz );
        Serial.println(" mG");

        Serial.print("q0 = "); Serial.print(*getQ());
        Serial.print(" qx = "); Serial.print(*(getQ() + 1));
        Serial.print(" qy = "); Serial.print(*(getQ() + 2));
        Serial.print(" qz = "); Serial.println(*(getQ() + 3));
      }

// Define output variables from updated quaternion---these are Tait-Bryan
// angles, commonly used in aircraft orientation. In this coordinate system,
// the positive z-axis is down toward Earth. Yaw is the angle between Sensor
// x-axis and Earth magnetic North (or true North if corrected for local
// declination, looking down on the sensor positive yaw is counterclockwise.
// Pitch is angle between sensor x-axis and Earth ground plane, toward the
// Earth is positive, up toward the sky is negative. Roll is angle between
// sensor y-axis and Earth ground plane, y-axis up is positive roll. These
// arise from the definition of the homogeneous rotation matrix constructed
// from quaternions. Tait-Bryan angles as well as Euler angles are
// non-commutative; that is, the get the correct orientation the rotations
// must be applied in the correct order which for this configuration is yaw,
// pitch, and then roll.
// For more see
// http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
// which has additional links.
      myIMU.yaw   = atan2(2.0f * (*(getQ()+1) * *(getQ()+2) + *getQ() *
                    *(getQ()+3)), *getQ() * *getQ() + *(getQ()+1) * *(getQ()+1)
                    - *(getQ()+2) * *(getQ()+2) - *(getQ()+3) * *(getQ()+3));
      myIMU.pitch = -asin(2.0f * (*(getQ()+1) * *(getQ()+3) - *getQ() *
                    *(getQ()+2)));
      myIMU.roll  = atan2(2.0f * (*getQ() * *(getQ()+1) + *(getQ()+2) *
                    *(getQ()+3)), *getQ() * *getQ() - *(getQ()+1) * *(getQ()+1)
                    - *(getQ()+2) * *(getQ()+2) + *(getQ()+3) * *(getQ()+3));
      myIMU.pitch *= RAD_TO_DEG;
      myIMU.yaw   *= RAD_TO_DEG;
      // Declination of SparkFun Electronics (40°05'26.6"N 105°11'05.9"W) is
      //    8° 30' E  ± 0° 21' (or 8.5°) on 2016-07-19
      // - http://www.ngdc.noaa.gov/geomag-web/#declination
      myIMU.yaw   -= 8.5;
      myIMU.roll  *= RAD_TO_DEG;

      if(SerialDebug)
      {
        Serial.print("Yaw, Pitch, Roll: ");
        Serial.print(myIMU.yaw, 2);
        Serial.print(", ");
        Serial.print(myIMU.pitch, 2);
        Serial.print(", ");
        Serial.println(myIMU.roll, 2);

        Serial.print("rate = ");
        Serial.print((float)myIMU.sumCount/myIMU.sum, 2);
        Serial.println(" Hz");
      }

#ifdef LCD
      display.clearDisplay();

      display.setCursor(0, 0); display.print(" x   y   z  ");

      display.setCursor(0,  8); display.print((int)(1000*myIMU.ax));
      display.setCursor(24, 8); display.print((int)(1000*myIMU.ay));
      display.setCursor(48, 8); display.print((int)(1000*myIMU.az));
      display.setCursor(72, 8); display.print("mg");

      display.setCursor(0,  16); display.print((int)(myIMU.gx));
      display.setCursor(24, 16); display.print((int)(myIMU.gy));
      display.setCursor(48, 16); display.print((int)(myIMU.gz));
      display.setCursor(66, 16); display.print("o/s");

      display.setCursor(0,  24); display.print((int)(myIMU.mx));
      display.setCursor(24, 24); display.print((int)(myIMU.my));
      display.setCursor(48, 24); display.print((int)(myIMU.mz));
      display.setCursor(72, 24); display.print("mG");

      display.setCursor(0,  32); display.print((int)(myIMU.yaw));
      display.setCursor(24, 32); display.print((int)(myIMU.pitch));
      display.setCursor(48, 32); display.print((int)(myIMU.roll));
      display.setCursor(66, 32); display.print("ypr");

    // With these settings the filter is updating at a ~145 Hz rate using the
    // Madgwick scheme and >200 Hz using the Mahony scheme even though the
    // display refreshes at only 2 Hz. The filter update rate is determined
    // mostly by the mathematical steps in the respective algorithms, the
    // processor speed (8 MHz for the 3.3V Pro Mini), and the magnetometer ODR:
    // an ODR of 10 Hz for the magnetometer produce the above rates, maximum
    // magnetometer ODR of 100 Hz produces filter update rates of 36 - 145 and
    // ~38 Hz for the Madgwick and Mahony schemes, respectively. This is
    // presumably because the magnetometer read takes longer than the gyro or
    // accelerometer reads. This filter update rate should be fast enough to
    // maintain accurate platform orientation for stabilization control of a
    // fast-moving robot or quadcopter. Compare to the update rate of 200 Hz
    // produced by the on-board Digital Motion Processor of Invensense's MPU6050
    // 6 DoF and MPU9150 9DoF sensors. The 3.3 V 8 MHz Pro Mini is doing pretty
    // well!
      display.setCursor(0, 40); display.print("rt: ");
      display.print((float) myIMU.sumCount / myIMU.sum, 2);
      display.print(" Hz");
      display.display();
#endif // LCD

      myIMU.count = millis();
      myIMU.sumCount = 0;
      myIMU.sum = 0;
    } // if (myIMU.delt_t > 500)
  } // if (AHRS)
}

Full demo sketch

Some configuration can be found at the beginning of the sketch. Here is where you can turn on or off AHRS calculations, and serial debugging:

language:c
#define AHRS true         // Set to false for basic data read
#define SerialDebug true  // Set to true to get Serial output for debugging

Some of the settings used by library exposed in the sketch

Magnetic declination

The AHRS needs to know where you are located to convert magnetic north to true north. I used the combination of two services to find the current declination of our offices; Google, and NOAA. This may or may not be ideal in your country.

The first thing I needed were the latitude and longitude of the office. Searching for SparkFun in Google Maps shows a red pin on our building. Clicking near the front door, but not on the existing pin dropped a new pin which also made a card appear bottom center. The bottom of this card contains a link to a search of the latitude and longitude marked by the new pin.

Screenshot of Google Maps showing the latitude and longitude of SparkFun Electronics

Google Maps showing the latitude and longitude of SparkFun Electronics

Clicking on the link in the card brings up a page showing the latitude and longitude in both the decimal degrees (DD) and degrees minutes seconds (DMS) forms. I find sign errors easier to avoid by using DMS form Google provides with the since I’m not intimately familiar with the WGS 84 coordinate reference system (CRS). The included cardinal directions are handy and required by the next tool.

Search for SparkFun Electronics' coordinates

Search for SparkFun Electronics' coordinates

The second tool is the default magnetic field calculator on NOAA’s website. Enter the coordinates found in the previous step into the latitude and longitude inputs. The Calculate button will trigger a dialog box with the results to appear. If the results appear on the Google map where you are expecting them, then you chose the correct directions with the radio inputs!

Magnetic declination of SparkFun Electronics Colorado office

Magnetic declination of SparkFun Electronics' Colorado office

Note that the declination here is currently 8˚ 30' E. Also note that the image on the map shows magnetic north to be east of true north. The provided DM format needs to be converted to DD format for the code. There are 60 minutes per degree, 30 of them is 3060 of a degree, or 0.5˚. The declination in DD format is thus 8.5˚ E. Update the code in the example sketch around line 391 with the declination for your desired location.

myIMU.yaw -= 8.5;

The library left a lot of the math in the example sketch in part to make things like this easier to access.

Here is an example of what the output of the demo sketch should look like:

MPU9250 I AM 71 I should be 71
MPU9250 is online...
x-axis self test: acceleration trim within : 2.4% of factory value
y-axis self test: acceleration trim within : 0.5% of factory value
z-axis self test: acceleration trim within : -0.0% of factory value
x-axis self test: gyration trim within : -0.3% of factory value
y-axis self test: gyration trim within : -1.0% of factory value
z-axis self test: gyration trim within : 0.5% of factory value
MPU9250 initialized for active data mode....
AK8963 I AM 48 I should be 48
AK8963 initialized for active data mode....
X-Axis sensitivity adjustment value 1.21
Y-Axis sensitivity adjustment value 1.22
Z-Axis sensitivity adjustment value 1.17
ax = -70.19 ay = -70.56 az = 931.03 mg
gx = 0.02 gy = 0.00 gz = 0.02 deg/s
mx = -189 my = 355 mz = 127 mG
q0 = 0.97 qx = -0.04 qy = 0.03 qz = 0.22
Yaw, Pitch, Roll: 16.45, 4.22, -4.14
rate = 140.15 Hz

Resources and Going Further

For more information about the MPU-9250 Breakout, check out the links below.

Many of the advanced features of the MPU-9250 are only accessable by agreeing to a pages of licensing terms and logging in as a developer to get access to Embedded MotionDriver 6.12. This approach isn’t super Arduino friendly. At power up 3062 bytes of undocumented hex needs to be loaded into the MPU-9250.

#define DMP_CODE_SIZE           (3062)

static const unsigned char dmp_memory[DMP_CODE_SIZE] = {
    /* bank # 0 */
    0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00,
    0x00, 0x00, 0x65, 0x00, 0x54, 0xff, 0xef, 0x00, 0x00, 0xfa, 0x80, 0x00, 0x0b, 0x12, 0x82,...

Code snippet of MPU-9250 Embedded MotionDriver firmware

That binary combined with the driver and any code that does something with the sensor data quickly maxes out smaller microcontrollers. Feel free to register and play around if you want to take this product further.


A customer of ours shared his great tutorial on Affordable 9-DoF Sensor Fusion. Check it out for more info on sensor fusion.


For more SparkFun sensor fun, check out these other great tutorials. (This was fun, right??)

Hackers in Residence - Hacking MindWave Mobile

Review, teardown, and hacking tutorial for the MindWave Mobile, a $99 commercial grade EEG sensor.

TMP006 Hookup Guide

How to get started reading temperature with the TMP006 sensor.

VL6180 Hookup Guide

Get started with your VL6180 based sensor or the VL6180 breakout board.

MyoWare Muscle Sensor Kit

Line of products to work with the MyoWare muscle sensor from Advancer Technologies

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Pokémon Go Patches with EL Panels

$
0
0

Pokémon Go Patches with EL Panels a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t551

Introduction

Here’s a fun way to show your team pride when out at night Pokémon hunting. In this project, we’ll add a cloth stencil over EL panels to create glowing team logos and designs. Read on for more tips and tricks at customizing EL panels and attaching them to clothing, backpacks, and more.

Patches

Suggested Reading

For this project, we’ll be using EL wire and will be doing some soldering. Here are some tutorials to review before getting started:

Materials

Here are some suggested materials for completing this project. The list shows a White EL Panel, but feel free to use your color of choice. SparkFun carries Red and Blue panels; we’ll also cover creating custom colors using lighting gels or fabric layers (for those of you wanting to make some Team Instinct swag or a Poké Ball).

Additional Materials:

  • Something to put the patch on - a hoodie, jacket, backpack, or hat would work well. The patch should be at least 5"x5" to completely cover the EL panel, so make sure that there is room on your item and that it can be ironed without melting.
  • Iron-on patch fabric - thick enough to block the light from the panels. We recommend denim or twill patches from your local fabric store. You can also create your own using an iron-on adhesive - Heat n' Bond brand works well.
  • Sewing supplies - scissors, thread, needle
  • Soldering iron, solder - to make an optional extension cable
  • Wire strippers - for soldering
  • Heat shrink - to insulate any exposed soldered connections
  • A cutting machine - Silhouette or Cricut personal cutting machines or a laser cutter work well. If you have the patience, hand cutting a stencil with a hobby knife will also work.
  • Iron - small wand-style craft irons work best for this project to get into detailed areas of the fabric without touching the EL panel directly. We are using a Clover Mini Iron in this tutorial.

Preparing Your Stencil

Before we begin building, we’ll need a stencil design. If cutting on a machine, you will need a vector line drawing of your logo/image. If you do a google search for ‘Pokémon GO Team Logo Vector,’ you will most likely find some files that other generous folks have created to download. They are often in .svg or .ai format, which may not import directly into your cutting machine’s software (see below for special considerations for each machine).

You can also use Software like Adobe Illustrator®, CorelDraw®, or Inkscape to trace an image and export for your machine.

For all stencils, size your image to ~3.75" x 3.75" to make sure it stays within the boundary of the EL Panel (10cm or ~3.9" square). Adjust any lines so that the space between cuts is thick enough that the fabric doesn’t tear or warp when removing from the cutting surface or installing.

NOTE: These panels can be cut to shapes or smaller if your project requires it (we did this for the baseball cap example). Regular scissors work fine to cut this EL panel, but, after you’ve cut the panel, you should seal the exposed edges with some tape or epoxy to avoid shorting the panel or shocking yourself.

Cutting Machine Tips

Silhouette Machines -

Unfortunately you cannot import .svg files into their software unless you upgrade to Silhouette Studio® Designer Edition. The premium software allows you to import files directly from Adobe Illustrator® or CorelDraw®. You can also download a plug-in called Silhouette Connect™.

If you don’t want to upgrade the software, you can also export your files as .dxf and import them.

Here are some additional resources for the Silhouette:

Cricut Machines -

If you have a Cricuit machine, you’ll use a web-based software called Cricuit DesignSpace. It will import both .svg and .dxf files, but they may need some clean up before use.

Note: Newer cutting mats can be sticky and transfer some adhesive to your fabric. Be careful when removing from the mat not to tear or warp the fabric. Using specialty spatula tools that come with the machines help to remove small parts of the cut without damaging the fabric.

alt text

Laser Cutter

Import your vector as you would any other print. Attaching the fabric to a piece of scrap cardboard with some clear tape will make it easier to remove the stencil from the bed.

Additional Tips:
It may be necessary to adjust the graphics to avoid small areas where strain may tear the fabric. In the example below, the spaces between parts of the stencil were too thin, and tore when removing from the machine. Practice on a test piece of fabric first.

alt text

Attaching Stencil

Next, we’ll adhere the stencil to the EL panels. Remove the thin plastic sheet covering from the EL panel and discard.

alt text

Adding Color Effects

If your design requires a different color or multiple colors on one El panel, here are a couple of a techniques you can try. Using a white EL panel as the base layer will give you the best color results.

Cut a piece of lighting gel (or colored plastic) slightly larger than the holes in your design, but smaller than the edge of the El Panel. Make sure to choose a material that can withstand the heat of the iron.

alt text

alt text

Alternatively, a thin piece of fabric or felt can be placed under the design and ironed in place.

alt text

Attaching Stencil

Carefully line up your stencil on the colored side of the EL panel, centering and adjusting as needed. When the design is placed, make small circles with a craft iron to begin melting the adhesive on the fabric. Move quickly and avoid touching the plastic of the EL directly. It’s better to make a few passes than hold the iron in place for too long.

NOTE: Do not iron the overlapping edges of the fabric not covering the EL panel - we will use those to iron the patch onto our project later.

Check the adhesive every so often by carefully trying to peel up edges of the fabric.

alt text

If ironing on the panel doesn’t work (some iron-on adhesives are better than others), you can use glue to attach the fabric stencil.

Adding Extension Cables

The wires on the EL panels are shorter than on EL wire, which can make intuitive placement of the battery pack a bit of a challenge. If you would like to place the EL panel further away from the battery pack, you can cut the wires and solder in additional wire as an extension cable.

CAUTION: Make sure to disconnect the EL panel from the battery back before soldering.

alt text

Prepare the wires for soldering by cutting them halfway between the EL panel connection and the JST connector. Measure two equal lengths of wire to use as the extension wiring, adding additional length for give/tension if needed. We used ribbon cable for this example because it is inexpensive and flexible.

If this is your first time working with wire and soldering, here are some resources:

Strip the ends of all wires, cut some heat shrink and feed over the wire before and away from the soldering area before you begin soldering. The heat shrink will slide over the soldered connection afterward to protect it. Solder the two extension wires to the panel wires.

alt text

After the solder is cool, slide the heat shrink over the connection, and use a heat gun or the edge of the soldering iron to shrink it. If desired, use a large piece of heat shrink over both of the wires for extra insulation and support. Repeat for all four connection points (two ends on each wire).

alt text

Installation

Now it’s time to put the patch on something! Position the patch on your item of choice and mark any holes that may need to be cut to thread the cable through. Check the positioning of battery pack so that it is in an easily accessible place.

CAUTION: Although it is low current, EL wire runs on high voltage AC (100 VAC). Double check that there are no exposed connections (on the wire or connection point to the panel) before wearing. For final projects, we recommend coating any exposed connections in epoxy, hot glue, electrical tape, or other insulating material.

Once everything is in place, use an iron to adhere the patch to your fabric - making sure to iron only the extended edges and not the panel itself.

alt text

Alternative Attachment Methods

You can also stitch the patch on with a sewing machine or by hand, be mindful of not puncturing the panel with the needle. Decorative stitching is a great way to add some extra customization to the patch.

alt text

alt text

A third option is making a pouch for the panel. This is great for an item that may need frequent washing or if you’d like to switch out the panel for another design in the future. The example below uses the fabric stencil on a pocket and a plain panel to backlight it.

alt text

Reinforcing the Connector Tab

The small tab on the EL panels can get damaged from frequent bending or pulling. To avoid the tab breaking or wires disconnecting, take special care in where the patch is placed. After installing, you can add a small loop in the wiring (secure with stitching, hot glue, or secure to itself with electrical tape) to ease the strain of the wires on the connection point.

alt text

Finally, feed the cable through your project, and plug it into the battery back. Light up, and enjoy!

alt text

Project Examples

Here are some examples of the patches used in different ways.

alt text

Team Instinct: We liked this track jacket, but it wasn’t iron-friendly, so we sewed the patch on. For the utility belt, we created a backlit pouch so the panel could be removed. The messenger bag has an iron-on patch.

alt text

Team Mystic: A trimmed down panel was installed in this baseball cap. For the messenger bag, iron-on adhesive was applied directly to the canvas bag, then cut on the laser. After cutting, the EL panel was placed underneath and ironed on. The jacket uses a faux leather patch cut on a craft cutting machine and glued on top of the EL panel.

alt text

Team Valor: The leather vest was laser cut and an EL panel was applied underneath with glue instead of ironing on a patch. The messenger bag features a sewn on patch with contrast stitching. The thigh holster uses an iron-on patch.

Resources and Going Further

Here are some additional tutorials to check out:

Check out these other EL tutorials for ways to make your patch more interactive:


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Multiplexer Breakout Hookup Guide

$
0
0

Multiplexer Breakout Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t553

Introduction

The SparkFun Multiplexer Breakout provides access to all pins and features of the 74HC4051, an 8-channel analog multiplexer/demultiplexer. The 74HC4051 allows you to turn four I/O pins into eight multi-functional, individually-selectable signals, which can be used do everything from driving eight LEDs to monitoring eight potentiometers.

SparkFun Multiplexer Breakout - 8 Channel (74HC4051)

BOB-13906
$1.95

A multiplexer, commonly abbreviated down to “mux”, is an electronically-actuated switch, which can turn one signal into many. It routes a common input signal to any number of separate outputs. Similarly, a demultiplexer routes any number of selectable inputs to a single common output.

The 74HC4051 can function as either a multiplexer or a demultiplexer, and it features eight channels of selectable inputs/outputs. The routing of common signal to independent I/O is set by digitally controlling three select lines, which can be set either high or low into one of eight binary combinations.

Covered In This Tutorial

This tutorial covers everything you should need to assemble the Multiplexer Breakout then wire it and integrate it into your project. Included in the tutorial are a pair of Arduino examples, which demonstrate how to use the mux for both digital output and analog input. The tutorial is split into the following sections, which you can navigate through using the bar on the right.

  • 74HC4051 Breakout Overview– A quick introduction to the workings of the 74HC4051 and the extra features of the breakout board.
  • Board Assembly– Tips and tricks for soldering headers or wires to your breakout and mounting it into your project.
  • Arduino Example: Output– An Arduino circuit and example code demonstrating how to use the multiplexer to drive eight LEDs.
  • Arduino Example: Input– Circuit and an Arduino sketch explaining how to use the board to read eight analog voltage-producing photocells.

Suggested Reading

Muxes are a great tool for electronics users of all experience levels – anyone who needs to multiply their project’s pin count. There are a few subjects you should be familiar with before diving into multiplexing, though. If the subjects below sound foreign to you, consider browsing through that tutorial before continuing on.

Binary

Binary is the numeral system of electronics, and widely used in programming...so it must be important to learn. But, what is binary? How does it translate to other numeral systems like the decimal we're used to?

How to Use a Breadboard

Welcome to the wonderful world of breadboards. Here we will learn what a breadboard is and how to use one to build your very first circuit.

Analog vs. Digital

This tutorial covers the concept of analog and digital signals, as they relate to electronics.

Digital Logic

A primer on digital logic concepts in hardware and software.

74HC4051 Breakout Overview

The Multiplexer Breakout’s schematic is just about as simple as it gets: There’s the chip, a decoupling capacitor, a pull-up resistor, and all of the pins are broken out (some broken out twice):

Board top

One half of the board breaks out the control signals (E, S0-S2) and common input/output (Z). The other side provides access to all eight independent I/O’s (Y0-Y7). Both sides include supply and ground connections (VCC, VEE, GND). The table below summarizes each pin and its function.

Pin LabelFunctionInput/Output
(to board)
Notes
EEnableInputActive low enable
S2, S1, S0Select ControlsInputSelect inputs, S2 is the msb and S0 is the lsb
ZCommon I/OInput/OutputCommon output or input
GNDGroundSupplyGround supply voltage (0V)
VCCPositive supplySupplyPositive supply voltage (2-10V)
VEENegative supplySupplyNegative supply voltage (Jumpered to ground by default)
Y7, Y6, Y5, Y4,
Y3, Y2, Y1, Y0
Independent I/OInput/OutputSelectable I/O to be routed to common pin

74HC4051 Logic Table

The select pins (S2-S0), in addition to the enable pin (E), control which (if any) of the eight independent I/O pins (Y0-Y7) are connected to the common pin (Z). The function table below shows how those pins work together to select the I/O.

ES2S1S0I/O Connected to Z
LLLLY0
LLLHY1
LLHLY2
LLHHY3
LHLLY4
LHLHY5
LHHLY6
LHHHY7
HXXXNone

Assuming the mux is powered at 5V, “L,” for “low”, is any voltage between 0 and about 2V and “H” – “high” – is any voltage between around 3 and 5V. “X” means it doesn’t matter what the logic level of the pin is (because it will be trumped by the enable pin).

The enable (E) pin is pulled low on the breakout board via a 10kΩ resistor. If your project doesn't require enabling/disabling the mux, you can leave that pin unused.

Power Supply Limits

The 74HC4051 supports a wide supply range, but the presence of the optional negative voltage supply – VEE– has the potential to make things a little complicated. Here are the basic rules that govern the 74HC4051’s power supplies:

  • VCC must be at least 2.0V (above GND).
  • VCC must not exceed 10V (above GND).
  • VEE must be less than VCC– anywhere between 2.0V and 10V below VCC.

The operating area graph below – figure 7 in the datasheet– represents those ranges visually:

Safe voltage supply operating area

For example, the 74HC4051 supports standard 3.3V, 5V, and 9V supplies, as well as bipolar supplies, like ±5V (but not ±9V).

JP1 – Connecting VEE to GND

We expect that the majority of multiplexer-equipped projects may not need the 74HC4051’s bipolar supply support. So, to make the board easier to get quickly up-and-running, we’ve added a jumper to the top side, which shorts VEE to GND.

JP1 highlighted on top side of board

By connecting VEE to GND, you can satisfy both VCC-GND and VCC-VEE limits by keeping VCC between 2.0 and 10.0V. Unless you need a bipolar supply, you can leave this jumper closed and ignore VEE entirely.

Using a Bipolar Power Supply

The 74HC4051 supports bi-polar power supplies, with a positive supply on VCC and a negative supply on VEE. The difference between VCC and VEE can be as much as 10V (e.g. ±5V), but VCC must be somewhere between 2V and 10V.

To use a bipolar supply, you must first open JP1, disconnecting VEE from GND.

JP1 jumper open

A quick hit of a soldering iron on some solder wick should lift that solder right up.

Once the jumper is open, your supplies can be connected. The logic levels of the select and enable pins will still be limited by VCC, but your common pin and eight I/O pins will be able to range between VEE and VCC.

Board Assembly

There is no one correct way to assemble the breakout, but you do need to solder something to the supply, select, common, and I/O pins. We recommend either male or female headers, but wire may be better suited to some projects.

Break Away Headers - Straight

PRT-00116
$1.5
20
Hook-Up Wire - Assortment (Solid Core, 22 AWG)

PRT-11367
$16.95
18
Hook-Up Wire - Assortment (Stranded, 22 AWG)

PRT-11375
$16.95
11
Female Headers

PRT-00115
$1.5
6
If you've never soldered before, this is a great place to start! Check out our How to Solder - Through-hole Soldering tutorial for help guiding that soldering iron!

The Multiplexer Breakout is breadboard-compatible, as the two header rows can span a breadboard’s inner trough. If you throw male headers onto the board…

Male headers soldered to both headers

…you can plug it in, and use jumper wires to connect the mux to an Arduino.

Example breadboard/Arduino circuit

Arduino Example: Output

Now that you’ve got a handle on how to use the Multiplexer works and have the board assembled, here are a few quick example Arduino sketches to help demonstrate both output and input capabilities of the chip.

The Circuit

To get the most out of this example, you’ll need to connect some sort of output device to each of the independent I/O pins (Y0-Y7). For example, grab a pack of LEDs and some 330Ω resistors for a quick hardware-verifying circuit.

Digital output circuit example

In this example, S0, S1, and S2 are connected to Arduino pins 2, 3 and 4 respectively. “Z” is connected to pin 5, which the example uses to produce PWM “analog output” signals.

VCC is connected to the Arduino 5V pin, and GND goes to GND. The breakout board’s JP1 is left intact, shorting VEE to GND.

Finally, the Y0-Y7 pins are all connected to LED/resistor pairs, with the positive anode end of the LED connected to the Y-pin and the resistor connecting the LED’s cathode to ground. This way, when the output is selected and “Z” goes high, the LED on that output will turn on.

The Sketch

Here’s the code for the above circuit. Upload it, and enjoy the cycling, breathing LEDs!

NOTE: For these examples, we're hosting the code on codebender, which not only features code-sharing, but also allows anyone to upload and debug Arduino sketches from within a web browser. Plus, it works on lower-tech machines, like Chromebooks!

There are codebender plugins for Chrome, Chromium, and Firefox. Visit the codebender plugin page for help installing the codebender plugin.

The magic part of this code is the selectMuxPin(byte pin) function at the bottom.

language:c
const int selectPins[3] = {2, 3, 4}; // S-pins to Arduino pins: S0~2, S1~3, S2~4
...
// The selectMuxPin function sets the S0, S1, and S2 pins to select the give pin
void selectMuxPin(byte pin)
{
  if (pin > 7) return; // Exit if pin is out of scope
  for (int i=0; i<3; i++)
  {
    if (pin & (1<<i))
      digitalWrite(selectPins[i], HIGH);
    else
      digitalWrite(selectPins[i], LOW);
  }
}

Given a pin number between 0 and 7, selectMuxPin configures the S0-S2 pins to connect that Y-pin to Z. If you take nothing else from this example, that function may prove the most handy in your future multiplexing endeavors.

Arduino Example: Input

In this example, we’ll switch gears and test out the 74HC4051’s analog signal support. By connecting “Z” to an analog input on the Arduino, we can turn one ADC pin into eight!

The Circuit

You can leave the select pins (S0-S2) tied to Arduino pins 2, 3, and 4, but re-route the Z jumper wire to A0. As for the Y-pins, you can connect potentiometers, photocells, or create voltage dividers on all eight inputs.

Example analog input circuit

Connect the Multiplexer Breakout up to eight photocells to create a single-octave, touchless keyboard!

In lieu of a collection of eight analog input devices, you can just use jumper wires to short the input pins to either VCC or GND. That way you can at least prove to yourself that it works.

The Sketch

Here’s the sketch for the above circuit:

After uploading the sketch, open your serial monitor and set the baud rate to 9600. Here you’ll see the analog values from all eight independent I/O (Y0-Y7) read and printed out once a second.

Example serial monitor output

Toggle your inputs, or switch out some jumper wires to see the values change.

This example uses that same selectMuxPin function to set the S0, S1, and S2 pins. But instead of writing out to the Z pin, we read from it.

Resources & Going Further

Need more information on the Multiplexer Breakout? There’s plenty where that came from! The 74HC4051’s datasheet is thorough and the breakout design is open-source:

Or, if you need some inspiration in choosing your next project, check out some of these related tutorials:

Shift Registers

An introduction to shift registers and potential uses.

Recreating Classic Electronics Kits

100-in-1? 500-in-1? It's up to you when you build your own Science Fair style experiment board!

Digital Logic

A primer on digital logic concepts in hardware and software.

LogicBlocks Experiment Guide

Experiments guide for the LogicBlocks kit. Build oscillators, latches, multiplexers and more with the LogicBlocks.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

9DoF Sensor Stick Hookup Guide

$
0
0

9DoF Sensor Stick Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t542

Introduction

The 9DoF Sensor Stick is an easy-to-use 9 degrees of freedom IMU. The sensor used is the LSM9DS1, the same sensor used in the SparkFun 9 Degrees of Freedom IMU Breakout, but is slimmed down to be only 0.9"x0.4".

9DOF Stick

Required Materials

To follow along with this hookup guide, you will need the following:

Suggested Reading

Before getting started, you may find the following links useful:

Board Overview

Let’s go over the 9DoF Sensor Stick in detail.

9DoF Sensor Stick

LSM9DS1 Details:

  • 3 acceleration channels, 3 angular rate channels, 3 magnetic field channels
  • ±2/±4/±8/±16 g linear acceleration full scale
  • ±4/±8/±12/±16 gauss magnetic full scale
  • ±245/±500/±2000 dps angular rate full scale
  • I2C serial interface
  • Operating Voltage: 3.3V

Pull-up Resistors

This breakout board has built-in 4.7 k&ohm; pull up resistors for I2C communications. If you’re hooking up multiple I2C devices on the same bus, you may want to disable/enable the pull-up resistors for one or more boards. On the 9DoF Sensor Stick, the pull-ups are enabled by default. To disable them, simply use a hobby knife to cut the traces connecting the left and right pads of the jumper labeled I2C PU on the back of the board. This will disconnect the resistors on the I2C bus from VCC.

i2c pullup jumper

Changing I2C Addresses

If you’re using multiple Sensor Sticks, or have a device that’s already using the default addresses of the Sensor Stick, you’ll want to change addresses to avoid having multiple devices try to talk over one another. The default address for the magnetometer is 0x1E and the default address for the accelerometer and gyroscope is 0x6B. To change the addresses, you’ll want to use a hobby knife to cut the trace between center and top pads and use solder to short the center and bottom pads. This will change the address of the magnetometer to 0x1C and the accelerometer and gyroscope to 0x6A.

address jumper

Hardware Connections

Connecting the 9DoF Sensor Stick to an Arduino

Wiring the Sensor Stick is very easy! We recommend soldering four male headers to the sensor stick. You can also directly solder wires to the board to fit your application’s needs.

Power

This board runs on 1.9V to 3.6V. Be sure to power the board from the 3.3V pin! I2C uses an open drain signaling, so there is no need to use level shifting; the 3.3V signal will work to communicate with the Arduino and will not exceed the maximum voltage rating of the pins on the LSM9DS1.

Connections to the Arduino

The 9DoF Sensor Stick has only four pins. We’ll be connecting VCC and GND to the normal power pins, and the remaining two pins are used for I2C communication. If you’re using a newer board that has SDA and SCL broken out, you can connect the SDA and SCL pins from the Sensor Stick directly to those pins. If you’re using an older board, SDA and SCL are pins A4 and A5 respectively.

  • VCC → 3.3V
  • GND → GND
  • SDA → SDA/A4
  • SCL → SCL/A5

Your circuit should look something like this:

alt text

Installing the Arduino Library

We’ve written a full-featured Arduino library to help make interfacing with the LSM9DS1’s gyro, accelerometer, and magnetometer as easy-as-possible. Visit the GitHub repository to download the most recent version of the library, or click the link below:

Download the SparkFun LSM9DS1 Arduino Library

For help installing the library, check out our How To Install An Arduino Library tutorial. You need to move the SparkFun_LSM9DS1_Arduino_Library folder into a libraries folder within your Arduino sketchbook or use the Library Manger to install.

The LSM9DS1_Basic_I2C Example

To verify that your hookup works, load up the LSM9DS1_Basic_I2C example by going to File>Examples>LSM9DS1 Breakout>LSM9DS1_Basic_I2C.

The default values set by this sketch should work for a fresh, out-of-the-box 9DoF Sensor Stick – it assumes both of the address jumpers haven’t been modified. Upload the sketch, then open up your serial monitor, setting the baud rate to 115200. You should see something like this:

Example serial monitor output

The current reading from each axis on each sensor is printed out, then those values are used to estimate the sensor’s orientation. Pitch is the angle rotated around the y-axis, roll is the board’s rotation around the x-axis, and heading (i.e. yaw) is the sensor’s rotation around the z-axis. Try rotating the board (without pulling out any wires!) to see how the values change.

Resources and Going Further

For more information about the 9DoF Sensor Stick, check out the links below:

Going Further

Now that you’ve got the Sensor Stick up-and-running, what project are you going to incorporate motion-sensing into? Need a little inspiration? Check out some of these tutorials!

  • Dungeons and Dragons Dice Gauntlet– This project uses an accelerometer to sense a “rolling the dice” motion. You could swap in the LSM9DS1 to add more functionality – like compass-based damage multipliers!
  • Are You Okay? Widget– Use an Electric Imp and accelerometer to create an “Are You OK” widget. A cozy piece of technology your friend or loved one can nudge to let you know they’re OK from half-a-world away.
  • Leap Motion Teardown– An IMU sensor is cool, but image-based motion sensing is the future. Check out this teardown of the miniature-Kinect-like Leap Motion!
  • Pushing Data to Data.SparkFun.com– Need an online place to store your IMU data? Check out data.sparkfun.com! This tutorial demonstrates how to use a handful of Arduino shields to post your data online.

Creating a Humidor Control Box

Because some of our boards need to be re-humidified after reflow, we decided to make our own humidor. This tutorial will focus on how to model a project in 3D and then fabricate it using a CNC routing machine.

Internet Datalogging With Arduino and XBee WiFi

How to combine an Arduino, XBee WiFi module, and handful of sensors to create a live stream of "Office Conditions". Storing light, temperature, carbon-monoxide, and methane (for science!) readings on the Internet.

Wake-on-Shake Hookup Guide

A basic hookup guide for getting started with the SparkFun Wake-on-Shake.

Blynk Board Washer/Dryer Alarm

How to configure the Blynk Board and app to notify you when your washer or dryer is done shaking.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado


ADXL345 Hookup Guide

$
0
0

ADXL345 Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t548

Introduction

The ADXL345 is a small, thin, low power, 3-axis MEMS accelerometer with high resolution (13-bit) measurement at up to +/-16 g. Digital output data is formatted as 16-bit two’s complement and is accessible through either an SPI (3- or 4-wire) or I2C digital interface.

SparkFun Triple Axis Accelerometer Breakout - ADXL345

SEN-09836
$17.95
8

This hookup guide will explore the various functions of the ADXL345 utilizing the SparkFun ADXL345 Arduino Library and example code. First, let’s get some background on this small yet powerful accelerometer.

As we step through the Hook Up Guide, you’ll find it useful to have the ADXL345 Datasheet on hand.

ADXL345 Datasheet

Required Materials

The wish list below includes all of the materials that will be utilized in this tutorial:

Suggested Reading

If you’re not sure if this product is right for your needs, check out the Accelerometer, Gyro and IMU Buying Guide. Some additional resources that might be helpful in this process, especially if you are just started out, you can find here:

How to Solder - Through-hole Soldering

New to electronics and soldering? Have you soldered before but need a refresher? This tutorial will cover everything you need to know about through-hole soldering.

Working with Wire

How to strip, crimp and work with wire.

Accelerometer Basics

A quick introduction to accelerometers, how they work, and why they're used.

I2C

An introduction to I2C, one of the main embedded communications protocols in use today.

Hardware Overview

Features

  • Supply Voltage: 2.0 - 3.6 VDC
  • Ultra Low Power: As low as 23 uA in measurement mode, 0.1uA in standby mode at 2.5V
  • SPI or I2C Communication
  • Single Tap / Double Tap Detection
  • Activity / Inactivity Sensing
  • Free-Fall Detection

Whoa! What are those last three?! Yes, the ADXL345 has special sensing abilities! The single and double tap sensing detects when a single, or two simultaneous, acceleration events occur. Activity and inactivity sensing detect the presence or lack of motion. Free-fall sensing compares the acceleration on all axes with the threshold value to know if the device is falling. All thresholds levels that trigger the activity, free-fall, and single tap/double tap events are user-set levels. These functions can also be mapped to one of two interrupt output pins. An integrated, patent pending 32-level first in, first out (FIFO) buffer can be used to store data to minimize host processor intervention.

The ADXL345 is well suited to measure the static acceleration of gravity in tilt-sensing applications, as well as dynamic acceleration resulting from motion or shock. Its high resolution (4 mg/LSB) enables measurement of inclination changes less than 1.0°. Furthermore, low power modes enable intelligent motion-based power management with threshold sensing and active acceleration measurement at extremely low power dissipation.

Applications

  • Handsets
  • Medical Instrumentation
  • Gaming and Pointing Devices
  • Industrial Instrumentation
  • Personal Navigation Devices
  • Hard Disk Drive (HDD) protection

Pin Functionality

Below you can reference the ADXL345 breakout board and pin functions.

alt text

Breakout Board Pin Function Descriptions

MnemonicDescription
GND This pin must be connected to ground
VCC Supply Voltage
CS Chip Select
INT1 Interrupt 1 Output
INT2 Interrupt 2 Output
SDO

Serial Data Output (SPI 4-Wire) / I2C Address Select

SDA / SDI / SDIO

Serial Data I2C / Serial Data Input (SPI 4-WIRE) / Serial Data Input and Output (SPI 3-Wire)

SCL/SCLK

Serial Communications Clock

Assembly

With the ADXL345, I2C and SPI digital communications are available. In both cases, the ADXL345 operates as a slave device.

Note: A potential problem when hooking up the ADXL345 breakout to an Arduino (or compatible board) is, if you are using a breadboard with loosely connected jumper wires, you risk getting bad data. Make sure your connections are solid, and you should be fine.

SPI Communication

First, we will look at how to connect an Arduino (or compatible board like SparkFun’s RedBoard) to the ADXL345 breakout board for SPI communication.

In SPI mode, the CS pin is controlled by the bus master. For SPI, either 3- or 4- wire configuration is possible.

Note: When using 3-wire SPI, it is recommended that the SDO pin be pulled up to VDD I/O or pulled down to GND via a 10 kΩ resistor. Please refer to page 15 of the ADXL345 Datasheet for additional information.

The following is a table describing which pins on the Arduino should be connected to the pins on the accelerometer for SPI 4-wire communication.

Arduino PinADXL345 Pin
GND GND
3V3 VCC
10 CS
12 SDO
11 SDA
13

SCL


Here is a wiring connection diagram to aid you in hooking it up for SPI 4-wire communication.

alt text

I2C Communication

Now, let’s look at how to connect an Arduino (or compatible board like SparkFun’s RedBoard) to the ADXL345 breakout board for I2C communication.

I2C mode is enabled if the CS pin is tied to high. There is no default mode if the CS pin is left unconnected, so it should always be tied high or driven by an external controller.

Note: If other devices are connected to the same I2C bus, the nominal operating voltage level of those other devices cannot exceed VDD I/O by more than 0.3 V. External pull-up resistors are necessary for proper I2C operation. Used in this connection diagram are two 4.7 kΩ resistors. Please refer to page 18 of the ADXL345 Datasheet for additional information.

The following is a table describing which pins on the Arduino should be connected to the pins on the accelerometer for I2C communication.

Arduino PinADXL345 Pin
GND GND
3V3 VCC
3V3 CS
GND SDO
A4 SDA
A5

SCL


Here is a wiring connection diagram to aid you in hooking it up for I2C communication.

alt text

Not using a SparkFun RedBoard or Arduino Uno? The reference table below shows where Two Wire Interface (TWI) pins are located on different and older Arduino boards.

BoardI2C / TWI Pins
SparkFun Red, Uno, Ethernet A4 (SDA), A5 (SCL)
Mega2560 20 (SDA), 21 (SCL)
Leonardo 2 (SDA), 3 (SCL)
Due 20 (SDA), 21 (SCL), SDA1, SCL1

SparkFun ADXL345 Library

The most exciting part of the Hookup Guide is the SparkFun ADXL345 library we’ve put together for you. Now, you not only have the ability to customize your sensing functions but also switch easily back and forth between I2C and SPI communication.

To get started, you can download the library here along with example code. For the most up-to-date code visit the SparkFun ADXL345 Arduino Library Repo.

SparkFun ADXL345 Library and Example Code

The downloaded file includes:

  • Library .cpp and .h files
  • Arduino Sketch: ADXL345 Calibration Example
  • Arduino Sketch: ADXL345 Example
  • Arduino Sketch: SparkFun Baby Blynk Monitor Thing Example
  • README.md
  • keywords.txt

Before we are able to use the example code, we need to place the SparkFun_ADXL345_Library folder into your Arduino Library. If you don’t know where that is located, you can usually find it here:

PC: My Documents > Arduino > Libraries
Mac: (home directory) > Documents > Arduino > libraries
Linux: (home directory) > Sketchbook > Libraries

For help installing the library, check out our Installing an Arduino Library tutorial.

Using the SparkFun ADXL245 Library

Once you’ve installed the SparkFun ADXL345 Library, you can open up SparkFun_ADXL345_Example.ino in the Arduino IDE.

Make sure you have downloaded and installed the Arduino Software IDE so you can open the example code and program your board.

Example Code

Now that you have the example sketch open, let’s go through and take a look at all the ways we can customize the ADXL345.

SPI or I2C?

The first important selection to make is under the COMMUNICATION SECTION. This is where you will let the library know whether you have setup your hardware for SPI or I2C communication.

language:c
/*********** COMMUNICATION SELECTION ***********/
/*    Comment Out The One You Are Not Using    */
ADXL345 adxl = ADXL345(10);           // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
//ADXL345 adxl = ADXL345();             // USE FOR I2C COMMUNICATION

Make sure to comment out // the line of code you are not using. By default, the code has you utilizing SPI communication.

Setup

The most complex part of the example code is the void setup() section. This is where you’ll be able to configure your settings and sensing feature thresholds.

language:c
/******************** SETUP ********************/
/*          Configure ADXL345 Settings         */
void setup(){

Serial.begin(9600);                 // Start the serial terminal
Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
Serial.println();

adxl.powerOn();                     // Power on the ADXL345

adxl.setRangeSetting(16);           // Give the range settings
                                    // Accepted values are 2g, 4g, 8g or 16g
                                    // Higher Values = Wider Measurement Range
                                    // Lower Values = Greater Sensitivity

adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
                                    // Default: Set to 1
                                    // SPI pins on the ATMega328: 11, 12 and 13 as reference in SPI Library

adxl.setActivityXYZ(1, 0, 0);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
adxl.setActivityThreshold(75);      // 62.5mg per increment   // Set activity   // Inactivity thresholds (0-255)

adxl.setInactivityXYZ(1, 0, 0);     // Set to detect inactivity in all the axes "adxl.setInactivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
adxl.setInactivityThreshold(75);    // 62.5mg per increment   // Set inactivity // Inactivity thresholds (0-255)
adxl.setTimeInactivity(10);         // How many seconds of no activity is inactive?

adxl.setTapDetectionOnXYZ(0, 0, 1); // Detect taps in the directions turned ON "adxl.setTapDetectionOnX(X, Y, Z);" (1 == ON, 0 == OFF)

// Set values for what is considered a TAP and what is a DOUBLE TAP (0-255)
adxl.setTapThreshold(50);           // 62.5 mg per increment
adxl.setTapDuration(15);            // 625 μs per increment
adxl.setDoubleTapLatency(80);       // 1.25 ms per increment
adxl.setDoubleTapWindow(200);       // 1.25 ms per increment

// Set values for what is considered FREE FALL (0-255)
adxl.setFreeFallThreshold(7);       // (5 - 9) recommended - 62.5mg per increment
adxl.setFreeFallDuration(30);       // (20 - 70) recommended - 5ms per increment

// Setting all interupts to take place on INT1 pin
//adxl.setImportantInterruptMapping(1, 1, 1, 1, 1);     // Sets "adxl.setEveryInterruptMapping(single tap, double tap, free fall, activity, inactivity);"
                                                        // Accepts only 1 or 2 values for pins INT1 and INT2. This chooses the pin on the ADXL345 to use for Interrupts.
                                                        // This library may have a problem using INT2 pin. Default to INT1 pin.

// Turn on Interrupts for each mode (1 == ON, 0 == OFF)
adxl.InactivityINT(1);
adxl.ActivityINT(1);
adxl.FreeFallINT(1);
adxl.doubleTapINT(1);
adxl.singleTapINT(1);

//attachInterrupt(digitalPinToInterrupt(interruptPin), ADXL_ISR, RISING);   // Attach Interrupt

}

The comments can help guide you as to what each function does along with recommended ranges to stay within where applicable. More detailed information of the sensing functions and interrupts can be found on the ADXL345 Datasheet.

Main Code

The main example code was kept very simple. It focuses on not only reading the accelerometer values but also checking to see if any interrupts have occurred.

language:c
/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){

// Accelerometer Readings
int x,y,z;
adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

// Output Results to Serial
/* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */
//Serial.print(x);
//Serial.print(", ");
//Serial.print(y);
//Serial.print(", ");
//Serial.println(z);

ADXL_ISR();
// You may also choose to avoid using interrupts and simply run the functions within ADXL_ISR();
//  and place it within the loop instead.
// This may come in handy when it doesn't matter when the action occurs.

}

Currently, the sketch will only output free fall detection, inactivity/activity, and single/double tap detection to the Serial Monitor.

In order to print the measured accelerometer values to the Serial Monitor, just remember to uncomment the following section to look like this:

language:c
// Output Results to Serial
/* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */
Serial.print(x);
Serial.print(", ");
Serial.print(y);
Serial.print(", ");
Serial.println(z);

Serial Monitor Output

Let’s see it in action! Go to Tools on your Arduino IDE, set your board and port, and upload the SparkFun_ADXL345_Example.ino sketch to your Arduino or compatible board. If you need further assistance in uploading your sketch this might be helpful: Uploading a Sketch.

The following two Serial Monitor outputs are what you should expect whether you have commented out the accelerometer values from being displayed or not.

Accelerometer Values Excluded

This is what your outputs will look like with the sensing features are triggered.

alt text

Accelerometer Values Included

This is the data you should see when you have uncommented the X, Y and Z Serial.print() lines of code. Also, keep in mind you will still see when the sensing features are triggered, it just might be harder to catch amongst the data stream.

alt text

Calibration

The other sketch available to you is the SparkFun_ADXL345_Calibration.ino. This will be useful whenever you have an application that requires your device to be precision calibrated.

Calibration Method

An accurate calibration method is to use two points per axis. In our case we have a three-axis design, therefore, we are interested in six points. In the datasheet and in the example sketch, you’ll notice references to the g range with accepted values of 2g, 4g, 8g or 16g. 1g is equivalent to the force of gravity acting on a stationary object resting on Earth’s surface. Acceleration relative to gravity can be measured in units of gravitational force.

A great resource is the Application Note from Analog Devices: Using an Accelerometer for Inclination Sensing

Calibration Example Sketch

Here is what the calibration example sketch looks like:

language:c
#include <SparkFun_ADXL345.h>

/*********** COMMUNICATION SELECTION ***********/
/*    Comment Out The One You Are Not Using    */
//ADXL345 adxl = ADXL345(10);           // Use when you want to use Hardware SPI, ADXL345(CS_PIN);
ADXL345 adxl = ADXL345();             // Use when you need I2C

/****************** VARIABLES ******************/
/*                                             */
int AccelMinX = 0;
int AccelMaxX = 0;
int AccelMinY = 0;
int AccelMaxY = 0;
int AccelMinZ = 0;
int AccelMaxZ = 0;

int accX = 0;
int accY = 0;
int accZ = 0;

int pitch = 0;
int roll = 0;

/************** DEFINED VARIABLES **************/
/*                                             */
#define offsetX   0       // OFFSET values
#define offsetY   0
#define offsetZ   0

#define gainX     1     // GAIN factors
#define gainY     1
#define gainZ     1

/******************** SETUP ********************/
/*          Configure ADXL345 Settings         */
void setup()
{
Serial.begin(9600);                 // Start the serial terminal
Serial.println("SparkFun ADXL345 Accelerometer Breakout Calibration");
Serial.println();

adxl.powerOn();                     // Power on the ADXL345

adxl.setRangeSetting(2);           // Give the range settings
                                    // Accepted values are 2g, 4g, 8g or 16g
                                    // Higher Values = Wider Measurement Range
                                    // Lower Values = Greater Sensitivity

adxl.setSpiBit(0);                // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
                                    // It is set to 1 by Default.
                                    // SPI pins on the ATMega328 as reference in SPI Library are 11, 12, and 13

}

/****************** MAIN CODE ******************/
/*  Accelerometer Readings and Min/Max Values  */
void loop()
{
Serial.println("Send any character to display values.");
while (!Serial.available()){}       // Waiting for character to be sent to Serial
Serial.println();

// Get the Accelerometer Readings
int x,y,z;                          // init variables hold results
adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

if(x < AccelMinX) AccelMinX = x;
if(x > AccelMaxX) AccelMaxX = x;

if(y < AccelMinY) AccelMinY = y;
if(y > AccelMaxY) AccelMaxY = y;

if(z < AccelMinZ) AccelMinZ = z;
if(z > AccelMaxZ) AccelMaxZ = z;

Serial.print("Accel Minimums: "); Serial.print(AccelMinX); Serial.print("");Serial.print(AccelMinY); Serial.print(""); Serial.print(AccelMinZ); Serial.println();
Serial.print("Accel Maximums: "); Serial.print(AccelMaxX); Serial.print("");Serial.print(AccelMaxY); Serial.print(""); Serial.print(AccelMaxZ); Serial.println();
Serial.println();


/* Note: Must perform offset and gain calculations prior to seeing updated results
/  Refer to SparkFun ADXL345 Hook Up Guide: https://learn.sparkfun.com/tutorials/adxl345-hookup-guide
/  offsetAxis = 0.5 * (Acel+1g + Accel-1g)
/  gainAxis = 0.5 * ((Acel+1g - Accel-1g)/1g) */

// UNCOMMENT SECTION TO VIEW NEW VALUES
//accX = (x - offsetX)/gainX;         // Calculating New Values for X, Y and Z
//accY = (y - offsetY)/gainY;
//accZ = (z - offsetZ)/gainZ;

//Serial.print("New Calibrated Values: "); Serial.print(accX); Serial.print(""); Serial.print(accY); Serial.print(""); Serial.print(accZ);
//Serial.println();

while (Serial.available())
{
    Serial.read();                    // Clear buffer
}
}

The main code will read your accelerometer maximums and minimums. With these values we will be able to calculate the offset values and gain factors giving us our new calibrated accelerometer readings. We will talk more about the equations for those calculations in a minute.

Mounting Accelerometer

Before taking these measurements, we want to have the accelerometer mounted with the Z axis parallel to the up direction. For example, if our accelerometer is on a table, our ADXL345 breakout board will be oriented like the picture below and the Z data should be constant.

alt text

Make sure it’s secure to either your application or a block that has a level flat surface.

Load Sketch and Take Measurements

Load the Calibration Sketch to your board. Open the Serial Monitor, and wait for the prompt that says to Send any character to display values. Each time you want to measure a different axis, simply turn the enclosure or block the ADXL345 breakout is mounted on, type a character to the Serial Monitor, and hit return to print out the measurement result. You’ll notice an X-Y-Z axis symbol on the breakout board that will help with orienting in each direction.

alt text

When an axis is placed into a +1 g and −1 g field, the measured outputs will look something like this on your Serial Monitor. You’ll want to take measurements in each axis direction.

alt text

Recording Data

To leave room for offset and gain adjustments, it’s probably best to do the calculations by hand. Record your data in a similar table like the one below.

+1 g -1 g OffsetGain
X-Axis
Y-Axis
Z-Axis

Calculations

The offset values and gain factors are calculated with the following equations as stated in the Application Note from Analog Devices (page 8: equations 17 and 18).

alt text

In the DEFINED VARIABLES section of the code is where we will place the new calculated values for offset and gain.

language:c
/************** DEFINED VARIABLES **************/
/*                                             */
#define offsetX     0    // OFFSET values
#define offsetY     0
#define offsetZ     0

#define gainX       1     // GAIN factors
#define gainY       1
#define gainZ       1

Hooray! Now you’ll be able to acquire the adjusted values for X, Y and Z.

Note: You'll have to uncomment a section of the following code to see your new calibrated values:

language:c
// UNCOMMENT SECTION TO VIEW NEW VALUES
accX = (x - offsetX)/gainX;         // Calculating New Values for X, Y and Z
accY = (y - offsetY)/gainY;
accZ = (z - offsetZ)/gainZ;

Serial.print("New Calibrated Values: "); Serial.print(accX); Serial.print(""); Serial.print(accY); Serial.print(""); Serial.print(accZ);
Serial.println();

Now your Serial Monitor output will be calibrated and look something more like this…

alt text

Resources & Going Further

The SparkFun Triple Access Accelerometer ADXL345 and the ADXL345 Arduino Library are both open-source, so there are plenty of resources, including:

For more information on the ADXL345, the datasheet can be referred to.

ADXL345 Accelerometer Project Inspiration

Dungeons and Dragons Dice Gauntlet

A playful, geeky tutorial for a leather bracer that uses a LilyPad Arduino, LilyPad accelerometer, and seven segment display to roll virtual 4, 6, 8, 10, 12, 20, and 100 side dice for gaming.

Das Blinken Top Hat

A top hat decked out with LED strips makes for a heck of a wedding gift.

Blynk Board Washer/Dryer Alarm

How to configure the Blynk Board and app to notify you when your washer or dryer is done shaking.

learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Getting Started with the AutoDriver - v13

$
0
0

Getting Started with the AutoDriver - v13 a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t558

Introduction

Autodriver Board

The AutoDriver board is based on the STMicro L6470 dSPIN stepper motor driver. This powerful chip allows you to control a stepper motor with a voltage from 8-45V at 3Arms over an SPI connection. Compared to traditional step/direction motor controllers, it offers a number of advantages:

  • The L6470 tracks the current position of the motor, so the application level doesn’t have to.
  • “Fire-and-forget” motion control, which allows the application to continue working while the motor autonomously completes the desired motion.
  • Acceleration and deceleration curves without complex software algorithms.
  • Microstepping for extra smooth movements.
  • Configurable currents for acceleration, deceleration, run, and hold, which give greater control to the user over power consumption.
  • SPI interface, which allows for a greater number of motors to be driven from a single processor.

The primary disadvantage of the L6470 is that it requires a great deal more configuration and adds software complexity to your system. This hookup guide will attempt to relieve some of that difficulty.

Differences in v13 of the hardware

Version 13 of the hardware is slightly different to the previous revision. It has been modified to make it easier to daisy-chain multiple boards together with simple 10-conductor ribbon cables for data and 6-conductor ribbon cables for control.

The library has changed as well, although it is possible to use the new library with the old revisions. The main addition to the library is an index parameter which is passed to the class constructor, allowing the user to specify where each Autodriver board is in a chain. Pin and SPI configuration were moved out of the library, as well, allowing for the use of SPI ports other than the main port on devices with more than one SPI port.

Suggested Reading

Before you get started, you may want to look at these other tutorials to get you headed in the right direction:

  • SPI - The Serial Peripheral Interface is the means by which the L6470 chip, and therefore the AutoDriver board, communicates with the system master CPU.
  • Motors - Understanding stepper motors is important to driving them.
  • Installing an Arduino Library - The AutoDriver has an Arduino library; if you don’t already know how to install a new library, check out this tutorial to get you pointed in the right direction.

Hardware

The AutoDriver board is designed to be easily integrated into a project, even with multiple boards. Here’s a brief tour of the hardware and how to connect it up.

The Board

Labeled pic of the Autodriver

As you can see above, there are several connectors on the board. Let’s take them one at a time:

  1. Communications in - where the SPI, clock, and logic level power enter the board. That can be either from the system CPU or from a prior AutoDriver board. By default, the AutoDriver expects a power supply input here, but that power supply is not the supply to the motors and should not exceed 5V. Designed for a 2x5 .1" shrouded connector, and to be connected by a 2x5 ribbon cable.
  2. Communications out - SPI, clock, and logic power out to the next AutoDriver. Designed for a 2x5 .1" shrouded connector, and to be connected by a 2x5 ribbon cable.
  3. Control signal in - metasignals for input and output to and from the AutoDriver. Chip select, optional step clock, and reset inputs come in here, and open-drain busy and error flag signals go back to the previous board. Designed for a 2x3 .1" shrouded header and to be connected by a 2x3 ribbon cable.
  4. Control signal out - Passes the common control signals on to the next AutoDriver. All pins on this header are common to the same pins on the control signal input header. Designed for a 2x3 .1" shrouded header and to be connected by a 2x3 ribbon cable.
  5. Switch input - the L6470 can accept input from switches to provide for a hard-stop limit switch or a configurable user interrupt. We’ll cover that later. Sized for a 3.5mm screw terminal.
  6. Power input - two connectors with two terminals each for power and ground to make connecting multiple boards to one power supply easy. This is the motor power input and is sized for a 3.5mm screw terminal. Motor power must be connected in order for the board to respond to commands!
  7. A and B winding outputs - the L6470 is designed to work with a bipolar stepper motor or a unipolar or universal stepper motor configured as a bipolar. One winding should be connected to each of these terminals, although it doesn’t matter which winding connects to which terminal (other than to determine which direction is considered “forward”).
  8. ADC input/potentiometer footprint - this footprint can be populated with a 200k potentiometer to provide for motor supply voltage correction, to ensure a constant drive current across varying supply voltages. Highly optional, but we put the footprint there, just in case.
  9. Data voltage supply signal - This jumper selects between the external supply on the communication header and the internally generated 3V supply. It is generally assumed that the user will pass the supply voltage across the communication header.
  10. Data routing jumper - This jumper allows the user to determine where data from this board will be sent: either forward, to the next board in the series, or backward, to the previous board in the series. When multiple Autodriver boards are connected in series, the last board (farthest from the controlling CPU) should be left as default (i.e., ‘prev bd’ setting) and all others should have the ‘next bd’ setting selected. If only one board is to be used, ‘prev bd’ should be selected.

An Example Connection to a RedBoard

Demo circuit

Later in this tutorial, we will show you how to hook up two AutoDriver boards to a RedBoard. For that example, you’ll need two AutoDriver Boards along with the following:

Test Hardware Assembly

Here’s a step-by-step guide for assembling the parts used for the rest of the guide. If you have your own hardware, feel free to skip this part, but it’s not a bad exercise to get you up to speed and make sure that your hardware is in a “known good” state before you begin writing code.

I’m going to take a few liberties with the basics here and assume that you’re capable of assembling the RedBoard/Breadboard holder on your own, and that you can put the headers and screw terminal blocks on the AutoDriver boards without help. Pay attention to the orientation of the shrouded headers on the AutoDriver – if you get them lined up properly, it’ll help ensure that the signal routing through the ribbon cables is proper later on. Also note the single pin for the chip select, near the control signal in header. You’ll need that later on.

Assembled AutoDriver

I’ve also made a base plate to hold my AutoDriver boards in place; mine is fancy laser-cut acrylic, but you can hot glue the boards to a piece of cardboard or even just leave them loose, depending on your personal preferences and tool availability.

Assembling the ribbon cables

You can use pre-assembled ribbon cables, but, as we don’t sell pre-assembled 6-conductor cables nor ribbon cables terminated in breadboard-friendly connections, I’m going to cover assembling the necessary cables here.

The easiest way to crimp the connectors to the end of the cable is to use a workbench vise; alternatively a pair of channel lock or vise-grip type pliers works well. In a pinch, you can use body weight and any flat surface; it takes quite a lot of pressure to push the connectors shut, however. Don’t squeeze too hard, or you’ll break the plastic.

Start by cutting your ribbon cable pieces. A pair of scissors works great for this, although it’ll be rough on them, so don’t use your sewing scissors! To keep our images concise, I’m using really short ribbons for these pictures. Feel free to make yours as long as necessary, although cables longer than a foot or two may cause signal integrity issues, which may affect the operation of your system.

Make sure that there are no little pieces of wire protruding from the end of the ribbon cable – those can really ruin your day.

Now we need to crimp connectors onto the ends of each cable. We’ll start with the breadboard-friendly ends; those are the hardest. Note that we’re using the 2x5 connector for both the 10- and 6-conductor cables, since we don’t sell a 2x3 breadboard-friendly end.

Insert the ribbon cable into the connector as shown below. For the 2x3, make sure that you’ve got the ribbon cable all the way to the top edge!

Preparing the connector for crimping

Before you apply pressure to crimp the connector closed, you need something to prevent the pins from being smashed in the process. A pencil fits between the pins perfectly.

Crimping the connector

Next, we’ll want to crimp on one of the other connectors. See the image below for proper orientation; crimping this in place is much easier because it doesn’t have pins to be damaged.

Crimping the 2x3 connector

Finally, assemble the additional connectors to the ends of the other ribbon cables, as shown below. Orientation of the connector is important, as the keying on the shrouded headers forces them into the proper orientation only if the cables are assembled right!

alt text

Pay careful attention to the orientation of the keying tab relative to the blue wire!

alt text

The 10-conductor wires go together just like these, except using the black wire as reference.

Wiring up the stepper motors

As mentioned earlier, there are two screw terminals on the board for connecting the motor. Each one should have one coil of the motor connected to it; if you’re not sure of how your stepper motor’s wires are connected, you can use a multimeter to figure it out. Two wires connected to the same coil should show a very low resistance (on the order of a few ohms) between them.

Once you’ve identified the pairs of wires, connect one pair to the ‘A’ screw terminal and the other to the ‘B’ screw terminal. The order of the wires isn’t terribly important yet, as the order determines the direction in which the motor turns, not whether it turns or not.

Motor wires connected

The above picture shows the order I’ve selected for our medium stepper motors. It’s probably a good idea to use the same wire order on both boards, so the relative direction of both motors is the same. If you need the direction to be opposite for the two motors (say, to drive the wheels of a robot), you can simply reverse the order of one pair of wires.

Connecting the boards

If all your ribbon cables are properly assembled, the rest of this should be a snap. Start by inserting the breadboard-friendly ends into the breadboard. You’ll be making connections on both sides of the connector, so it helps to pre-bend the ribbon to a right angle with the breadboard.

Breadboard connections

Here’s a little wiring diagram of how the connections to the breadboard connectors should be made from the RedBoard or Arduino.

Breadboard to AutoDriver

That’s the hardest part. Now all you need to do is connect the ribbon cables to the AutoDriver boards.

Ribbons between AutoDrivers

Connecting the Power Supply

Finally, connect up the power. All you need is a four pieces of hookup wire with bared ends. Here’s a picture of the power connections all wired up:

Power connections to the AutoDriver board

It’s generally a good idea to hook up the power to the RedBoard and logic circuitry before you power the AutoDrivers; do note that you can’t access the AutoDriver boards via SPI until BOTH parts are powered, however.

Arduino Library - Configuration

To make your life a little easier, we’ve developed a fairly comprehensive library for configuring and controlling the AutoDriver. On this page, we’ll go through the various commands in the library and the impact they have on the operation of the AutoDriver board.

As mentioned earlier, the AutoDriver requires more configuration to operate than standard “step/direction” type stepper motor drivers. We’ve provided functions to make configuring the registers in the L6470 chip much easier than it might otherwise be. Here they are, in no particular order.

Downloading the Library

The library is hosted on GitHub, along with the other design files associated with the AutoDriver board. To install the library and example code to your computer, download this zip file and follow these directions to install the library.

Initialization functions

There are two initialization functions (or “constructors”, in C++ class-speke) provided for the AutoDriver library. You must invoke one of them to create an instance of class AutoDriver before you can use the board.

language:cpp
AutoDriver(int boardPos, int CSPin, int resetPin, int busyPin);
AutoDriver(int boardPos, int CSPin, int resetPin);

The two constructors provided allow you to specify which pins the particular AutoDriver boards are connected to, and where the particular board is in the chain of boards. It is assumed that you will connect at least the reset and chip select pins; connecting the busy pin is optional, as the busyCheck() function will check either the pin state or the device’s internal register to determine if the AutoDriver is busy or not, depending on whether you use the constructor that initializes a busy pin assignment or not.

This hardware does not initialize the SPI hardware, nor the pin states, for you. For information about how to do that, see the official Arduino SPI library documentation, or any of the code examples that come with the library. It is recommended that you use pin 10 as a chip select pin, since that pin must remain an output at all times in order for the library to function properly (this is a requirement of the SPI peripheral in the chip and cannot be changed).

In order to tell the library which SPI port to use, you’ll need to call this function:

language:cpp
SPIPortConnect(SPI *portName);

This allows boards with more than one SPI port to select the one they want to use. For a normal Arduino, though, we expect the function call to look like this:

language:cpp
AutodriverBoardName.SPIPortConnect(&SPI);

See the included examples for more information.

Setting Basic Chip Parameters

There are many different parameters which must be set for the AutoDriver to function properly. These are stored in RAM on the AutoDriver and must be configured after every power cycle or chip reset.

Some of these parameters must be set for the chip to operate successfully; those parameters are described here.

void configSyncPin(byte pinFunc, byte syncSteps);

The BUSY pin on the AutoDriver actually has two possible functions: it can indicate when the board is BUSY (usually indicating that a motion command is underway and has not yet completed) or it can be used to output a sync signal for counting full motor steps with an external device.

There are constants defined for the two parameters: the first can be either BUSY_PIN or SYNC_PIN. If SYNC_PIN is passed, the second parameter should be one of the following:

  • SYNC_FS_2 - two pulses on sync pin per full step of motor
  • SYNC_FS - one pulse per full step
  • SYNC_XFS - where X can be 2, 4, 8, 16, 32, or 64, and X indicates the number of full steps between pulses on the sync pin

If BUSY_PIN is passed, the second paramater should be zero.

void configStepMode(byte stepMode);

The AutoDriver is capable of microstepping, wherein the output signal is PWMed to create a pseudo-sine wave output which makes the transition from one step to the next less jerky. There are 8 possible microstep options, and defines have been provided for selecting between them:

  • STEP_FS - Full-step mode; microstepping disabled
  • STEP_FS_X - Enable microstepping with X microsteps per full step. X can be 2, 4, 8, 16, 32, 64, or 128.

Note that enabling microstepping has no effect on motion commands or sync pulse outputs; it is not possible to move less than one full step. Microstepping simply makes the transition between steps smoother.

void setMaxSpeed(float stepsPerSecond);

Provide an upper limit to the speed the driver will attempt to reach. Attempts to exceed this speed will result in motion being completed at this speed. The value established by this command will also be the value used for motion commands such as goTo() where no speed parameter is provided.

void setMinSpeed(float stepsPerSecond);

The minimum speed is slowest speed the motor will run. If low speed optimization is enabled (see below), minimum speed is automatically zero, and the special low-speed waveform optimization will be used until minimum speed is reached. Defaults to zero.

void setFullSpeed(float stepsPerSecond);

If microstepping is enabled, this parameter sets the speed above which microstepping is disabled and the driver engages full step mode.

void setAcc(float stepsPerSecondPerSecond);
void setDec(float stepsPerSecondPerSecond);

Set the acceleration/deceleration curves to be used. The maximum value for this is 29802; above that, the AutoDriver will not use any curve at all.

void setOCThreshold(byte threshold);

Sets the level at which an overcurrent event occurs. There are 16 different options; all take the format OC_XmA, where X is the limit and can be any of these values: 375, 750, 1125, 1500, 1875, 2250, 2625, 3000, 3375, 3750, 4125, 4500, 4875, 5250, 5625, or 6000.

void setPWMFreq(int divisor, int multiplier);

There’s a separate internal clock for the PWM frequency used by the chip when microstepping or when KVAL settings (more on these later) call for a reduction in current. This frequency is 31.3kHz (nominal, when using the internal 16MHz clock), and is adjusted by the divisor and multiplier sent to this function. Again, we’ve created a set of defines for the possible values:

  • For divisor, define syntax is PWM_DIV_X, where X can be any value 1-7.
  • For multiplier, define syntax is PWM_MUL_X, where X can be 0_625 (for 0.625), 0_75 (for 0.75), 0_875, 1, 1_25, 1_5, 1_75, or 2.

It’s a good idea to keep the frequency above 20kHz or so, to avoid annoying those in close proximity to the device, as lower frequencies can cause an audible ring or buzz.

void setSlewRate(int slewRate);

The slew rate is the slope of the voltage change coming out of the driver. There are three options here: 180V/us, 290V/us, and 530V/us. Higher slew rates increase the torque at higher speeds, at the risk of increased electromagnetic emissions, which may or may not matter to you. The defines for this are SR_180V_us, SR_290V_us, SR_530V_us.

void setOCShutdown(int OCShutdown);

By default, the drive transistors in the L6470 chip will shutdown on an overcurrent event to prevent damage to motor and driver. This can be disabled by passing the define OC_SD_DISABLE to this function, and re-enabled by passing OC_SD_ENABLE.

void setOscMode(int oscillatorMode);

This is one of the more important of the basic parameters. By default, the chip will run at 16MHz on its internal oscillator, and that suffices for most applications. However, in a situation where more than one AutoDriver is being used in a circuit, it’s best to drive all of the boards from a common clock, so the motors will remain synchronized. That clock source can be either an external clock fed to the first chip and then passed along to subsequent chips, or it can be the internal clock source of the first chip, passed along to later devices. There are rather a lot of possible options here; we’ve created a verbose set of constants to help you select the right one:

  • INT_16MHZ - Use the internal 16MHz oscillator, with no output on the OSCOUT line.
  • INT_16MHZ_OSCOUT_2MHZ - Internal 16MHz, 2MHz on OSCOUT. Default.
  • INT_16MHZ_OSCOUT_4MHZ - Internal 16MHz, 4MHz on OSCOUT.
  • INT_16MHZ_OSCOUT_8MHZ - Internal 16MHz, 8MHz on OSCOUT.
  • INT_16MHZ_OSCOUT_16MHZ - Internal 16MHz, 16MHz on OSCOUT. Recommended for the first AutoDriver in a system with more than one AutoDriver.
  • EXT_8MHZ_XTAL_DRIVE - External 8MHz crystal. Not recommended.
  • EXT_16MHZ_XTAL_DRIVE - External 16MHz crystal. Not recommended.
  • EXT_24MHZ_XTAL_DRIVE - External 24MHz crystal. Not recommended.
  • EXT_32MHZ_XTAL_DRIVE - External 32MHz crystal. Not recommended.
  • EXT_8MHZ_OSCOUT_INVERT - 8MHz clock to OSCIN. Inverted OSCIN on OSCOUT.
  • EXT_16MHZ_OSCOUT_INVERT - 16MHz clock to OSCIN. Inverted OSCIN on OSCOUT. Recommended for subsequent boards in a multi-board system.
  • EXT_24MHZ_OSCOUT_INVERT - 24MHz clock to OSCIN. Inverted OSCIN on OSCOUT.
  • EXT_32MHZ_OSCOUT_INVERT - 32MHz clock to OSCIN. Inverted OSCIN on OSCOUT.

Two things of note regarding the osciallator settings: first, if you select an invalid setting (for example, an external crystal in a system with no crystal), the AutoDriver board will stop responding. Because the settings are stored in RAM, however, a reset or power cycle of the chip will restore it to operation, allowing you to change your program to a supported clock mode.

Second, the frequency specified in this is used by the library to convert user-friendly units to units the chip understands. Using any frequency besides 16MHz will result in scale errors when setting speeds in steps per second, acceleration in steps per second per second, etc.

Advanced Chip Parameters

void setVoltageComp(int vsCompMode);

Voltage compensation attempts to keep the motor’s behavior consistent across varying supply voltage. This is not as straightforward as it sounds, and users wanting to employ this functionality are urged to consider page 34 of the L6470 datasheet.

The defines to enable or disable this are VS_COMP_ENABLE and VS_COMP_DISABLE.

void setSwitchMode(int switchMode);

The switch input on the AutoDriver mode can be made to do one of two things: hard-stop the motor (for limit switch functionality), or perform user-based functions by exposing the switch mode to the user through an internal register. The constants to select between the modes are SW_HARD_STOP and SW_USER.

void setAccKVAL(byte kvalInput);
void setDecKVAL(byte kvalInput);
void setRunKVAL(byte kvalInput);
void setHoldKVAL(byte kvalInput);

The KVAL settings allow you to impose a global scaling on the current used for the four conditions listed above. The input ranges from 0-255, or 0% to 100% in steps of approximately .4%. This can be a good way to reduce the power consumption of your system if the full torque provided by 100% current operation is not required.

void setLoSpdOpt(boolean enable);

Low-speed optimization attempts to improved the zero-crossing of the driving sine wave at low speeds. When low-speed optimization is enabled (true passed to this function), the value set for minimum speed above becomes the speed at which low-speed optimization is no longer applied. When disabled (default, or false passed to this function), the minimum speed value is the lowest speed the driver will attempt to use.

Arduino Library - Operation

Having covered configuring the board to run, let’s talk about the commands that actually cause it to perform operations. One common parameter through all of these commands is dir. Any command which calls for dir can have passed to it either FWD or REV. So long as all of your motors are wired up the same, those values will produce the same rotation in all motors. If you find yourself dissatisfied with the rotational direction produced by the FWD and REV constants, the best course of action is to reverse the order of the wires on ONE winding on the motor in question. That will reverse the direction the motor spins.

Any motion will begin at the value defined by the setMinSpeed() function (unless low-speed optimization is enabled, in which case, the motion starts at 0 steps/s and low-speed optimization is used until MIN_SPEED is reached), and will use both the acceleration and deceleration curve values to reach the final speed.

Basic Operations

void resetDev();

Equivalent to toggling the reset pin, but performed through an internal software register control on the L6470 chip. If you don’t want to use a pin for reset, this option is for you.

void busyCheck();

Returns a 1 if the board is “busy”, i.e., executing a motion command, or a 0 if not. If the current instance of the AutoDriver board was defined with a busyPin, it checks that pin; otherwise, it reads the internal STATUS register on the board to see if the driver is busy or not.

void run(byte dir, float stepsPerSec);

Turns the motor either FWD or REV at stepsPerSecond rate, forever. The BUSY flag will remain asserted until motion is stopped by either issuing a hard stop or a soft stop.

void move(byte dir, unsigned long numSteps);

Turn the motor FWD or REV by numSteps full steps. numSteps is internally limited to 22 bits and is unsigned. The motor will use the acceleration profile as mentioned above, and the top speed of the motor during the motion will be the speed set with the setMaxSpeed() function.

void softStop();

Stop the motor using the value set in the setDec() function. Motor will come to a nice, gentle halt.

void hardStop();

Stop the motor with “infinite” deceleration. Motor will lurch to a very rapid grinding halt. Good for emergency stops.

void softHiZ();

Execute a soft stop, then put the motor drivers into a high-impedance state where no current flows through the windings. Note that this means the motor will turn freely!

void hardHiZ()

Execute a hard stop, followed by setting the drivers to high-impedance.

Position Operations

There are two registers in the L6470 which can be used for absolute position tracking and motion commands: ABS_POS and MARK. These functions use those registers to provide for motion based on the current and desired position of the motor, measured in steps.

long getPos();

The ABS_POS register in the L6470 chip on the AutoDriver contains a 22-bit signed value (-2097152 to 2097151 steps) tracking the position of the motor. This register starts at 0 on power up or reset. getPos() returns the current value of that register. It is automatically incremented during moves of FWD direction, and decremented during moves of REV direction.

void resetPos();

Zero out the ABS_POS register, resetting home to the current location.

void setMark(long newMark)

Create a new MARK, which can be used as a shortcut for some motion commands. The value in MARK can also be automatically set by some events (such as activity on the switch input), if the device is configured properly. Same limits as set forth in the getPos() function above.

void setPos(long newPos)

Set the current position to a new, arbitrary value. Same limits as set forth in the getPos() function above.

void goTo(long pos)

From the current position, move in the shortest possible direction to the position passed by the user. Same limits as set forth in the getPos() function above.

void goToDir(byte dir, long pos);

Similar to goTo(), but with a specified direction. Same limits as set forth in the getPos() function above.

void goHome();

Similar to goTo(0) but requires less time to send via SPI. If a direction is required, use goToDir() instead.

Advanced motion operations

void stepClock(byte dir);

Put the device in a “step-per-pulse” mode, where pulses on the STCK line will cause the motor to move one step in the direction indicated by dir. The ABS_POS register will update, and microstepping will be used to move the motor.

void goUntil(byte action, byte dir, float stepsPerSec);

Start the motor moving, according to the acceleration profile, either FWD or REV, at stepsPerSec rate, until a switch even occurs. When the switch event occurs, one of two things happens, based on the value passed to action: if RESET_ABSPOS is sent to action, the ABS_POS register is reset to zero. If COPY_ABSPOS is sent, the ABS_POS register is copied into the MARK register.

Either way, once the signal is received, either a hard stop or a soft stop will occur. The mode is determined by the setSwitchMode() function: passing SW_HARD_STOP to setSwitchMode() results in a hardstop, while passing SW_USER results in a soft stop.

void releaseSw(byte action, byte dir);

Move the motor at minimum speed until the switch is released, then hard stop and perform action in the same manner as goUntil() (i.e., copy ABS_POS into MARK or reset ABS_POS).

Parameter Access

Because we understand that you may want to do things the hard way, we’ve included two extra functions which provide full access to the parameter registers documented in the datasheet.

void setParam(byte param, unsigned long value);
unsigned long getParam(byte param);

Both can be used to arbitrarily read and write the exact contents of the registers in the datasheet. Names for the registers as described in the datasheet have been defined for use here, as well.

int getStatus();

Returns the current contents of the STATUS register on the L6470 chip. This is a good communications sanity check because on boot, the value will be 0x2E88.

Example

Having covered the hardware setup and the use of the library, all that remains is to provide an example sketch for the AutoDriver board.

This sketch allows you to play music by controlling the step rate of your motor. The default song it plays is the first part of “Want You Gone” by Jonathon Coulton. I’m only including the main file and the support functions here; the notes.h and wantYouGone() function files are available on the board’s GitHub page.

alt text

If you skipped over the Test Hardware Assembly page, and just want to hook up an AutoDriver to an Arduino or RedBoard as easily as possible, see the above diagram. You’ll need to change the example sketch to remove references the boardB, however, and to not use the busy pin.

Because of the size and complexity of this sketch, it has been broken into several files. Please be sure you have all the files downloaded!

Setup() and Loop()

language:cpp
#include <SparkFunAutoDriver.h>
#include <SPI.h>
#include "SparkFunnotes.h"

// Test sketch for the L6470 AutoDriver library. This program instantiates three
//  AutoDriver boards and uses them to play Jonathon Coulton's "Want You Gone" from
//  the Portal 2 soundtrack. In a more general sense, it adds support for playing
//  music with stepper motors. Not all notes can be played, of course- at too high
//  a steps/sec rate, the motors will slip and dogs and cats will live together.


// Create our AutoDriver instances. The parameters are the position in the chain of
//  boards (with board 0 being located at the end of the chain, farthest from the
//  controlling processor), CS pin, and reset pin.
AutoDriver boardA(0, 10, 8);
AutoDriver boardB(1, 10, 8);

void setup()
{
  Serial.begin(9600);
  Serial.println("Hello world");
  // Start by setting up the SPI port and pins. The
  //  Autodriver library does not do this for you!
  pinMode(8, OUTPUT);
  pinMode(MOSI, OUTPUT);
  pinMode(MISO, INPUT);
  pinMode(13, OUTPUT);
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  digitalWrite(8, LOW);       // This low/high is a reset of the L6470 chip on the
  digitalWrite(8, HIGH);      //  Autodriver board, and is a good thing to do at
                              //  the start of any Autodriver sketch, to be sure
                              //  you're starting the Autodriver from a known state.
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);
  dSPINConfig();
}

// loop() waits for a character- any character- and then plays the song.
void loop()
{
  if (Serial.available() !=0)
  {
    Serial.read();
    Serial.println("Play it!");
    wantYouGone();
    Serial.println("Done playing!");
  }
}

In the main file, you can see that there’s not much going on. We initiate two AutoDriver boards (as befits our hardware test setup described earlier), call a configuration function, initialize our SPI port and pins, then wait around for a user to request us to play the music.

Support Functions

// Support functions.

#define NOTE_DIVISOR 2  // My cheesy way of reducing the note frequencies to a range
                        //  that doesn't cause the motor to slip. I *could* rewrite
                        //  the wantYouGone() function to change the notes, but that
                        //  would be a lot of work.

int stepDir = 1;        // Direction flipping bit. Rather than all going one way,
                        //  they change directions. It looks cooler.

// To play a note, we start the motor spinning at the note's frequency in steps/s.
//  The run() function automagically calculates the appropriate value to feed to the
//  dSPIN part based on the desired steps/s.
void playNote(int note, int duration)
{
  if (stepDir == 1)  boardA.run(FWD, note/NOTE_DIVISOR);
  else               boardA.run(REV, note/NOTE_DIVISOR);
  if (stepDir == 1)  boardB.run(REV, note/NOTE_DIVISOR);
  else               boardB.run(FWD, note/NOTE_DIVISOR);
  delay(duration);
  stepDir*=-1;
  boardA.softStop();
  boardB.softStop();
  while (boardA.busyCheck());
}

// This is the configuration function for the two dSPIN parts. Read the inline
//  comments for more info.
void dSPINConfig(void)
{
  boardA.SPIPortConnect(&SPI);      // Before doing anything else, we need to
  boardB.SPIPortConnect(&SPI);      //  tell the objects which SPI port to use.
                                    //  Some devices may have more than one.

  boardA.configSyncPin(BUSY_PIN, 0);// BUSY pin low during operations;
                                    //  second paramter ignored.
  boardA.configStepMode(STEP_FS);   // 0 microsteps per step
  boardA.setMaxSpeed(10000);        // 10000 steps/s max
  boardA.setFullSpeed(10000);       // microstep below 10000 steps/s
  boardA.setAcc(10000);             // accelerate at 10000 steps/s/s
  boardA.setDec(10000);
  boardA.setSlewRate(SR_530V_us);   // Upping the edge speed increases torque.
  boardA.setOCThreshold(OC_750mA);  // OC threshold 750mA
  boardA.setPWMFreq(PWM_DIV_2, PWM_MUL_2); // 31.25kHz PWM freq
  boardA.setOCShutdown(OC_SD_DISABLE); // don't shutdown on OC
  boardA.setVoltageComp(VS_COMP_DISABLE); // don't compensate for motor V
  boardA.setSwitchMode(SW_USER);    // Switch is not hard stop
  boardA.setOscMode(EXT_16MHZ_OSCOUT_INVERT); // for boardA, we want 16MHz
                                    //  external osc, 16MHz out. boardB
                                    //  will be the same in all respects
                                    //  but this, as it will generate the
                                    //  clock.
  boardA.setAccKVAL(128);           // We'll tinker with these later, if needed.
  boardA.setDecKVAL(128);
  boardA.setRunKVAL(128);
  boardA.setHoldKVAL(32);           // This controls the holding current; keep it low.

  boardB.configSyncPin(BUSY_PIN, 0);// BUSY pin low during operations;
                                    //  second paramter ignored.
  boardB.configStepMode(STEP_FS);   // 0 microsteps per step
  boardB.setMaxSpeed(10000);        // 10000 steps/s max
  boardB.setFullSpeed(10000);       // microstep below 10000 steps/s
  boardB.setAcc(10000);             // accelerate at 10000 steps/s/s
  boardB.setDec(10000);
  boardB.setSlewRate(SR_530V_us);   // Upping the edge speed increases torque.
  boardB.setOCThreshold(OC_750mA);  // OC threshold 750mA
  boardB.setPWMFreq(PWM_DIV_2, PWM_MUL_2); // 31.25kHz PWM freq
  boardB.setOCShutdown(OC_SD_DISABLE); // don't shutdown on OC
  boardB.setVoltageComp(VS_COMP_DISABLE); // don't compensate for motor V
  boardB.setSwitchMode(SW_USER);    // Switch is not hard stop
  boardB.setOscMode(INT_16MHZ_OSCOUT_16MHZ); // for boardB, we want 16MHz
                                    //  internal osc, 16MHz out. boardA
                                    //  will be the same in all respects
                                    //  but this, as it will bring in and
                                    //  output the clock to keep them
                                    //  voth in phase.
  boardB.setAccKVAL(128);           // We'll tinker with these later, if needed.
  boardB.setDecKVAL(128);
  boardB.setRunKVAL(128);
  boardB.setHoldKVAL(32);           // This controls the holding current; keep it low.
}

The supportFunctions file has a good example of the settings used to configure the AutoDriver boards for this application, as well as a nice example of using the run() and softStop() functions to control the motion of the motor.

Other important items to note: we configure the oscillator on boardB (which, remember, we assigned to position 1) to generate a 16MHz signal on the oscillator out pin, and boardA to use the incoming signal and pass that signal to the next board (although. of course, there is no next board in this system). This will be the case in any chain of Autodriver boards: the highest numbered board should generate the clock, while all lower numbered boards use the input from the previous board and pass a clock signal to the next board. This ensures that all of the boards run at the same clock frequency and are in phase with one another.

Also take note of the SPIPortConnect() functions. You’ll pass the same parameter to both of them, as they both use the same SPI port. The library takes care of all the under-the-hood stuff necessary to make sure the right board gets the right signals when you call a function later on.

Resources and Going Further

You should be well on your way to plenty of projects that use stepper motors. Here are some resources to help you on your way.

Here are some other motor related products and hookup guides for you to check out.


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Proto Pedal Assembly and Theory Guide

$
0
0

Proto Pedal Assembly and Theory Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t535

Introduction

The SparkFun Proto Pedal is a PCB that makes building guitar effect pedals easier.

alt text

The SparkFun Proto Pedal PCB

Lets face it, most guitar pedals start with similar circuitry – you need the input and output jacks, the bypass switch (hopefully with a status LED), and a barrel jack for power input. In some circuits, there may be as much wiring involved in the jacks and switch as there is in the effect itself.

This PCB handles all of the essential jack and switch related wiring. It offers:

  • True bypass and LED switching with a heavy-duty three pole, double throw (3PDT) stomp switch.
  • Prototyping area equivalent to a standard solderless breadboard.
  • Some extra proto area for power regulation or reference voltages.
  • Six positions to help organize potentiometer wiring.

To protect the PCB from the hazards of stage and studio, we’ve also got an optional, matching, pre-drilled die cast enclosure.

alt text

Proto Pedal Chassis and PCB

This guide will show you how to assemble the PCB, then explain the I/O, power, and switching circuits. If you’re new to building guitar pedals, this guide should help you get started. If you’re experienced with electronics, but new to guitar pedals, you might want to check out the prototyping and theory sections, because guitar pedals employ some clever and unique circuit conventions.

Before we even get into discussing the basics of the proto pedal, we need to mention that the barrel jack is wired according to the convention for guitar pedals -- the sleeve of the jack is positive 9V, and the tip is ground. This is the opposite of the wall warts that SparkFun sells!

The upside is that it's compatible with nearly any pedal power supply, such as the Boss PSA Adapter, or the Voodoo Labs Pedal Power supply.

Suggested Reading

Assembly Instructions

Parts

In the Proto Pedal box, you will find the following pieces.

alt text

Proto Pedal Components

Clockwise from the top left, you see:

  • One heavy-duty 9 Volt battery snap.
  • One 3PDT stomp switch.
  • Two TRS jacks.
  • One each 4-40 nut, machine screw and star washer ground lug.
  • One 2.1mm Barrel jack
  • One PCB with SMT work completed

Additionally, we highly recommend the pre-drilled chassis. It’s a standard sized cast aluminum box, which does double duty as an assembly jig, to help get the jacks and switch aligned correctly.

You’ll also need a short piece of stranded hookup wire.

Tools

To assemble the Proto Pedal, we recommend the following tools and materials:

Assembly

The first step of assembly is deciding whether or not you’re using the pre-drilled chassis. There are a couple of assembly steps that are determined by the chassis.

  • First, if you’re building with the chassis, it serves as an assembly jig for some components. The walls of the chassis sit at a slight angle, so when the TRS jacks meet the walls properly, they don’t sit completely flush with the board.
  • Second, when sealed up in the chassis, the onboard surface mount LED is hidden. There’s a position for an optional 5mm PTH LED. You’re welcome to pick your favorite color and select a 1/4W PTH bias resistor for the LED. For this guide, we’re using a 5mm Red LED and a 1K &ohm; resistor.

If you’re not using the chassis, you can mount the jacks flush on the board, and the SMT led will suffice for bench testing.

Jacks and Switch

If you’re building the pedal with the chassis, the first step is to mount the switch and jacks to the box.

alt text

Jacks and switch mounted to box.

The jacks each have a plastic nut and a washer, which should both be threaded on from the outside of the box.

The switch has two nuts, a smooth washer, and a lock washer. Remove one nut and both washers, then set the remaining nut about 0.125" (3mm) from the body of the switch, as shown below.

alt text

Notice the location of the nut, a couple of threads above the body.

Put the lock washer on the switch, then put the switch through the chassis. On the external side of the switch, put on the smooth washer, and finally the other nut.

Tighten the nuts on the jacks and switch so they stay in place but can still rotate in the holes. Having a little bit of play in them helps get the PCB aligned properly.

Slide the printed circuit board onto the legs of the jacks and switch.

alt text

Setting the PCB on jacks.

Taking care to keep the TRS jacks near the top of the oblong holes, tighten the nuts on the jacks and switch with your fingers. Due to the sloped side of the enclosure, the legs of the jacks that are nearer the center of the board will protrude further than those near the edge.

Solder the jacks and switch to the PCB.

alt text

PCB resting on jacks and switch.

Remove the PCB from the chassis, and put on the last few touches.

To remove the PCB from the chassis, undo the nuts on the jacks and switch. Then, press the switch, and the whole assembly will pop free.

alt text

Press the button to pop the board free.

Power Input Jack

The next step is soldering the barrel jack, which goes between the TRS jacks.

alt text

Soldering in the barrel jack.

5mm LED.

If you’re adding a through-hole LED, it goes next to the stomp switch, and the bias resistor goes next to it in the resistor location marked BRT. To make it through the hole in the chassis, the LED needs to stand some distance from the PCB. As with the switch and jacks, you can use the chassis as a template to get it aligned correctly.

The LED is polarized and needs to be installed correctly. The cathode of the LED is marked by both the flat spot on the collar of the LED and the shorter leg, which should face towards the switch.

alt text

LED assembly closeup.

With the LED and resistor soldered in place, trim the legs flush with the bottom of the PCB.

You can also remove the solder blob from SJ1, near the bias resistor, to disable the internal LED.

Chassis Ground Lug

Next, add the ground lug.

You’ll need a short piece of stranded hookup wire. Strip and tin the ends of the wire. Solder one end to the ground pad near the barrel jack and the other end to the star washer.

alt text

Chassis ground pigtail.

The star washer mounts to the chassis via the small hole near the barrel jack.

alt text

Firmly connected chassis ground.

9V Battery Snap

Finally, solder in the 9V battery snap. The PCB has some additional holes to relieve stress on the battery wires – feed the wires up through the holes, then back through the solder pads. Take care to match the wires, red, and black, to the legend on the board.

alt text

Battery snap detail.

The battery snap is optional – if you’re strictly using an external power supply, you might prefer to leave it off so there isn’t a loose connector wandering around in the box.

Prototyping With The Proto Pedal

While you’re developing your circuit, you can place a solderless breadboard over the center of the board.

alt text

Solderless breadboard in place.

When you’re ready to finalize the design, you can transcribe the circuit onto the Proto Pedal PCB. The connections in this area of the PCB duplicate those on the solderless board.

There is one difference between the breadboard and Proto Pedal layout, though. There are two additional side-to-side traces down the center of the proto area.

alt text

Connections to lateral power traces.

These traces aren’t assigned to any specific signal, but can be easily tied to VCC, GND, or VAUX using the pads at the left edge of the board. We’ll discuss VAUX shortly.

Coupling Caps

The input and output to a guitar pedal circuit almost always use coupling capacitors at the input and output. There are footprints for these caps near the lower edge of the PCB.

alt text

Input and output coupling capacitors.

Not every circuit uses the same value, size or composition of capacitor. Therefore, these footprints are designed to accommodate a variety of lead spacing. These locations fit both 2mm and 5mm caps, as shown above.

If you’re using polarized coupling caps, the + leads usually face the circuit input/output pads, as marked on the PCB.

Your Circuit Goes Here

With the coupling caps in place, the input and output to the heart of the circuit are the through-hole pads between the coupling caps, marked IN and OUT.

alt text

Input and output pads.

Adding Knobs

The PCB also has six positions for adding potentiometers.

alt text

Potentiometer footprints.

The intent of these positions is that you can run short wires from the proto area to the lower row of pads, then run longer wires from the top pads to the pots, which are bolted to the chassis. This helps keep the proto area tidy.

alt text

Pot on flying wires.

The concept of leaving the wires a little long is known as a “Service Loop” – the system can be disassembled and the PCB can be accessed without having to take the pots off the front panel or disconnect any wires.

Power Supply Area

There is an extra pad-per-hole proto area between the TRS jacks. This area is intended to allow you to add extra circuitry, such as a voltage regulator or rail splitter. If you’re really ambitious, you could build a charge pump circuit in this area, to generate bipolar power supply rails.

alt text

Power prototyping area.

If you’re deriving a new voltage rail, there is also an uncommitted trace from this area to the proto area, marked VAUX, for “auxillary voltage.”

The three connections at the lower left of this area (VAUX,VCC,GND) run to the similarly named set of pads to the right of the prototyping area.

Prototyping Area

The center of the board is the same as a medium-sized solderless breadboard.

Across the top and bottom of this area are power supply traces that run from side to side. The Trace marked + is tied to VCC, and the trace marked - is tied to ground. Between the power traces are pairs of five-pad vertical groupings, arranged in 30 columns. Typically, a dual-in-line (DIP) IC package is placed so it spans the gap at the center of the board.

alt text

IC in place, spanning center of board.

Each leg of the IC is then electrically continuous with the remaining four holes in the group. A short wire can be used as a jumper to connect pads to the power rails, and passive components like capacitors and resistors can be inserted between rows to make connections.

Extra Lateral Traces

On an ordinary DIP-IC prototyping board, the space down the center of the proto area (between the two sets of pads) is empty. The Proto Pedal has an extra pair of traces running in this area.

alt text

Standard protoboard pattern versus Proto Pedal.

These traces simply run from left to right – you can decide how they’re used in your design. For convenience, VCC, Ground and VAUX can be found on pads near the right end of these traces and can be jumpered to the center traces.

alt text

Connection to center rails.

We’ll show an example that uses these traces in the EQ Pedal project.

Ground Lugs and Test Points

There are a number of extra through hole pads on the PCB. There are several pairs of ground pads, which can be populated with small wire loops so you can clip a multimeter or oscilloscope probe ground to them.

alt text

Ground connection.

There are also test points providing access to the tip and ring of the input and output, adjacent to their respective jacks. The ring of the input jack can be found near the ground connection at the top-right corner of the board – if you need to power the pedal even when the input jack is unplugged, you can run a piece of wire between them. Just don’t forget to remove it before deploying the pedal, or your battery life will suffer!

alt text

Input power switch disabled.

It Reads From Right-To-Left

When seen from the user’s perspective, the Proto Pedal is on the floor near their feet, with the stomp switch facing towards them and the jacks facing away.

In another puzzling but long-standing FX pedal convention, viewed this way, the input jack is on the right and the output is on the left. One plausible explanation for this is that the cable usually comes out of the guitar towards the right, so it doesn’t have to cross back to the left to get plugged in.

This is the opposite of how we typically think about circuits and draw schematics (with signal flowing from left-to-right). It’s just a detail to keep in mind as you translate schematics into actual circuits!

Theory Of Operations

Guitar pedals are their own specialized engineering discipline. A number of design conventions have evolved through the years that are now commmonplace. The Proto Pedal incorporates some of these conventions.

Bypass switching

The chunky footswitch on many pedals is a derivative of an old-fashioned automotive hi-beam switch.

alt text

Three-pole, double-throw switch.

Inside the switch, there are actually three separate switches that actuate together when the button is pressed. This switch is actually designed specifically for guitar pedals.

Through the years, a wide variety of bypass switching circuits have been used, many of which use a two-pole switch. The most usable configuration of a two pole switch uses both sections of the switch to steer the signal around the circuit in a “true bypass” configuration. When bypassed, the Proto Pedal passes signal even if the circuit isn’t powered.

alt text

Typical true bypass switching.

The protopedal uses a variant of true bypass switching. The input of the effect is tied to ground when the effect is bypassed, which keeps some high-gain circuits from misbehaving.

alt text

Proto Pedal bypass switching

Indicator LED

In the discussion of bypass switching, we only used two of the three poles on the switch. The third section is used to switch the LED, showing the status of the pedal.

There are two options for LED indicators. By default, there is a surface mount red LED on the PCB, so you can tell the bypass status on your workbench. If you want to defeat this LED, remove the solder blob on SJ1.

alt text

SJ1 is just above the switch, noted with arrow in the silkscreen.

The second LED option allows for a through-hole 5mm LED near the footswitch, which aligns with the hole in the chassis. There is a through-hole bias resistor next door, marked BRT, so you can configure the brightness of the LED.

AC Coupling

Adding the Offset

Guitar signals generally swing about 0V, with an amplitude of around one volt, peak-to-peak (though this varies quite a bit with different pickups, string materials, and playing styles).

alt text

Fender Telecaster, bridge pickup, loudly strumming open E major.

Pedal circuits are typically powered by a single 9V DC battery, which limits the signal swing to that range. The negative peaks of the signal fall below ground, which is outside the region where the circuits operate.

To aid this situation, an offset is added to the signal. This is called a “DC bias.”

alt text

Same guitar, with 4.5VDC bias added.

As you analyze pedal schematics, you’ll learn to identify where this offset is generated. It’s frequently a pair of equal-value resistors wired as a divider between 9V and ground, sometimes with a cap in parallel with the lower resistor. Let’s look at an actual schematic and identify the offset voltage.

alt text

AMZ Super Buffer
(Schematic courtesy Jack Orman, used with permission)

The offset voltage is produced by the divider formed by R8 and R9. The node where they meet will be one-half of V+ (4.5V if powered by a 9V battery).

In more complex schamatics, the half-rail voltage might be used multiple places in the circuit, and there might be more than one divider.

Coupling Capacitors

The DC bias voltage is required inside the circuit, but it needs to be prevented form reaching the outside world. If the DC bias finds its way to the bypass switch, it will cause pops or thumps when the switch is is actuated. Similarly, the guitar, amplifier, and other pedals are expecting the signal to be centered around 0 V. The bias is removed using capacitors on the effect input and output.

The the Super Buffer schematic above, the input coupling capacitor is C1 and the output coupling capacitor is the parallel combination of C2 and C3.

The Proto Pedal anticipates that circuits will need those caps, providing footprints for them on the edge near the battery.

alt text

The Proto Pedal also has 1 M&ohm; pulldown resistors on the external sides of the coupling caps, similar to the 2.2M &ohm; R5 and R7 in the buffer schematic. Some types of capacitors leak the bias voltage, slowly charging the external sides of the caps. The pull-down resistors keep the external sides of the caps at ground potential, preventing popping when the switch is actuated.

As a side note, if you're experiencing popping when your effect is switched in or out, check that the "external" side of each coupling cap is indeed staying at ground potential.

Wait, There’s No Power Switch?

In the discussion of the stomp switch above, you’ll notice the switch is being used to steer the signal through the effect, and turn the LED on and off. It’s not actually turning the circuit on and off.

If you’re familiar with guitar peals, you understand that the input jack needs to be connected for the pedal to come on. The input jack functions as the power switch!

Let’s take a closer look at how this works, by looking at the components in question.

alt text

From top to bottom: TRS jack, TRS socket and TS (guitar) jack.

Here, from top to bottom, are

  • A tip-ring-sleeve (TRS) ¼" jack.
  • A ¼" TRS socket.
  • A standard guitar cable with a tip-sleeve (TS) ¼" jack.

The difference between the TS and TRS jacks is that the TRS jack has a third conductor (the ring) between the tip and sleeve. Or, seen from the opposite perspective, the TS jack is a TRS jack with the ring and sleeve shorted together.

The input on an effect pedal is actually a tip-ring-sleeve socket, with three conductors. When a TS cable is plugged into it, it bridges the ring to the sleeve. Pedals use that connection as a low-side power switch, connecting the negative terminal of the battery to the pedal ground.

If you’ve used pedals with 9V betteries, you quickly learned that you had to unplug them when you weren’t using them if you didn’t want the batteries to die.

Power Input Selection

The Proto Pedal has two power sources: the barrel jack and the 9 volt battery snap. These connections are arranged so that when the barrel is plugged in, the battery is out of the circuit.

This relies on a somewhat obscure detail in the construction of the barrel jack: it has an extra, spring loaded, contact.

alt text

Barrel jack with nothing plugged in.

When nothing is plugged in, the spring holds the second and third contacts together. When the barrel is plugged in, the jack pushes the contacts apart, disconnecting the battery.

alt text

Barrel jack – plugging in disconnects battery.

In the sophisticated world of pedalboard design, it’s common that the battery is omitted entirely, and the pedals are powered by DC power supplies.

Finally, as we mentioned in the introduction, guitar pedals use a barrel jack polarity that’s backwards from other disciplines. Just in case the wrong DC adapter finds its way into the picture, the power connections are protected using a P-channel MOSFET that will only conduct when forward biased. A reverse-polarity adapter (or fumbling a 9V battery against the snap) won’t cause any damage - it simply won’t work.

Some Notes on “Tone Suck”

Through the years, some guitar pedals have become notorious for introducing unwanted changes in the input signal. Perhaps they make the sound quieter, darker, the low end disappears, or just becomes somewhat indistinct – sometimes even with the pedal bypassed!

Unlike some hard to prove audiophile concepts, “Tone Suck” is a real phenomena, which can be easily explained with a little engineering analysis.

An electric guitar pickup is a high impedance inductive source. If the load on that source is too high, it forms a frequency dependent voltage divider, and the high end disappears. Early in the pedal era, this fact wasn’t fully recognized, and some circuits had unusually low input impedance.

alt text

To prevent undue loading, the load impedance should be ten times the source impedance.

In round numbers, the source impedance of guitar pickups is commonly in the 10K&ohm; to 25K&ohm; range. To work well with both sources, a guitar input should have ten times that impedance, or 250K – even higher, such as 1 M&ohm;, is better. Typical hi-fi and pro-audio inputs are in the 10K&ohm; to 47K&ohm; neighborhood. If a guitar is plugged directly into them, it probably loses some mojo.

There are two solutions to the impedance loading problem. The first is to design circuits with a suitably high input impedance. The second is to add a buffer stage in front of the low Z input. The buffer could be as simple as a JFET or MOSFET configured as a source follower, or even another pedal inserted between the guitar and the low impedance input.

The bypass circuitry in older pedals sometimes cut corners, as well. There have been switching strategies that use a single pole switch to simply select between the input signal or the effect output, so the effect is always loading the pickups, even when bypassed.

alt text

Bad switching with single-pole switch.

With a two pole stomp switch, the switch can steer the signal completely around the effect circuit, removing the load entirely.

Finally, the coupling capacitors in some pedals are simply too small, causing a loss of low end.

The Proto Pedal incorporates a number of features that should prevent these problems.

  • The bypass switch is configured in a true-bypass configuration.
  • The input impedance of the PCB is 1 M&ohm; – high enough to not form an undue load on most guitars.
  • The coupling capacitors on the input and output are user-selectable, so they can be chosen to prevent low-end loss.

Resources and Going Further

This guide is the first of several for the Proto Pdeal. Where you go next depends on your interests and background.

Resources

Going Further


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Proto Pedal Example: Analog Equalizer Project

$
0
0

Proto Pedal Example: Analog Equalizer Project a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t547

Introduction

Having assembled the Proto Pedal in the Proto Pedal Assembly Guide, we’d like to continue by actually building an effect circuit on the board. The circuit we’ll be basing this on is Fred Forssell’s swinging-input equalizer.

alt text

Two-band equalizer pedal.

Required Materials

To build the EQ circuit, we’ll need to following components:

Tools

You’ll also need the usual tools to solder things together.

Additionally, while it’s not required, we were using a Resistor Lead Forming tool to get the resistors bent to precise lengths.

Suggested Reading

The Circuit

The Challenge - to devise an analog circuit that makes a usable guitar pedal and can be built entirely from parts in the SparkFun catalog.

The Result - an analog equalizer based on Fred Forssell’s equalizer white paper. The result is a good sounding and flexible pedal design, featuring bell-shaped bass and treble controls. The low frequency is centered on 100 Hz, and the high frequency is centered on 3.2 kHz. Each band offers about 10 dB cut and boost.

alt text

Frequency Response Graph
(click to enlarge).

The filters are also easily tuned to other frequencies and modified for shelving response.

alt text

Dual Band EQ Schematic
(click to enlarge).

Assembly

Step Zero

To begin, we’ll assume that you’ve completed the basic assembly of the proto pedal board.

alt text

If you’re using the Proto Pedal Chassis, you’ll need to prepare it by drilling holes for two potentiometers, as shown in the Chassis Hookup Guide.

With the prerequisites complete, you can start the sequence below. We’re going to be stepping in fairly large chunks. Each step lists the required components, so you can prepare them before you commence. Once they have been placed, double-check your solder joints, and compare your work to the photos.

Playing Battleship

In the following steps, we’re going to use the grid notation seen on a standard solderless breadboard. From left to right, the columns are numbered 1 to 30, and, from bottom to top, the rows are assigned letters from A through J. Any hole in the center of the board can be referenced by number-letter coordinate, such as 27L or 7G.

alt text

Coordinates and rails.

Additionally, we’ll be using the power and center rails of the proto area. At the top and bottom edge of the board are 9V power (AKA Vcc) on the traces marked + and ground on the traces marked -. One of the center traces is used as a half-rail bias voltage, which we’ll refer to as Vref.

In the following steps, we’ll give the coordinate designation of each component.

Step One: Wire Jumpers

The first step is to use solid core hookup wire, and make some basic connections between sets of pads in the proto area. For clarity, we’re using many different colors of wire, but not using any red wire.

Jumper NumberColorStart CoordinateEnd Coordinate
1BlackIn1A
2Yellow2ALower Vcc
3Blue3E3F
4Green10JUpper Ground
5Yellow11JPot3 Left
6Black12JPot3 Right
7Blue17JPot3 Middle
8White18EPot4 Middle
9Green20JUpper Ground
10Bare11D12D
11Yellow12CVref
12Yellow13ALower Vcc
13Black16FOut
14Bare22G23G
15Bare21D22D
16Yellow23ALower Vcc

Installed, these jumpers look like this.

alt text

Jumper placement (click to enlarge).

The jumpers are soldered to the back of the board and trimmed close to the board. If the tails stick out too far, they will short to the metal enclosure.

alt text

When you’re done, count the number of jumpers – there should be sixteen in total. If you find that you’re short, doublecheck that you’ve got the 0.1 inch wire links as noted in the photo.

Step Two: Resistors

There are eleven resistors in this design. To get started, select the following from your resistor assortment. We include the color markings below. The packaging of the resistor assortment serves as an illustrated guide.

Resistor ValueValue Color CodeStart CoordinateEnd CoordinatePlacement Notes
1M &ohm;brown-black-green-gold1DVref
10K &ohm;brown-black-orange-gold3BLower Ground
10K &ohm;brown-black-orange-gold4G11G0.7" long
10K &ohm;brown-black-orange-gold12H16H0.4" long
100K &ohm;brown-black-yellow-gold10ALower Vcc
100K &ohm;brown-black-yellow-gold10BLower GroundAt angle
47 &ohm;yellow-violet-black-gold13G16G
2.2K &ohm;red-red-red-gold21J24J
2.2K &ohm;red-red-red-gold24HVref
2.2K &ohm;red-red-red-gold26DVref
2.2K &ohm;red-red-red-gold20C26C0.6" long

These resistors get installed as shown below. Take note of a couple placement details: some of the resistors are stretched longer than you might expect, and one of the 100K &ohm; resistors is at an angle.

alt text

Resistor placement (click to enlarge).

Step Three: Capacitors

There are ten capacitors, as follows. The values are printed on the caps, and there is a value decoder on the package. The ceramic caps are the small yellow ones, and the electrolytic caps are small black cylinders.

Capacitor ValueValue MarkingStart CoordinateEnd CoordinateOrientation Notes
100 pf ceramic10112I16I
0.01 uf ceramic10318A20A
0.1 uf ceramic104Input Coupling
0.1 uf ceramic10422B24B
0.1 uf ceramic10424A26A
1 uf electrolytic1uf/50V17G19G`-` to right
1 uf electrolytic1uf/50V22I24I`-` to left
1 uf electrolytic1uf/50V19I21I`-` to left
10 uf electrolytic10uf/25VOutput Coupling`-` to right
10 uf electrolytic10uf/25V3H4H`-` to right

These capacitors are installed as shown below. We’ve noted the polarity orientation of the electrolytic caps above, also – the body of the cap has a white stripe with “-” symbols printed to mark the negative leg.

alt text

Capacitor placement (click to enlarge).

Step Four: Semiconductors

There are two types of semiconductor devices used in this project. The MOSFET is part of the Discrete Semiconductor Kit.

ComponentMarkingStart CoordinateEnd CoordinateOrientation Notes
5LN01SP MOSFETYB3C1CPin1 in column 3
YB facing upwards
rounded edges facing downwards
DIP-8 IC Socket
for LM358
Row 10Row 13Spanning center trough
Notch facing right
DIP-8 IC Socket
for LM358
Row 20Row 23Spanning center trough
Notch facing right

alt text

Semiconduictor placement (click to enlarge).

Step Five: Flying Wires & Pots

This last step involves adding the pots to the board. We’ll make a little subassembly out of them, then solder that to the PCB.

Because it needs to flex a bit, we’re using stranded wire for this step. Cut the following pieces

Length (Inches)Lentgh (Metric)Color
2.5"5cmBlue
2.5"5cmRed
2.5"5cmBlue
5"13cmRed
5"13cmYellow
5"13cmGreen

First, orient the pots so the legs are facing the same direction. If you’re using the enclosure, you can put the pots in the chassis holes to hold them in place while you work.

alt text

Use the shorter pieces of red wire to jump from pin 1 of the first pot to pin 1 of the second pot. Before soldering tie the longer piece of red wire to pin 1 of the first pot. Then, repeat the above, bridging from pin 3 to pin 3 with blue wire.

Next, solder the yellow wire to pin 2 of the first pot, and green wire to pin 2 of the other pot. The pot with the yellow wire is the low frequency control, and the pot with the green wire is the high frequency control.

alt text

At this point, you’ll have four wires trailing from the subassembly. They meet the PCB as shown below, in the pot 3 and 4 areas.

alt text

Last Step: Insert the ICs

With the above steps completed, you can insert the IC’s in the sockets, taking care to align the pin-1 marks. The dimple should be at the top-right corner, and the notch should be facing right. The legs come splayed out a little bit wider than the sockets – they’ll need to be bent in a little bit to fit.

alt text

IC Orientation (click to enlarge).

Now we can move on to testing the pedal!

Testing

Preparation

We’ll start testing with a handful of sanity checks, or the proverbial “smoke test”.

  • Start by connecting power, either a 9V battery, or an external supply.
  • Then connect a TS jack to the input. Recall that the input jack also serves as a hidden power switch, which is required to get the circuit to power up.
  • Quickly and carefully feel the ICs and MOSFET. They should be cool to the touch. If not, power down and doublecheck your work.
    • If they’re getting warm, doublecheck that the ICs are oriented correctly, and that there aren’t any solder bridges between adjacent fillets.
  • Press the stomp switch a couple of times. The LED should toggle on and off with each actuation. The circuit is active when the LED is on, and bypassed when the LED is off.
  • If you’re using a bench supply with a built in ammeter, check that the current draw isn’t excessive. On our bench, the device drew miniscule current when bypassed, and about 7 mA when switched to active.

Knowing the Controls

Since they’re just flying on the ends of the wiring harness, it can be hard to tell which potentiometer is which. The pot with the yellow wire is the low frequency control, and the pot with the green wire is the high frequency control.

Before moving on to the next step, make sure that the pedal is active, the LED is on, and set both pots to the center of their rotation.

Operational Testing

If you’ve got a function generator and oscilloscope, you can quickly test an EQ using a low frequency square wave.

Connect the signal generator to the input, and set it for 100 Hz at 1 Vpeak-to-peak. You can view the output by connecting to the output tip test point, adjacent to the output jack. We’ll be using a two-channel oscilloscope, with the first channel, in yellow, observing the signal generator output and the second channel, in blue, scoping the output of the EQ.

alt text

Bench test apparatus.

With both controls centered, the output will be very close to in input.

We’ll first check the low frequencies. As you rotate the knob, the plateaus of the square wave will bend. Rotating the control colckwise increases the low frequency content, and the plateaus bend outward.

alt text

Low frequencies amplified.

Rotating the control counter-clockwise bends the plateaus inward.

alt text

Low frequencies attenuated.

As you adjust the high frequencies, it becomes apparent just past the rising and falling edges of the square. When the high frequencies are rotated clockwise, the boost causes the edges to ring and overshoot.

alt text

High frequencies amplified.

A cut causes a rounded second edge to appear near the vertical segments.

alt text

high frequencies attenuated.

Failsafe

If you don’t have a signal generator and oscilloscope availabile, there’s no harm in just plugging the pedal in and listening to it. It’s wise to perform the smoke test listed above first, and keep the master volume low until you’re confident that the EQ is well behaved.

Performance

The frequency response is illustrated below, showing the effect of turning the potentiometers from their lowest to highest settings.

alt text

Frequency response graph.

Seal It Up

If your testing yields satisfactory results, you’re done!

alt text

You can put the pots through the enclosure, stick on knobs, and deploy the pedal for use!

In Use

This circuit performs best when the input signal isn’t too hot. It’s OK with a 1 Vpeak-to-peak input, but much above that and it distorts a bit (part of our testing involved a bass guitar with a high-output pickup that could easily produce 4 Vpp!). If you don’t like the distortion, there are several potential fixes, listed below in order of increasing required effort.

  1. Turn down the volume a bit.
  2. Swap out the LM358 op-amps for better ones. We had success with NE5532’s, at the cost of much higher quiescent current consumption.
  3. Increase the power supply voltage. Some pedal supplies offer an 18V output, or you can use two 9V batteries in series.
  4. Dig deeper into the design to add an attenuator on the input, with makeup gain on the output.

Theory

The schematic breaks down into several functional blocks.

We’re going to quickly cover them below. If you want much more detail, you can find it in this white paper.

Input Buffer

alt text

MOSFET input buffer.

The start of our path through the equalizer is a single MOSFET, wired as a source follower. This bumps up the input impedance and prevents a loss of high frequencies when the pedal is switched on.

Because the input impedance is so high (defined by the parallel combination of R11 and the 1M input pull-down on the board, or 500 k&ohm;), the input coupling cap (C2) can be a very small value.

The buffer feeds into the…

Cut/Boost Amplifier

alt text

Cut/boost amplifier.

This amplifier is the heart of the equalizer circuit. It’s configured as a unity gain noninverting amplifier. The gyrator circuits (more below!) are attached to potentiometers that “swing” between the inverting and non-inverting inputs of this op-amp. This EQ curcuit is sometimes called the “swinging input” topology.

Gyrators

alt text

Equal-resistor gyrator.

A gyrator is a virtual inductor, made with a capacitor and an op-amp. By putting a second capacitor in series with the gyrator, a band-stop filter is created.

Since we’re using the decade-value capacitors from the capacitor kit, we’re taking advantage of the series combination of some of the caps to get different values, as implemented with C7-C8 and C5-C6.

These band stop filters are attached to potentiometers that move them between the inverting and non-inverting inputs of the cut/boost amplifier.

When the bandstop filter is on the + input, that band is removed from the input signal, resulting in a cut. When it’s on the - input, it’s removing the frequency from the feedback path. The result of cutting the feedback is a boost at the frequency. When the potentiometers are in the middle, the cut and boost actions balance each other, with no net change.

Buffered Half-Rail

Finally, part of the circuit serves as an ancillary power supply.

alt text

Bias voltage buffer.

The circuit requires three op-amps, but with two dual op-amp chips, we have a spare. That extra amplifier is configured as a voltage follower on a half-rail voltage. It’s used for the DC bias added to the signal and also as the “virtual ground” that the gyrators dump signal into.

Many pedals use pairs of equal value resistors as dividers, to create Vcc/2 reference voltages. By buffering a single divider with an op-amp, we have a half-rail of lower impedance. It costs an op-amp stage (that was otherwise unused) but probably saves a number of resistors.

The half rail is treated as VAUX, applied to one of the lateral traces in the center of the breadboard.

Resources and Going Further

alt text

Resources

  • The basis for this project was Fred Forssell’s Equalizer design.
    • The basis for the design is explored in his EQ whitepaper
    • There is a secondary document that contains detailed information on the gyrator math.
  • The National Semiconductor Audio Radio Handbook contains a similar gyrator EQ circuit. The gyrators are slightly different, and their explanation is much more math-heavy.
  • If you’re really interested in EQ circuits, Douglas Self’s Small Signal Audio Design is a great reference.

Going Further

Modifications

The filters in the circuit are highly configurable. By adjusting the component values, the center frequencies can be moved, bandwidths adjusted, and the maximum amount cut and boost altered. The gyrator paper mentioned above covers the basics.

For bass guitar, simply doubling the values of the gyrator capacitors (C4, C5, C6, C7, C8 and C9) will drop the bands by an octave.

If you’d like to simulate different component values, there is an LT SPICE simulation in the Github repository.

Try other capacitor chemistries, too. Again, the design challenge was to design something using only parts in stock at SparkFun. If you’ve got a stash of fancier caps, this is a great circuit to try them in. Polyester film (Mylar) caps work nicely in audio circuits, and silver-mica caps are also highly regarded.

As mentioned in the testing section, the LM358 op-amps have been surpassed by newer ones. They share a footprint with many other dual op-amps.

Finallly, if you’re really ambitious, and can add more frequency bands by duplicating the potentiometer-gyrator stages. The heart of this circuit is the basis for a multi-band graphic equalizer.


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Proto Pedal Example: Programmable Digital Pedal

$
0
0

Proto Pedal Example: Programmable Digital Pedal a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t554

Introduction

Having assembled the Proto Pedal in the Proto Pedal Assembly Guide, we’d like to continue by actually building an effect circuit on the board. This time around, we’ll be putting a Teensy 3.2 and Audio Adapter in the pedal. The Teensy Audio library contains a bunch of building blocks that you can use to create a custom digital signal processing pedal. Rather than a single effect, you can reprogram the Teensy to create new sound effects.

alt text

Reprogrammable digital pedal.

Suggested Reading

Background

The Teensy 3.2 is a small board built upon a powerful microcontroller, the Freescale Kinetis K20. It can be overclocked to 96 MHz, and features the Cortex M4 instruction set, which lends itself to signal processing tasks.

alt text

Teensy 3.2.

The Teensy is Arduino compatible, and programmable via a USB connection. If you’ve used any Arduino-based board, you’re already partway there.

To help take advantage of the signal processing instruction set, the Audio Board adds a 16-bit stereo audio ADC and DAC.

alt text

Teensy Audio Board.

Best of all, you don’t need to be a signal processing guru to get started with the audio board. Instead, there’s a web based editor that lets you start building the signal processing in a drag-and-drop, patchable GUI. To get started, you assemble the desired processing blocks in the GUI, then cut and paste a snippet of code into an Arduino sketch.

alt text

Sample DSP patch.

We’re going to assume that the reader is familiar with Teensy and the Audio framework. If you need some additional background, there is a guide to getting started with Teensy. PJRC have also prepared a detailed tutorial on the Teensy Audio environment.

In Pedal Form

What were going to do in this project is pair Teensy Audio with the Proto Pedal, resulting a reprogrammable digital guitar pedal.

alt text

Prototype Teensy-based pedal.

Before we begin

This is a complicated circuit! It involves a number of different types of wiring – analog, digital, and power circuits are all included. If you’re new to building guitar pedals, this might not be the best starting point.

Second, the noise floor performance of the circuit leaves something to be desired. There’s a fair amount of digital crust that the authors have been struggling to remove. If you’re a master of noise reduction in mixed-signal systems, we’d love for you to take a closer look! If you find things we have missed in our haste, please inform us using the comments link in the menu to the right, and we can update this guide.

Finally, if you like the idea of this project, but want ready-made hardware, you might see if you can track down the old Line 6 ToneCore development kit.

The Circuit

alt text

Teensy-Pedal Schematic (click to enlarge).

The most important component is in the middle of the schematic: the Teensy and audio adapter. We’re using a simplified symbol to represent them, which only shows the connections we’re using.

Theory Of Operations

We’re going to quickly describe what each section of the circuit does.

Input Buffer

The first portion of the circuit is the input buffer.

It consists of one stage of an LM358 operational amplifier, configured as a voltage follower. It’s input is biased to 4.5 VDC with the pair of 1M &ohm; resistors, and the input signal is coupled to them via the 10 uf cap. The output of the buffer matches the input signal – the buffer increases the input impedance, but doesn’t amplify or attenuate the signal.

It provides a reasonably high impedance of 500K &ohm;, defined by the parallel 1M resistors. 1M &ohm; is the highest value resistor in the SparkFun Resistor Kit – if you’ve got higher value resistors (such as 2.2 M &ohm;), they should provide even better performance.

alt text

Input buffer circuit.

The output of the buffer amplifier feeds the divider of R3 and R4, which attenuates the signal by 10K/(10K + 22K), or 10/32, roughly one-third the input value.

Since this amp stage is powered directly from the 9 VDC supply, it has roughly 9 Vpeak-to-peak overall headroom. Dividing the output by 1/3 constrains it to about 3 Vpp, which more closely matches the input headroom of the Teensy line input that it feeds.

Output Amplifier

The output of the Teensy also has about 3 Vpp headroom, which we amplify back to the 9 Vpp range using an amplifier with a gain of 3.

alt text

Output amplifier circuit.

The gain of this noninverting stage is determined by the equation 1 + (Rfeedback/Rshunt), or 32/10, the reciprocal of the attenuation of the input amplifier. This pair of circuits achieve what’s known as unity gain, the combined result being a multiply by one. What goes in comes back out the same.

Voltage Regulator

The Proto Pedal operates in a world of 9 V batteries and wall adapters, while the Teensy can operate from a miximum of 6 VDC. To help bridge the gap, we’re using a simple LM7805 linear voltage regulator.

alt text

Voltage regulator.

It turns the 9 V into 5 V. The Teensy draws about 60 mA, and the regulator is dropping the voltage by 4 V, so this regulator has to dissipate about ¼ Watt as heat. It gets a little warmer than room temperature, but doesn’t get appreciably hot.

The Teensy has further onboard regulators, dropping the 5 V down to 3.3 V.

Analog controls

Finally, there are five potentiometers, wired as voltage dividers between Teensy 3.3V and AGND.

alt text

Parametric controls.

The wipers of these pots are connected to Teensy ADC inputs A1, A2, A3, A6, and A7. These controls can be assigned to effect parameters in firmware, and are not hardwired to specific parameters.

Materials

To build this pedal, you’ll need the folliwing materials, in addition to the Pedal PCB and chassis.

Tools

You’ll also need the usual tools to solder things together.

Additionally, while it’s not required, we were using a Resistor Lead Forming tool to get the resistors bent to precise lengths.

Assembly Part 1 (power and analog section)

The Jumping Off Point

To begin, we’ll assume that you’ve completed the basic assembly of the proto pedal board.

alt text

Proto Pedal PCB assembly.

One detail worth noting is that you can likely omit the 9V battery snap. While it’s possible to power this pedal from a 9V battery, the Teensy is thirsty for current, and you can expect 6 to 10 hours battery life. An external power supply is highly recommended!

If you’re using the Proto Pedal Chassis, you’ll need to prepare it by drilling holes for five potentiometers, and holes for programming the Teensy. This is the chassis shown in the Chassis hookup guide.

With the prerequisites complete, you can start the sequence below. We’ll build the circuit in four major stages: the voltage regulator, the analog section, the Teensy, and the panel controls. We’re going to be stepping fairly quickly. Each step lists the required components, so you can prepare them before you commence. Once they have been placed, double-check your solder joints, and compare your work to the photos. Each of the four stages ends with a short test, to test out the results of that stage.

Grid Notation

In the following steps, we’re going to use the grid notation seen on a standard solderless breadboard. From left to right, the columns are numbered 1 to 30, and from bottom to top, the rows are assigned letters from A through J. Any hole in the center of the board can be referenced by number-letter coordinate, such as 27L or 7G.

alt text

Grid coordinates and power rails.

We’ll also be using both of the center rails of the proto area. The upper one will be tied to VAUX, the output of the 5V voltage regulator, and the lower one will be tied to ground.

Power Section

Teeny expects an input voltage in the 3.6 to 6.0 VDC range. We’ll create a new supply rail for that voltage, using the power section between the input and output jacks, which we’ll route to the VAUX trace at the center of the board.

The area near the top of the board has a 7 x 7 grid of pad-per-hole prototying area, plus rails for VCC and ground across the bottom.

We’ll start with a LM7805 voltage regulator, and two 10 uf capacitors.

alt text

LM7805 connections.

To fit the voltage regulator into this area, we’ll bend the legs as follows.

  • The output, leg 3, is bent straight down along the body of the regulator.
  • The input, leg 1, extends one grid space beyond the body before being bent down.
  • The ground, leg 2, is one grid space longer than leg 1.

This contortion is illustrated in the photo below.

alt text

Voltage regulator assembly.
Note the staggered legs of the regulator.

There are also two 10 uf capacitors in this area.

Capacitor ValueValue MarkingStart CoordinateEnd CoordinateOrientation Notes
10 uf electrolytic10uf/25VGround rail
atfar left
VCC rail
at far left
`-` to ground rail
10 uf electrolytic10uf/25Vground rail at far rightVAUX pad
at far right
`-` to ground rail
+ lead extends from VAUX
to regulator output terminal.

The cap on the VAUX rail has a special trick: its positive leg ls run underneath the board, to the output of the voltage regulator, before being soldered in place at both the VAUX pad and the regulator pin. After soldering, trim the excess leads of both the cap and regulator.

alt text

Using capacitor leg to bridge from VAUX to regulator pin.

Incremental Test

With the regulator and caps in place, we can test the voltage regulator.

Apply 9V power to the board, connect a TS jack to the input, and measure the VAUX pin. It should be in the range of 4.9 to 5.1 VDC.

Before moving on to the next step, be sure to remove power from the unit.


Analog Section

With the regulator tested, we can move on to the analog portion of the circuit. We’ll start by placing a bunch of jumpers, then add resistors and caps, finally the IC.

Jumpers

The analog section of the circuit has nineteen jumpers. We used multicolored solid-core 22 gauge wire. For clarity in the photos, we’re not using any red wire.

Jumper NumberColorStart CoordinateEnd Coordinate
1Black3JPot1 Left
2Blue4JPot1 Right
3Yellow7JPot2 Middle
4Blue8JPot3 Middle
5White11JPot4 Middle
6Black12JPot5 Middle
7Green13JPot1 Middle
8Yellow23JVCC
9White26AGround
10BlueInput26I
11Green21AOut
12Black21D23D
13Yellow28AGround
14Blue30AVcc
15Bare2FVAUX
16Bare2EGround
17Bare24J25J
18BareVAUXTop Center Rail
19BareGroundBottom Center Rail

With the jumpers in place the board will look like this

alt text

Wire jumper placement
(Click to enlarge).

R’s & Cs

Next we’ll install the passive analog components, the resistors and capacitors.

There are eight resistors. Most are folded to 0.3" long, with the legs bent right at the ends of the body. One 10K and one 100K are 0.5" long, as noted in the placement column below.

Resistor ValueValue Color CodeStart CoordinateEnd CoordinatePlacement Notes
1M &ohm;brown-black-green-gold26JUpper Ground
10K &ohm;brown-black-orange-gold27JUpper Ground
22K &ohm;red-red-orange-gold24H27H
1M &ohm;brown-black-green-gold23G26G
22K &ohm;red-red-orange-gold21C24C
10K &ohm;brown-black-orange-gold24D29D0.5" long
100K &ohm;brown-black-yellow-gold25C28C
100K &ohm;brown-black-yellow-gold25B30B0.5" long

alt text

Resistor placement
(Click to enlarge).

There are three 10 uf electrolytic capacitors. Take note of the polatiry - the negative leg is marked on the body of the cap with a stripe, which is also visible in the photo below.

Capacitor ValueValue MarkingStart CoordinateEnd CoordinateOrientation Notes
10 uf electrolytic10uf/25VInput Coupling`-` to left
10 uf electrolytic10uf/25V29ECenter ground`-` to top
10 uf electrolytic10uf/25VOutput Coupling`-` to right

alt text

Capacitor placement
(Click to enlarge).

Op-amp

The last component in the analog section is the operational amplifier.

ComponentMarkingStart CoordinateEnd CoordinateOrientation Notes
DIP-8 IC Socket
for LM358
Row 23Row 26Spanning center trough
Notch facing left

alt text

IC socket placement
(Click to enlarge).

After soldering the socket, insert the LM358, again with the notch facing to the left.

Incremental Test

To test this stage, we’ll install one extra, temporary wire, from 25A to 27I, the red wire shown below. This ties the input amplifier to the output amplifier.

alt text

Test jumper from 25A to 27I.

Apply power to the circuit, then connect the input and output. We used a signal generator and an oscilloscope. If you don’t have them handy, you can use a guitar and amplifier – just be careful to keep the volume low until you’re certain that the circuit is well behaved.

While applying input signal, press the stomp switch. Aside from the slight click when the switch engages, the output signal should be nearly the same with the pedal active or bypassed.

Again, disconnect power before moving on, and also remove the temporary jumper.

Assembly Part 2 (Teensy and controls)

Teensy Section

The next portion of the circuit that we’ll be building is the Teensy and Audio Adapter. We’ll start by turning them into a subassembly, then putting it on the pedal PCB.

Optional Modification

This step is optional, but has been found to help lower the noise floor of the Audio Adapter. Once the subassembly goes together, it is very hard to get access to the capacitor we're going to be modifying here.

As wen mentioned earlier, the Teensy Audio adapter has a rather high noise floor. On the PJRC forums, user omjanger has posted a modification that helps reduce the noise slightly. It involves putting a 1 M&ohm; resistor in parallel with the 0.15 uf capacitor on the VAG pin of the codec chip. This modification is shown below.

alt text

Piggyback resistor.

If you chose to undertake this modificaton, be warned: it takes an extremely careful touch to get the resistor in place without removing the capacitor entirely, or bridging adjacent components with solder blobs.

Prepare the Stack

Since we’re going to be powereing the Teensy from the regulator on the pedal circuit board, we want to cut the jumper that bridges the USB bus voltage to the Teensy power input. We used a hobby knife to cut the trace, and a continuity checker to make sure the cut was complete.

alt text

Cut VUSB jumper.

Next we want to stack the teensy and audio adapter with header pins.

The first step is to break off two 14-pin sections of snappable header, and solder them to the Teensy, with the longer portion of the pins pointing downwards. Below, we’re using a small breadboard to hold the pins straight while we solder.

alt text

Aligning the Teensy pins.

Then we remove the Teensy from the breadboard, and put the pins through the audio adapter. Double check the alignment before proceeding: the USB port on the Teensy and the headphone plug on the audio board both face the same direction.

alt text

Teensy and Audio board – note orientation: USB and headphone jack face same direction..

The audio board gets soldered to the pins from below.

alt text

Solder the pins from beneath.

While we’re looking at the bottom of the board, let’s solder two more wires to the audio adapter. Here, you can see white and blue wires connected to the left line input and the left line output. Each wire is about 4 inches long – we’ll trim them to length later.

Wire ColorConnectionLength
WhiteLine out L4 inches
BlueLine In L4 inches

They’re inserted from the bottom of the board…

alt text

Attach wires to the left line input and output.

…and soldered to the top of the board.

alt text

Line in and out pigtails.

Now we put the stack on the proto pedal circuit board.

alt text

Teensy on main PCB, with stir stick shim.

The stack is placed with the USB and headphone jacks pointing to the left, where the USB plug will align with the hole in the left side of the chassis. It spans from column 2 to column 15, and the pins were placed in rows C and G. We don’t want to bottom of the audio adapter to accidentally touch anything on the pedal PCB, as we’re using a coffee stirrer as a shim while we solder.

You can see the clearance between the stack and the pedal PCB below.

alt text

Note the space between Teensy Audio board and main PCB..

The last piece of this step is to run the wires from the line connections back to the analog section.

Wire ColorSourceDestination
WhiteLine Out L25A
BlueLine In L26I

Before soldering, we ran the wires to their destination, and trimmed some excess, helping avoid clutter.

alt text

Line in & out pigtails connected to analog circuit.

Incremental Test

Testing this step is similar to the previous incremental test. Connect the input, output and power. Then load the throughput sketch. This sketch allows the Teensy to pass audio from line input to line output.

Toggle the stomp switch a few times. The output of the pedal should be the same amplitude when it is engaged or bypassed. You will likely be able to hear the raised noise floor of the Teensy when the pedal is engaged.

Controls section

The final quadrant of the circuit is the panel coltrols. Like the previous step, we’ll build a subassembly, then integrate it with the main circuit board.

To start, mount the five 10K potentiometers in the chassis, and tighten them in place. Notice that we’ve numbered each pot (1 through 5), and labeled it with it’s corresponding Teensy ADC input (A12, A7, A6, A3 and A2). The numbers run right-to-left beacuse we’re looking from the inside of the box.

alt text

Pots in chassis.

The pots are wired as parallel voltage dividers between the Teensy AGND and 3.3V signals. Since they’re in parallel, they’ll be wired as busses.

alt text

Potentiometer terminals.

As indicated in the photo above, the left legs of the pots are daisy-chained with black wire, and the right legs are daisy-chained with blue wire. The middle terminal of each pot will get it’s own color coded wire in a later step.

For the bus that runs from pot to pot, we used short pieces of solid core wire. Each leg in the daisy-chain has a wire to each of it’s neighbors. We stripped the ends of each wire, then pushed them through the holes in the pot terminal.

alt text

Putting bus wires in place.

We then flow solder onto that nexus, making sure to avoid cold solder joints.

alt text

Soldering bus wires.

The black and blue daisy chains are run between pots, and then we add pigtails to run to the main PCB. Because these wires need to be flexible, we selected about 6 inches of stranded hookup wire, and soldered them to the end of the respective daisy chains.

alt text

Bus wires and pigtails.

With the buses complete, we need to add five more wires to the potentiometer wipers. Again, we’re using stranded hookup wire, each about 6 inches long.

The following table and photos illustrate the connections.

Pot connectionWire ColorBoard Destination
Clockwise BusBluePot1 Right
Counterclockwise BusBlackPot1 Left
Wiper 1GreenPot1 Middle
Wiper 2YellowPot2 Middle
Wiper 3BluePot3 Middle
Wiper 4WhitePot4 Middle
Wiper 5BlackPot5 Middle

When these wires in place, you should have wires as seen below. Note that we’ve got two blue and two black wires – the wiper signals (to the left of the photo), and the daisy chained buses (to the right of the photo). Be careful to keep them straight when you connect them to the PCB!

alt text

adding color-coded wires for the wipers.

The black and blue bus wires connect to the left and right pads of the Pot1 area, respectively. The blue wiper wire connects to the center of pot 3, and the black wiper wire connects to the center of pot 5.

alt text

Pot connections to main board.

With the controls soldered to the PCB, you should have an overall assembly as depicted below.

Notice that we’ve also bolted the ground lug from the PCB to the chassis.

alt text

Pedal with the hood up.

Final Incremental Test

The throughput test sketch that we loaded in the last step also serves as an integration test for the panel controls. If you open the serial port, you notice that it periodically prints a set of five values, showing the potentiometer readings. As you turn each pot, the values should change from 0 when set counterclockwise, to 1023 at when fully clockwise.

alt text

Notice the five analog read values.

Close It Up

When the tests are passing, we’re done soldering, and we can close the pedal up.

To put the PCB into the chassis, angle it so the TRS jacks go through the oblong holes, then pivot the board so the switch goes through its hole. As it closes, make sure that the control wires aren’t hanging up on anything, and if you’ve got a PTH LED, take care to get it through the chassis hole, too.

alt text

Put PCB in chassis.

Then put the external hardware on to hold the board in place. The switch gets a hex nut, and each TRS jack has a plastic washer and hex nut.

alt text

Secure it with hardware.

Before you tighten all of the hardware, doublecheck the aliignment of the barrel jack. It should be centered in the panel hole, as shown below. This alignment reduces the chances of the barrel jack shorting to the chassis, or the bottom of the PCB coming into contact with the lid of the enclosure.

alt text

Verify barrel jack alignment.

Finally, put the back on the box, and put knobs on the pots.

alt text

A complete pedal.

Add the Software

It’s up to your imagination to come up with the effect you want, but here’s a few you can load right in and try.

They can be found in the teensy sketches directory in the Proto Pedal github repository.

Throughput

We’ve already used the throughput sketch to test the audio hardware. It simply passes audio straight from the input to the output. Boring, but you can use it to make sure your system is working!

You can also use this as a template when creating new sketches.

AutoRoller

The AutoRoller has an input filter for tone control, an output low-pass filter for effect, and a modulation source consisting of a sine wave generator with rate dependent on input peak values. The louder you play, the faster the filter sweeps. It creates a dynamically controlled warble, similar to a rotary tone cabinet.

alt text

AutoRoller block diagram.

Within the AutoRoller patch, the input hits a tone control, which allows the relative tonal balance to be adjusted. From there, it feeds a peak detector module. The output of the peak detector modulates the frequency of a sine wave, which is used to modulate the lowpass filter. The ‘tone’ knob is used to set the nominal characteristics of the output filter, combining cutoff frequency and resonance on a single knob.

alt text

The completed AutoRoller. The knobs are set to a good starting place for use with an electric guitar

More information about the AutoRoller can be found in the readme and other files in the repository.

Tape Echo Emulation

Finally, we’ve got an example of a tape echo emulation.

alt text

It consists of a delay line with highpass and lowpass filters in the feedback loop. It can be used as a subtly colored digital delay, or tweaked into an interactive, regenerative sound effect generator.

You can find the sketch and related files here.

Please note: the README.md file for the echo contains some additional information about compiling the effect. In order to have the maximum amount of RAM available for the delay line, be sure to select a non-optimized build configuration in the tools->cpu speed menu.

Resources and Going Further

Resources

Going Further

This guide is really just the starting point - what you ultimately create depends on your imagination, and how clever you are at using the Teensy Audio library!


learn.sparkfun.com |CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Viewing all 1123 articles
Browse latest View live