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

Shapeoko Assembly Guide

$
0
0

Shapeoko Assembly Guide a learn.sparkfun.com tutorial

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

Introduction

SparkFun’s Deluxe Shapeoko kit is a Carbide3D Shapoko 3 in fancy SparkFun red with our open source 3 axis mill driver, the Stepoko.

alt text

The full kit. In this picture, the Shapeoko parts have been assembled as per the Shapeoko guide, and the SparkFun kit parts are shown beside it.

Guide Content

This guide directs you to the Shapeoko assembly instructions, then goes through the final steps to add the electronics to the mill.

Required Materials

Suggested Reading

Stepoko guide - This guide talks about how the Stepoko control electronics works. Important information is also linked below.

Assembly

  1. Follow the Shapeoko assembly instructions until you get to the part where controller is added. There are a few differences, for instance the motors in this kit have equal length wires, but nothing too significant.

    Set Aside Some Time It may take about four hours to complete the initial assembly. Once you’ve got it, continue on.
  2. Install the Shapeoko into the enclosure. There are 10 4-40 screws for this purpose, but you’ll only need 8. Use a number 1 phillips screwdriver.

    alt text

    To get the Stepoko into the enclosure, put the ‘port end’ in first.

    alt text

    Installing the 4-40 screws
  3. Install the enclosure to the rail with the terminal connections at the top. Use the extra M6x12mm bolts provided with the Shapeoko.

    alt text

    Mounting the controller
  4. Connect the X and Z axes to the Stepoko. For more information, check the Stepoko guide’s Hardware: Connecting the Motors section.

    alt text

    The X and Z axis are connected.
  5. Connect the Y axis. But wait! It has two motors that are wired in parallel.

    If two stepper motors are connected in parallel, they may not spin in the same direction because the internal polarities may not be the same. The solution to this problem is to transpose the colors of one pair of coil wires. This polarity/spin direction problem is compounded by the fact that the motors are mirrored on the mill and actually need to spin different directions.

    Watch the video below go get a basic idea, then work through these steps.

    • Connect short leads to the Y axis terminals.
    • Identify the coils.
    • Group one coil from each motor together by color, except with reversed polarities.
    • Twist the ends to test.
    • Try and move the mill in the Y axis. If it moves smoothly, solder the wires and apply heatshrink/electrical tape, or use wire nuts.
    • If the axis moved roughly, unlike the X and Z axes, filp one of the pairs of coils so that it has the same colors combined, but leave the other reversed. This is because the motor’s coils are not always wired the same internally.

    Take a quick look at this video to see, and hear, how the Y axis when wired incorrectly, and correctly.
  6. Set the motor drive currents. Make sure the trimpots are in the center for 1A service until you are more experienced. Or, read up on how the current setting works in the Stepoko Guide’s Hardware: Setting the current section.

    alt text

    The trimpots are centered for 1 A drive in this photograph.
  7. Mount the switch to a free hole on the gantry end plate and solder on leads.

    alt text

    Here the switch has been mounted and the switch wires are being measured. They go into the two terminals labled E-Stop.

    alt text

    Soldering on the leads.

    alt text

    All of the wires are added for this mill setup.
  8. Screw in the lid to the enclosure using a number 1 or 2 phillips.

    alt text
  9. Collect your wires and bind with twist ties or zip ties.

    alt text

    The Y axis wires have been twist tied together here. The X and Z axes are gently pulled out to see how long they are.

    alt text

    With the X axis moved ofer to one end, I can see that my bound wires have enough slack so that they won’t be pulled on when the carriage moves.
  10. Connect the power supply, power cord, and USB cord between your computer and the Stepoko

  11. Open up the Universal Gcode Sender, open the Stepoko’s serial port, and select the machine control tab. Set the switch to ‘ON’ and try to move the machine by computer control. If the axis move in the wrong directions to your liking (but of course, up should be positive Z), switch the direction bit field accordingly. Use the Stepoko guide’s Software: Machine Control section for more information about grbl, or check out grbl’s Github wiki for more information on changing settings.

  12. Measure know movements and calibrate each axis. See the Stepoko guide’s Firmware: Configuring grbl and Calibrating section for more info.

You’re done!

Resources and Going Further

Here’s some links and projects you may find useful.

Or, head back to the The Stepoko and Shapeoko Landing page to see what accessories and tools are available.

Now that you have built your Shapeoko Mill, check out these other SparkFun tutorials to learn how to use the SparkFun Stepoko Control board.

Once you’re familiar with the Stepoko, create your first project by following along with the Shapeoko SparkFun Coaster.

New!

Shapeoko Coaster Project

November 20, 2015

A step-by-step guide to cutting and engraving a coaster with the Shapeoko.

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


Shapeoko Coaster Project

$
0
0

Shapeoko Coaster Project a learn.sparkfun.com tutorial

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

Introduction

The purpose of this project is to show that milling is a complex, multi-layered and multi-step process. It’s not like printing on paper; there are many small steps involved to get from an idea to an object. But, one must begin somewhere.

This guide is intended to allow someone who’s never milled before make something useful with a mill.

alt text

The finished coaster.

Tools needed

  • Shapeoko mill (prototype shown in pictures), Stepoko controller, and a trim router
  • ¼ inch dual fluted wood router bit (from hardware store)
  • ¼ inch, 45 degree engraver bit (from hardware store)
  • Drill for drilling and driving screws
  • A drill bit to match screw shaft size
  • The router chuck tool and adjustable wrench
  • A few screws to hold down the material
  • Hearing protection
  • A computer that can get sawdust on it

Think about cleanup before you begin too. I operated outside but still had to vacuum down the mill and computer afterwards.

Materials

  • Stain – I chose Watco Danish Oil
  • A Sakura brush pen
  • A length of 1x6 Common Board
  • Sandpaper
  • Paper towels

Software

Suggested Reading

If you have not already, we recommend reading the Shapeoko Assembly Guide and the Stepoko Hookup Guide for a better understanding of how this project came together.

New!

Shapeoko Assembly Guide

November 20, 2015

A guide for attaching the Stepoko Add-on kit to a Shapeoko Mechanical kit.

Processing the Toolchain

alt text

The first part of the process involves doing the design and CAM work. For this example, Inkscape is used to generate .svg files that are then passed to Makercam.com to do the tool path generation. This section covers what that process looks like.


alt text

I start by opening inkscape and figuring out how to make the grid meaningful to me. I set it to ¼ inch and aim for a 3 ½ inch coaster.


alt text

Start drawing some shapes!


alt text

I realized my grid wasn’t fine enough for the task, so I increased it. I put lines in for each place I want to engrave or cut out. I think I want two rings around the outside with a graphic in the middle, and a few terraced cuts around the parimeter

Now, it’s time to bring in the graphic. Inkscape works great for dealing with vector shapes that don’t have to be any particular size. On the flip side, it’s not so good for working in strict coordinates, like for machining parts.


alt text

The SparkFun flame is the obvious demo material! After importing it, it needs to be cleaned up.


alt text

Select it, remove the fill, and set the stroke paint to solid. After this, a mini flame can be seen in the middle for no particular reason. Delete what you don’t need.


alt text

I thought the flame might look good framed by the two edge circles, so I scaled and slid it around until I was satisfied.


alt text

To remove the extra part, select “edit paths by node”, and use the tool bar to clean up the desired points.


alt text

At the last moment, I decided I wanted to put another level to the perimeter. I had already made the interior graphics, so I slid up and to the right so I could put another circle around them.


alt text


A sketch of the profile helps me decide what cuts need to be done, and in what order

I was developing this thought as I went through the inkscape drawing and came up with the above. Each number is the order of the operations. For the first job, the 1x6 will be planed down to 3/8th inch, and two of the perimeter cuts made. The coaster won’t be free until step 5 which is what I want. The next job will be to change tools and run step 4 to put the graphics on the coaster. Lastly, the perimeter cuts will be finished releasing the part from the stock.


Now that I have an idea of what my workflow will look like, MakerCam is loaded with the .svg file from inkscape, and it appears at the origin because that’s where I drew it. If it’s not, it can be moved.


alt text

I’ve selected one ring to show that each line is an independent shape. If different operations happen for different shapes but they’re connected, the CAM software can’t tell them apart.


alt text

The first operation will be to plane the ¾ inch stock down to the thickness of the coaster, 3/8 inch. Select the major circle, then select ‘CAM’ then ‘Pocket operation’. MakerCam presents me with a set of parameters that I need to change. I know I’ll be zeroing the machine to the surface of the material, so the stock surface will be 0. I’ll cut down to .375 inches, or -0.375 (because down is negative on the Z axis). Feed rates and depth-per-cut can be set here too. Don’t forget to specify your tool diameter!


alt text

Next up is to make a profile operation. This will generate a path around the major circle to hog out the extra material and give the tool some room to work on the other parimeter operations. Really, this just makes the pocket operation a little bigger.


alt text

Now, it’s time to make the two profile operations that make the detail on the perimeter. First, a shallow cut on the inner circle, then a deeper cut farther out.


alt text

This is the profile for the outer circle.


alt text

To make the toolpath for the engraving, select all shapes to engrave (use ctrl-click to multi-select) and choose ‘CAM’ then ‘Follow path operation’. Where a profile operation is used, the path goes outside or inside the line by half a bit width, while ‘Follow path’ goes directly on the line. I will be using a fine pointed engraver for this step so it’s Ok, I can assume the width is small. I’ve set up these parameters to make one pass at almost the complete depth, then finish off with another pass a little deeper to make sure everything is cleaned out.


alt text

The final operation is to finish the parameter cut and free the piece from the stock. When the part becomes free, it may bounce around and get chewed up by the tool but I’ll risk it. Using ‘tabs’ is the industry standard way of cutting out most of the part while leaving little bits of material to retain it. Tabs are available in MakerCam, but I haven’t used them.


alt text

Now, click ‘CAM’ then ‘Calculate All’ to have the software ponder the operations you have specified and generate the associated tool paths.


alt text

After calculating, green paths with arrows appear that show the movement from the top down. Everything looks ok, though our view is obscured by the lack of a third dimension.


alt text

Here’s where the Gcode comes into play. Select ‘CAM’ then ‘Export Gcode’ to bring up this window. It allows you select which operations go together, then generate and save a text file. Don’t forget to add “.nc” to the end of the file name for MakerCam! The first job I select will be steps 1, 2, and 3 of my profile diagram, which will include the first pocket, the major profile, and the two detail profiles.


alt text

Next up is to export the engraving step on its own. This is because I need to manually change tools, and I can’t do that in the middle of a Gcode job.


alt text

The last thing to export is the final perimeter cut.


Now, I have three .nc gcode files! As a sanity check I open them in Universal Gcode Sender, and click the ‘visualize’ button to view the paths in 3D

alt text

The first path shows mostly pocketing with a few parimeter paths, just how I want it. If you look closely, you can see how they will create a stepped edge.


alt text

The engraving step looks good too. It has two closely spaced cuts that resemble the original graphic.


alt text

The final pass to release the part. Notice that when the last cut is made, the part will not be held to the wasteboard anymore and will have be retained with a push-stick for a good cut.


Operating the Mill

Setup

Now that the files look good, it’s time to prepare for the actual work. Gather together all the things you think you’ll need before starting, especially if you’re not working in a shop. This can prevent running for new tools.

alt text

The various hand tools and supplies collected for this project, as mentioned in the Introduction.

alt text

Of course, you’ll need a mill and computer. Shown here is a Carbide 3D Shapeoko mill with SparkFun Stepoko controller

Operation

alt text

Set the material into the mill. Some mills have clamps but for this simple job I drilled holes in the material and screwed it down to the wasteboard.


alt text

I’ve left the carriage at about zero so I know the cut path of the job won’t hit the screw heads. An easy way to get it all straight is to eye-ball off the previous liner cuts that develop in the wasteboard over time.


alt text


alt text

There will be three jobs to run. First, ¼ inch milling, then engraving, then milling again. With the e-stop enabled, the carriage moves freely but doesn’t track motion. We haven’t calibrated to zero yet, so move it up to get to the collet.


alt text

The tool is made pretty tight. If it slips up in the collet during operation, the tool may be dull, too loose, or the feed rate is to high.

Now, it’s time to make a zero reference. Once made, this will be zero for all jobs. If everything goes smoothly (don’t plan on it the first time around), the machine will never have to be re-zeroed. If not, you’ll have to use this reference to locate zero again.


alt text

The tool can be lightly pressed into materials like plastic and wood to dent and give a mark.


alt text

Back on our computer, click ‘Reset Zero’ to tell everybody that the machine is at the new zero. If this doesn’t seem to take, close and reopen the software.


alt text

With the machine at zero, switch off the e-stop (turn on the switch). This locks the stepper motors.


alt text

Use the machine control tab in Gcode Sender to lift the tool by a know amount. I chose 10mm. This is kind of a sanity check to make sure the machine is working and to get it away from the material.

Lesson: Draw a cross-hair across the center of the zero. Later in the process, I dropped a running tool on the point and milled out the indentation and had to guess a bit. Pros use wigglers to set zero.

alt text

Hearing Safety Warning!: High speed cutters are loud! Some people think it's not so bad, but after about a minute of milling they all start backing away. Put on hearing protection before proceeding.

alt text

After the first pass, the first 3 operations are apparent. The mill has been returned to zero.


alt text

To switch tools, use the switch to unlock the motion, lift the Z axis without disturbing the X and Y, and re-enable the motion. Now I have some room to work.


alt text

Oops! It can be seen here that the black plate, which moves with the tool, will crash into the work surface if I try to run the job.

Lesson: Make sure the tool is adjusted in the clamp before starting any work.

alt text

I loosen the router clamp evenly.


alt text

The router is dropped down an inch or so. I had to zero again before running the job.

After running the job, switching the tool back to the mill bit, and running the final perimeter job the part is released. If you watch the video you can see that on the last pass, I hold down the part with a scrap pushstick. Alternately, you can leave tabs in the CAM software so that it doesn’t fly around when on the final cut.


Enjoy a time-lapse video of the three jobs being sent to the mill!


alt text

The coaster, right out of the mill.

Finish Work

Finishing work really brings out the design and is pretty easy to do for any woodworking project.

alt text

Sand the coaster to your heart’s content! I used a medium grit paper in circular motions, and it came out as good as soft wood can.


alt text

Ahh, I’ll take it!


alt text

This Danish oil is applied with a cloth or spounge… or paper towel.


alt text

The idea is to apply profusely, let sit for 10-15 minutes in the shade, then wipe off the extra.


alt text

The coaster is wiped down to remove the excess stain.


alt text

Carefully line the engraving with a brush pen such as this one made by Sakura.

The Final Product

alt text

The finished coaster! I didn’t really like how the lowest edge turned out. If I want to make a rev B, I’ll go in the toolchain and adjust this circle in about 1/16 of an inch.


alt text

And the moment of truth. It coasts my beverage! A success.



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

Stepoko: Powered by grbl Hookup Guide

$
0
0

Stepoko: Powered by grbl Hookup Guide a learn.sparkfun.com tutorial

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

Introduction

The SparkFun Stepoko is an ATmega328p, Arduino compatible, 3-axis control solution. It’s open source, uses open source firmware and works with an open source Java based cross platform G-Code sending application.

alt text

The SparkFun Stepoko, in all its glory.

The simplest installation of it consists of just plugging the stepper motors in, but of course hard work pays off. Handy machine control buttons and locating features can be added at taste to give a mill whichever options are desired.

alt text

The Stepoko implemented on a novelty-sized laser cutter, sitting atop a Shapeoko mill also driven by a Stepoko

Features:

  • 3 stepper connections
  • Full, to 1/8 stepping
  • Comes with heatsinks installed!
  • Options for input and feedback include E-Stop (emergency stop, or general motor drive switch), Reset, Feed Hold, Cycle Start, Homing Location and Probing.
  • Has option for spindle direction and PWM control.
  • Can be powered from 12-30V.
  • Independent axis current limiting adjustments

Required Materials

Suggested Reading

If you still need to assemble your Shapeoko Mill, please consult our Shapekoko Assembly Guide.

New!

Shapeoko Assembly Guide

November 20, 2015

A guide for attaching the Stepoko Add-on kit to a Shapeoko Mechanical kit.
  • Motor tutorial– This tutorial covers all types of motors. If you’re unfamiliar with stepper motors and how they work, check it out.

Hardware: Overview

The Stepoko is a complicated board. First, let’s take a look at the whole thing, then the various parts will be broken out by function and discussed.

alt text

The top side.

Parts of the top side:

  • LEDs
    • X, Y, Z Direction – Denotes polarity of movement
    • X, Y, Z Step – Flashes each time the associated channel steps
    • X, Y, Z Limit – Illuminates when a stop switch is active
    • E-Stop – Illuminates when the stop button is active (shows axis lock has been removed)
    • Probe – Illuminates when probe switch is active
    • Step En – Illuminates to show the controller is ready to step its axes
    • Power – Illuminates when the bulk rail is energized. Shows when back emf is also charging the unpowered rail.
    • TX, RX – Shows communication over the USB.
    • Reverse protection – Illuminates when power has been connected backwards – Remove power
  • Axis connectors
  • Switch connectors
  • Switch active polarity switch
  • Power connectors
  • Uno-type 328p
    • Reset switch
    • USB connection
    • Pin Breakout
  • Axis drivers – DRV8811
    • Step switches
    • Heatsinks
  • Power regulation
  • Fan connection

alt text

The bottom side

Parts of the bottom side:

  • Arduino pin map
  • Arduino pin breakout
  • Heatsink

Hardware: The System and Power Supply

alt text

The top side

Powering the Stepoko

Stepper motors take a lot more current than most hobby circuits. The Stepoko can supply up to 2.0A each per coil! To get that kind of power, an ordinary wall adapter won’t suffice. Apply 12-30 VDC to either the barrel jack or screw terminals, but not both. Use either a power brick or a Benchtop Supply of some kind. Make sure the supply can generate about 3 times the single-coil current for a 3-axis setup. Because of the switching nature of the stepper motors, the maximum current for a single winding is greater than the total current required to run that motor.

Use the following formula:

alt text

For instance, if two channels are used and set to 1A each, a 2A supply is required.

After power is attached, the blue power LED should light illuminate. If it doesn’t, or if the reverse protection LED lights up, remove power and check voltage/polarity of the supply.

Note: When a USB connection is made, the power LED will light up even though there is not enough current to drive the motors.

The Embedded ATmega328p Microcontroller

The Stepoko is actually an Uno compatible ATmega328p! It’s just an Arduino with a grbl shield attached. This is evident by looking near the USB port where the familiar FTDI, Atmel IC, reset button, and even the SPI 2x3 header can be found. In this area, we’ve even broken out all of the pins that are associated with the microcontroller and power supplies. If you peek at the back of the board, there’s a chart in silkscreen that matches the grbl pin functions to the Arduino pin naming convention. It’s open source! You can do what you want to it.

To use the microncontroller, attach a USB cable and let your computer enumerate the device as it would with an Arduino. After that, you could program it with the Arduino IDE. It comes with grbl 0.9 though, so don’t program it unless you absolutely have to. Even if you revert back to grbl, the grbl settings will be lost and you’ll have to program them all in again.

Connecting the control switches

The Stepoko supports

Pin Name
Function
LocationWiring
E-Stop
Disengages the
motor drivers
Breakout pins
Screw terminals
Closed on 'Run' while connected to terminals.
Drive high for 'Stop' on pin headers - remove U6 for use
Reset/Abort
Breakout pins
Internally pulled high. Close to ground for function.
Feed Hold
Pauses the
current job
Breakout pins
Internally pulled high. Close to ground for function.
Cycle Start
/Resume
Restarts the
paused job
Breakout pins
Internally pulled high. Close to ground for function.
ProbeDetect material
Breakout pins
Screw terminals
Normally open, connected to terminals.
Drive high for active on pin headers - remove U6 for use
ResetResets the microcontroller
Breakout pins and 1x2 header by reset switchPulled up by design. Close to ground to reset microcontroller.
X,Y, and Z
Limit
Stops all
motion
Screw terminals
Normally open or closed set by switch and wired across terminal pair.

On the left, the red light indicates that the E-Stop has been pressed (or the switch terminals are open). In this mode, the steppers are not being driven and can be manually moved. On the right, the green light indicates that E-Stop has been deactivated. Power is enabled to the stepper moters and that their rotors are magnetically locked. In this mode, the system has control of the movement.

Hardware: The Stepper Drivers

The stepper drivers consist of three identical circuits, one for each axis. Here, one is shown but the application applies to any of them.

alt text

The top side

Parts of a single axis circuitry:

  • State LEDs
    • Direction – Denotes polarity of movement
    • Step – Flashes each time the associated channel steps
    • Limit – Illuminates when a stop switch is active
  • Stepper Motor Connection
  • Axis driver – DRV8811
  • Microstepping Control Switches
  • Heatsinks – One each on the driver IC and a collective aluminum slug on the backside
  • Current control potentiometer

Operation

At the heart of each axis driver is a DRV8811 IC by Texas Instruments. The microcontroller talks to the 8811 by digital control signals (not serial) that: set the direction, enable the motor, and cause a step. Internally, it has a state machine that matches the coil states necessary to get a stepper motor to perform. Modifying the microstepping switches changes that state machine such that the pattern is correct for the microstepping indicated.

The digital portion of the IC operates from 5V by way of the Stepoko’s on-board regulator. This is not enough to drive the motors though. The IC has a separate VIN supply that connects directly to the power jack / screw terminals. Whatever the voltage (12V - 30V) supplied, that voltage will be the driving voltage on the motor coils.

All this work is graciously provided by the grbl software that comes pre-installed, so unless you are building new software, how the 8811 works is really not too important. If you are, the DRV8811 datasheet explains in great detail.

Hardware: Connecting the Motors

The Stepoko is designed to be able to control a multitude of 2-phase stepper motors. These all have two sets of coils that are driven in a particular combination in order to make the motor turn in the correct direction. If this is all new to you, read our tutorial on Motors and Selecting the Right One, in particular the section Stepper Motors. This tutorial has some descriptions of motors with three sets of coils rather than two, but the theory is the same.

alt text

The Stepoko can handle a variety of motors by adjusting the current level for the application.

Identifying the Coils

A lot of the time steppers come from a ‘motor box’ on a hobbyist’s shelf, and may not have ratings or part numbers. If there are four wires, chances are it’s a stepper. The coils need to be identified though, so take out a multimeter and look for continuity between wires. If the motor has four wires, with two pairs that have a similar resistance, you’ve found the coils!

Here you can see that the first two random wires measured open, and the second two measured 1.8 ohms. This is a typical large-ish 2 phase stepper.


Alternately, with the datasheet the wires should be indicated. An example datasheet from our general purpose motor shows a simple wiring diagram with the two coils.

Attach the motors

The two coils of the motor correspond with the ‘A’ and ‘B’ terminal pairs on the board. Including the fact that you can put the coils in backwards, there are 8 possible ways to connect two coils! But which one goes where? Don’t even worry about it. If one is backwards, or if coils ‘A’ and ‘B’ are swapped, the motor will just spin in the other direction, which can be set in software.

More worrisome is how to convince the stranded wires get into the terminal blocks and then, stay there after they have been tightened. Tinning the leads can make the whole thing go smoothly.

Left: the wire ends look pretty ratty from the factory. Center: Collect the wire strands by giving them about 180 degrees of twist along the length of the strip. Right: Tin each lead. Apply excess solder to allow the flux to work, and pull the extra solder off with the iron yielding a solid cylinder of wire.


Sometimes the terminal springs are tight from the factory. To help ease connection, back out the termina screw until it’s flush with the terminal block, gently open the contact, and use a tool to push from the tinned end.


Left: Back the screw out until flush. Center: Gently open the contact plate. Right: Help put the wire in with a tool that is choked up near the tinned end. You can’t push a rope!


Hardware: Setting the Current

Before powering up the Stepoko, set the desired current for each attached motor. The current control potentiometer scales the peak drive current from 0 to 2 amperes. There a few methods of setting the current.

Set by ‘Dead Reckoning’

This is the preferred method.

The trimpot can swing through 200 degrees of motion, and covers a range of 2 amps. Turn the trimpot counter-clockwise gently until it hits the stop, then clockwise a number of degrees for the desired current. The example datasheet from the previous section lists the motor as being 0.33 A capable. Set the knob to 33 degrees from counter-clockwise stop.

Use this formula for other motors:

alt text

- or -

alt text

Set by Test

If you have more experience, you may opt to set the current by feel.

Start by setting all the trimpots to slightly off their counter-clockwise stop. Then, fire up the Universal Gcode Sender software (described later) and connect to the Stepoko. This enables all the motor drivers and will lock their position. Now, attempt to move the motor. If the motor moves easily, carefully turn up the channels and repeat the test until the force required to move the motor (slipping poles) is greater than the expected lateral force exerted by the tool head.

Caution! This can result in setting the current higher than the rating on the motor. Even though a motor may be rated at one level, it is absolutely possible to drive it at a higher level. If you need torque, or locking torque, that results in current above the motor's rating, you should be using a bigger motor. The result will be heat so keep checking that the motors are not too hot to touch (without burning yourself). Do this every couple minutes for about a half-hour until you are convinced that the temperature is stable.

Set by Current-Shunt Measurement

The most scientific method to know a thing is to measure it. To do that, you’ll need a scope and a steady hand.

There are 6 current sense resistors on the Stepoko that can be identified in the schematic, and by finding the larger resistors near the drivers. Each has one end grounded while the other is connected to the active driving circuitry. By adding a probe ground to one end and stabbing the other end, both positive and negative coil current can be measured.

alt text

Here an oscilloscope probe has the grabber and alligator clip removed, and is inserted in a coil that contacts the ground part of the probe while the tip fits down into a pin cup that attaches to either end of the current sense resistor. Sometimes this setup is called a ‘Zero Length Probe’.

The resistor itself is 0.1 ohms in resistance. At the max current setting of 2A, and by following ohm’s law, the max voltage read across this resistor is 0.2V, or 200 millivolts. This is quite low. A scope with 8 divisons on the screen has to be set to 50mV per divison so that positive and negative 2A can be read. At this vertical scale, the electromagnetic radiation from the giant current loads of the motor will be picked up by the extra few inches of the probe, which is why a the shortest possible loop of wire at the probe end is desired.

alt text

This plot shows the positive and negative cycles of the motor’s coil. Notice that the plateau is at 100mV, or one ampere. The trimpot is centered.

Adjust the plateau average to the rating of the motor.

Hardware: Dealing with Heat

To get the heat out of the driver ICs, the Stepoko comes equipped with three heatsinks on the top and a large aluminum mass on the backside. When setting up the Stepoko, be careful to check the temperature often to make sure it is not too hot to touch. Generally speaking, the harder the motors are driven, the more heat will accumulate on the heatsinks.

Here are a few methods of dealing with the heatsinks.

Provide air space

For small motors or mills that don’t have a large cool mass of metal to wick out the heat, make sure the Stepoko is lofted and that air can passively circulate around the heatsinks.

alt text

On my mini-laser cutter, the heatsink has been kept off the wood base

Attach a path for cooling

The intent of the aluminum slug on the backside is to conduct heat to the mill itself for cooling. The height is perfect to pass through a hole cut in the SparkFun Big Red Box enclosure so that the whole thing can be mounted to a thermally conducive surface.

alt text

The frame of the Shapeoko mill is large enough that the mill can operate with a strong drive for hours before the frame even starts to get warm.

Add a fan

There is a connection on the Stepoko for attaching a single, or multiple 12V fans. This connection is regulated to 12V and unswitched, so fans connected there will run whenever the Stepoko is powered from 12-30V.

Software and Firmware Overview

Milling is a little more interactive than just sending a job to a printer. After the hours put into modeling, the model files are converted into what’s called G-code by CAM software. Then, the G-code is sent to the mill by some machine control software (in our case, universal G-code sender). The mill itself runs firmware which can interpret what the machine control software is saying and in turn, drives the stepper motors to move the mill. Whew.

alt text

This process of walking through various programs is know as a tool chain. This graphic shows each distinct part of the tool chain, though the machine firmware is not usually talked about, and sometimes (in particular for 3D printing) the CAM and gcode sending software are the same.

The solid modeling, design work, and CAM software are not in the scope of this hookup guide, and from here on it is assumed that you have some gcode from somewhere. Several examples exist in the Stepoko github including a 1x1 inch square, a few 10x10 inch squares, and the SparkFun flame.

Software: Machine control (Universal G-code Sender)

Once G-Code files have been created, a program is needed to parse them and issue the commands to the Stepoko. A good open source one that works well with the Stepoko (and all grbl hardware) is Universal G-Code Sender.

As of writing this, 1.0.9 is the latest stable build. Most people will want this as a zip archive rather than having the github source. Download it, unzip it into a directory, and run the batch file for windows, or shell script for mac/linux.

Make sure you are connected to the Stepoko. Once the program is loaded, you can set the connection parameters, and click ‘Open’ to get a connection to the mill. Use 115200 baud and the port that appears when you attach the Stepoko. If all goes well, the grbl firmware will reply with its version number.

alt text

This is a view of the gcode sending software, Universal Gcode Sender. The upper most tabs allow you to enter arbitrary gcode, load files, operate the mill in a manual way, and send macro command strings. The lower tabs show terminal output and progression through a gcode file as a table of commands.

alt text

Selecting the menu ‘Settings’, ‘Firmware Settings’, then ‘GRBL’ opens this window. This shows the settings currently saved to the Stepoko and allows modification. Once modified, click ‘Save’ to put them in the Stepoko’s ROM. Common settings are covered in the next page.

alt text

The File Mode tab.


alt text

The Visualizer window.


Firmware: grbl for the Stepoko

The Stepoko is shipped with the latest grbl, (v0.9) as of this writing. The grbl project is highly developed and can be found in github, complete with a wiki that describes in detail what the settings do.

Direct links to the project and wiki:

From the grbl github repository:

List of Supported G-Codes in Grbl v0.9 Master:
- Non-Modal Commands: G4, G10L2, G10L20, G28, G30, G28.1, G30.1, G53, G92, G92.1
- Motion Modes: G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
- Feed Rate Modes: G93, G94
- Unit Modes: G20, G21
- Distance Modes: G90, G91
- Arc IJK Distance Modes: G91.1
- Plane Select Modes: G17, G18, G19
- Tool Length Offset Modes: G43.1, G49
- Cutter Compensation Modes: G40
- Coordinate System Modes: G54, G55, G56, G57, G58, G59
- Control Modes: G61
- Program Flow: M0, M1, M2, M30*
- Coolant Control: M7*, M8, M9
- Spindle Control: M3, M4, M5
- Valid Non-Command Words: F, I, J, K, L, N, P, R, S, T, X, Y, Z

In our factory, after programming the firmware onto the Stepoko, we put the following settings directly into the ROM of the ATmega328p. These are held even when power is removed, or until they are changed by the user through the serial (or Universal Gcode Sender) interface.

These default settings are appropriate for the Shapoko 3 mill.

$0=30 (step pulse, usec)
$1=255 (step idle delay, msec)
$2=0 (step port invert mask:00000000)
$3=0 (dir port invert mask:00000000)
$4=0 (step enable invert, bool)
$5=0 (limit pins invert, bool)
$6=0 (probe pin invert, bool)
$10=3 (status report mask:00000011)
$11=0.050 (junction deviation, mm)
$12=0.002 (arc tolerance, mm - NEW SETTING)
$13=0 (report inches, bool)
$20=0 (soft limits, bool)
$21=0 (hard limits, bool)
$22=0 (homing cycle, bool)
$23=1 (homing dir invert mask:00000001)
$24=25.000 (homing feed, mm/min)
$25=250.000 (homing seek, mm/min)
$26=100 (homing debounce, msec)
$27=1.000 (homing pull-off, mm)
$100=40 (x, step/mm)
$101=40 (y, step/mm)
$102=40 (z, step/mm)
$110=500.000 (x max rate, mm/min)
$111=500.000 (y max rate, mm/min)
$112=500.000 (z max rate, mm/min)
$120=25.000 (x accel, mm/sec^2)
$121=25.000 (y accel, mm/sec^2)
$122=25.000 (z accel, mm/sec^2)
$130=225.000 (x max travel, mm - NEW SETTING)
$131=125.000 (y max travel, mm - NEW SETTING)
$132=170.000 (z max travel, mm - NEW SETTING)

Firmware: Configuring grbl and Calibrating

This section covers calibration of the axes. The settings take a parameter of steps required for each millimeter of motion, but factors such as microstepping and mill geometry come into play.

Calibrating

When working with a new motor, a few steps need to be taken to get it moving correctly

  • Get the number of steps per revolution
  • Decide on microstepping value
  • Determine ratio of motor revolutions to carriage motion
  • Calculate steps per mm
  • Drive the carriage a known distance
  • Measure error and apply to settings

The Initial steps/mm Setting

If using a mill with known geometries, you’re in luck! Punch in the steps/mm as given.

If using recycled parts or variable materials (like belts), do some basic math to get an approximate first-setting.

Do This for Each Axis:

While turning the motor, measure the distance traveled in mm. Then, calculate steps per mm based on

alt text

For example, with a 20 steps/rev motor that travels 2mm per revolution and 1/8 microstepping,

alt text

Now, using the ‘machine control’ tab in Universal Gcode Sender, instruct the mill to move 1 inch (or some number of millimeters). Is it close? Reset the mill, mark the location and repeat. Make a measurement of the true movement.

alt text

alt text

Now, modify the original setting by a ratio of the expected and measured movement. Another way to think of it is, what’s the percent error?

alt text

For my example, I intended to drive 1 inch but actually drove 1.3 inches. I take the original setting of 9.52, multiply by 1/1.3 to get 7.32. After programming the new setting, the movement is dead-on (or bang-on if using mm).

Cutting a Square

If you’ve never used a mill before, start by cutting out a simple shape. For this, the design step will be skipped. We’ll go directly to CAM and use it to put in a basic shape.

The first step is to open MakerCam in a new window. If you have ad blocking software enabled, you may have to disable it.

alt text

Makercam first view. I’ve scrolled around until I was able to locate the origin.

Next, use the menu to add a square (or any shape). A window will open that lets you specify some of the parameters.

alt text

Enter the desired parameters

The real purpose of the cam software is to determine how to make a real machine do some movement that yields the desired shape remaining at the end of the whole thing. To do this, drop down the CAM menu and select profile. This means the tool will move around the outside of whatever the shape is that’s selected. Other options are engrave, to follow the line exactly, and pocket, which removes all the material inside the shape.

alt text

The profile options window

From this window, the cam software takes into account the geometries of the actual mill. Set the tool diameter, safety height (how far above the surface to go before X-Y movement), and step increment. Stock surface is important too, but for now leave it a 0. It can be used for multiple path jobs where one path takes the stock surface down, and the next cuts from that level.

I’ve selected quarter inch depth with eighth inch depth per cut. Hit ‘OK’

Now we need to calculate a path based on the parameters. From the CAM menu, select ‘calculate all’

alt text

Now a green line with arrows appears above the part. This shows how the tool will move. This path becomes the gcode, so the next step is to export (again, from the CAM menu). There should only be one path available to select.

alt text

Got it? OK, now put MakerCam aside and open Universal Gcode Sender. Then load the file and click visualize. By holding down the mouse button in the visualization window, the view can be rotated.

alt text

The visualizer shows that two cuts will be made (sanity check: I did want ¼ inch depth at a rate of 1/8 inch per cut). With the ESTOP function activated (no carriage movement), the job can be run and you can watch the tool head move around the path.

When you’re confident that the mill head has enough room to complete the pass, zero it out, and hit go. Running a couple inches above the table is a good way to build confidence in the job. Be ready to hit the estop if something goes amiss. When you’re good and ready, turn on your active cutting device and let ‘er rip.

Now's a good time to check the accuracy of the mill. Did the shape measure correctly to the intended size? If not, do another calibration calculation, and adjust the settings.

Cutting and Engraving a SparkFun Coaster

Squares are alright, and it’s fun to watch the machine move around, but eventually you’ll want to actually cut some real shape out with the mill. I’ve put this Shapoko Coaster Project together to show all the steps of cutting a project with a mill.

New!

Shapeoko Coaster Project

November 20, 2015

A step-by-step guide to cutting and engraving a coaster with the Shapeoko.

This uses open source software for all steps:

  • Create design in inkscape
  • Create took paths through makercam.com
  • Send gcode with Universal Gcode Sender
  • Stepoko runs grbl on the mill

Watch a video of the coaster being made below:

Resources and Going Further

This is all the basic information about applying the Stepoko to mills. If you would like more information about a particular step, please comment.

Looking into the future

  • McMaster-Carr - Order tools online, as well as any part you would ever need.
  • CamBam Software - This CAM software is better than the free one and is reasonably priced. It has a 40 day use trial. I would highly recommend trying it out.

Links mentioned in this hookup guide


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

EL Sequencer/Escudo Dos Hookup Guide

$
0
0

EL Sequencer/Escudo Dos Hookup Guide a learn.sparkfun.com tutorial

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

Introduction

The SparkFun EL Sequencer is an Arduino-comptabile microcontroller, with circuitry for controlling up to eight strands of electroluminescent (EL) wire.

SparkFun EL Sequencer

COM-12781
$34.95

The Arduino shield version of the Sequencer is the SparkFun EL Escudo Dos, and it can be used with any Arduino Uno footprint-compatible microcontroller.

SparkFun EL Escudo Dos

COM-10878
$24.95
5

Materials Required

To follow along with this tutorial, we recommend you have access to the following materials in addition to your Sequencer or Escudo Dos.

Suggested Reading

If you aren’t familiar with the following concepts, we recommend reviewing them before beginning to work with the EL Sequencer or Escudo Dos.

Hardware Overview - Similarities

This section will cover the features that are shared between both the EL Sequencer and the EL Escudo Dos.

External Power Headers

External Power Headers

External Power Headers on the EL Sequencer.

There are three power connection points on the Sequencer. The first is the AC In connection, which is the default connection point for any external inverter. The second connection is the DC Out line, which will connect to any inverter that does not have an external power supply. This provides a DC power supply to the inverter from the EL Sequencer itself. The final power connection is the Batt In connection. This allows the user to provide a power supply from a 3.7V lipo battery, or other power supply of 3.5V-16V.

These can be connected via a standard 0.1" 2-pin header, or via the JST connector available on each line. If you ever forget the purpose of these connections, they are clearly labeled on the bottom of the board.

EL Escudo Dos

External Power Headers on the EL Escudo Dos.

The power headers on the EL Escudo Dos have the same functionality as the EL Sequencer. However, there is no Batt In header. This is because the power for the Escudo comes from the VRAW line on the connected Arduino or RedBoard.

Channel Headers (HIGH VOLTAGE)

Sequencer Channel Headers

Channel Headers on the Sequencer

Escudo Channel Headers

Channel Headers on the Escudo Dos

As the silk on the bottom side of the board states, there is high voltage in this area of the board. Care must be given when handling the board in a powered state, to prevent a shock to the user. These channels output the AC current needed to drive the EL wire. This is output at 100+V AC, 4000Hz (dependent on the inverter used). Each channel (A-H) is attached to one digital pin on the ATMega328 (pins 2-9, respectively). Driving the digital pins HIGH triggers the EL wire to turn on.

These can be connected to EL devices (wire, panels, etc.) via a standard 0.1" 2-pin header, or via the JST connector available on each line.

Solder Jumpers

  • SJ1 - This jumper allows the user to bypass the LM317 regulator when it’s shorted. This regulator is used for external inverters. If left open, the regulator output voltage can be modified by user-supplied resistors on RA and RB pads. More on that below.

Solder Jumper 1

Solder Jumper 1 on the Sequencer.

Escudo SJ1

Solder Jumper 1 on the Escudo.

  • SJ2 - This jumper is included as an option for wirelessly uploading of code to the Sequencer via XBee. This feature is experimental, and no guarantees are given for this feature’s functionality.

Solder Jumper 2

Solder Jumper 2 on the Sequencer. This jumper is not present on the Escudo.

TRIACs and Optoisolators

The main functionality of the Sequencer/Escudo comes from the TRIACs (Triode for Alternating Current) on-board. The MO3063S TRIAC Optocoupler takes the logic output from the associated ATMega328 digital pin which triggers the Z0103MN TRIAC to open the flow of the AC current from the inverter through the gate to drive the EL channel. This keeps the AC side of the circuit optically isolated from the DC portion of the circuit.

Sequencer TRIACs

EL Sequencer TRIACs and Optoisolators

Escudo TRIACs

EL EscudoDos TRIACs and Optoisolators

Keep in mind that when the boards are powered and connected to an inverter, touching these areas can lead to an unpleasant shock. It won’t hurt you, but it doesn’t feel good.

Adjustable Voltage Regulator

The LM317 voltage regulator on this board is adjustable based on the resistor values applied to it. By default, this board comes shipped with a 390Ω resistor on R1 and a 240Ω on R2. However, footprints for thru-hole resistors (A and B) have been added for the user to adjust the voltage out to their project needs. You’ll need to remove the SMD resistors first. Then add thru-hole resistors of your choice. See the LM317 Datasheet for more information on which resistor values correspond to which voltage output.

PTH resistors

Resistors A and B on the EL Sequencer

PTH resistors

Resistors A and B on the EL Escudo Dos

Hardware Overview - EL Sequencer

This section will cover the unique features of the EL Sequencer.

NRF24L01+ Header

NRF24L01+ Header

This header is designed to interface with an NRF24L01+ module breakout. This provides a 2.4GHz signal to the EL Sequencer, which provides remote control options for the Sequencer at up to a 100m range.

FTDI Header

FTDI Header

This is a 5V FTDI header, which is given to provide simple access for reprogramming the ATMega328 via serial connections. This can also be used to have the EL wire triggered via serial data in to the system.

XBee Header

XBee Headers

This connection is provided to give users the option of wirelessly connecting the EL Sequencer via XBee. This can be used for mesh networking of several different Sequencers together (this is great for group costume projects), or remote control of the Sequencer.

ICSP Header

ICSP

This 6-pin header is provided to allow the user to reprogram the ATMega328 on board via an external programmer. This also allows you to reprogram the EL Sequencer without the requirement of the Optiboot loader from the Arduino IDE.

Analog Input Header

Analog Headers

The additional analog pins on the ATMega328 are broken out to a standard 0.1" header on the EL Sequencer. This also gives the user the capability to trigger the EL wires from analog inputs (such as a photocell, temperature sensor, or a line sensor ).

Pins A6 and A7 are analog input only. Pins A0-A5 can be used as an analog input or as a digital I/O.

Switches and Reset Button

switches and button

  • XBee to FTDI (far right, center) - This switch changes the RX line from being supplied via the FTDI header or the XBee. If attempting to program the Sequencer via FTDI, this switch must be set to the FTDI side.

  • USB/BATT (bottom, center) - This switch changes the power source for the ATMega328. The USB setting allows the ATMega328 to be powered via the FTDI connection, while the BATT setting allows the Arduino part to be powered off of a lipo battery instead.

  • Reset Button - Resets the Arduino sketch running on the ATMega328. It pulls the RESET line low, allowing the system to reset.

Hardware Overview - EL Escudo Dos

This section will cover the unique features of the EL Escudo Dos Arduino Shield.

Shield Headers

Uno Headers

These headers allow the shield to be connected to any Arduino Uno/Uno R3 compatible board. We will be using the SparkFun RedBoard for this example.

Currently, the EL Escudo Dos Shield is designed for the original Arduino Uno footprint (not the R3 footprint). However, this shield can be used with Arduino Uno R3 boards without issue.

Channel Headers

Channel Headers

The EL Escudo also provides a row of 0.1" spaced headers to allow the user to read the signals from the microcontroller to the EL wires. This is beneficial for debugging.

Hardware Hookup

To get started using the EL Sequencer or EL Escudo Dos, there are a few basic steps that must be completed.

Solder Headers

EL Sequencer

At an absolute bare minimum, you must solder 6 pins on the FTDI header. For simplicity’s sake, we recommend using male headers (either straight or right angle as these are compatible by default with the FTDI breakout). This will enable you to program the EL Sequencer via an FTDI breakout board.

If you plan on using an XBee unit with your Sequencer, you will also want to solder XBee Sockets to the board. If you plan on using any additional connectors on the board, you will also want to solder those headers on now. Keep in mind you may also want to trim off any excess header on the bottom of the board if you intend to use this in a wearable application.

EL Escudo Dos

Thanks to the simplified design, you only need to solder Arduino shield headers onto the Escudo. If you want to use any additional components in your project (such as wireless modules or external sensors), you will want to use stackable headers.

Connect the EL Wire

You have 8 channels available on the Sequencer to which you can plug in EL wire, chasing EL wire, or EL panels.

Please check out this tutorial on working with EL Wire specifically, and the current requirements for different types of materials.

Note: If you plan on using Chasing EL wire, keep in mind you will need an adapter cable to make it compatible with the EL Sequencer/EL Escudo Dos. You also will need 3 channels available on the EL Sequencer for the chasing wire, in order to get the proper ‘chasing’ effect to display. This means you will only have 5 additional channels available (or 2, if you plan to use 2 chasing EL wire strands).

Connect the Inverter

Once you have hooked all of your EL wires up, the next step is to hook up the inverter.

  • 3V Inverter - If you are using the 3V inverter, you will need to hook up both wire pairs from the inverter to the Sequencer. The black/black wire pair will plug into the AC In JST connector, while the red/black wire pair plugs into the DC Out JST connector.

  • 12V Inverter - While using the 12V inverter, there is only one wire pair that will plug into the Sequencer. The red/black wire pair will plug into the AC In JST connector. You will need a separate power supply to run this inverter (such as the 12VDC 600mA Wall Adapter).

Note: Make sure all power has been removed from the system before plugging in any inverter. This will help prevent any inadvertent shocks to the user.

Connect the Power Supply

EL Sequencer

If you are using a battery for the power supply, you can connect this to the Batt In JST header without altering the board. Using an external power supply with the 3V inverter will require closing SJ1. You will need to connect that supply to the PTH headers labeled Batt In. Make sure the power supply falls in the range of 3.5V-16V for an external power supply.

EL Escudo Dos

The power supply for the EL Escudo Dos actually comes from the Arduino. We recommend using a 12V wall adapter for powering the Arduino.

Alternatively, if you would like to go wireless, you could use a male barrel jack adapter along with a 12V battery. Typically, however, the EL Sequencer will be a better option for you for wireless applications.

Final Circuit

Once everything is hooked up, your circuit should look something like the following:

EL Sequencer HookUp

Arduino Code

Once you have all of your hardware hooked up properly, it’s time to program your Sequencer to run the EL Wire display as you want. You will need to download the Arduino code in order to follow along with the example.

Download EL Sequencer Example Firmware

You can also download the most up-to-date code from the EL Sequencer GitHub repository.

We will be working with the “SparkFun_EL_Example.ino” example. If you need a review on how to upload Arduino code to your board or using the Arduino IDE, please check our tutorial here. Also, if you are unsure about installing the FTDI drivers, please check out this tutorial.

If using the EL Sequencer:

Plug in your FTDI board to the computer via USB, and insert the FTDI onto the EL Sequencer. Make sure you match up the BLK to BLK and GRN to GRN labels.

When uploading your code, please be sure to select the following settings in the IDE:

  • Board: LilyPad Arduino
  • Processor: ATMega328
  • COM port: Whichever port the FTDI Basic appears on for your operating system.

If using the EL Escudo Dos + RedBoard:

Plug in the RedBoard to the computer via USB. Select the following settings in the IDE:

  • Board: Arduino Uno
  • COM port: Whichever port the FTDI Basic appears on for your operating system.

Demo Code

This basic demo will cycle through each channel on the Sequencer, one by one, repeating until the system is either reprogrammed or turned off.

In the first section, we must define each pin that we will be using on the ATMega328.

language:c
/*******************Setup Loop***************************/
void setup() {
  // The EL channels are on pins 2 through 9 on the ATMega328
  // Initialize the pins as outputs
  pinMode(2, OUTPUT);  // channel A
  pinMode(3, OUTPUT);  // channel B
  pinMode(4, OUTPUT);  // channel C
  pinMode(5, OUTPUT);  // channel D
  pinMode(6, OUTPUT);  // channel E
  pinMode(7, OUTPUT);  // channel F
  pinMode(8, OUTPUT);  // channel G
  pinMode(9, OUTPUT);  // channel H

//Uncomment the following line if using this on the EL Escudo Dos.
// Pin 10 is a status LED on the EL Escudo.
//  pinMode(10, OUTPUT);

//Pin 13 is the status LED on both the EL Sequencer and Arduino for use with the EL Escudo Dos.
   pinMode(13, OUTPUT);
}

Each pin is declared as an output, which will allow us to drive the channel HIGH or LOW. We will cycle through each channel, turning them on individually, waiting 1/10 second, turning off, and moving to the next channel.

language:c
/*******************Main Loop***************************/
void loop()
{
  int x,status;

  //Step through all eight EL channels (pins 2 through 9)
  for (x=2; x<=9; x++)
  {
    digitalWrite(x, HIGH);   // turn the EL channel on
    delay(100);              // wait for 1/10 second
    digitalWrite(x, LOW);    // turn the EL channel off

//digitalWrite(10, status);   //Uncomment this line if using the EL Escudo Dos
digitalWrite(13, status);   // blink status LEDs
    status = !status;
  }
}

Each time a channel is cycled through, the status LEDs on the board will blink.

Once the code is uploaded, you should see each strand of EL wire light up one by one. If you aren’t seeing that, verify that you have the correct power settings on the USB/Batt switch, and that the inverter is connected properly, switched on (if using the 12V inverter), and that the power supply to the board is properly charged and/or connected.

Going Wireless

If you would like to add wireless capabilities to your project, there’s just a few more steps to get up and running.

  • Insert a radio unit: You can either use a paired XBee unit or an NRF24L01+ module. You will need to make sure headers are soldered on for either device. If you need additional information on adding an XBee module, please check out our tutorial here. On the EL Sequencer, you will also need to flip the XBee to FTDI switch to XBee to ensure XBee communication is working properly.

  • Update the Code

If using a Series 1 XBee:

Upload the ‘SparkFun_XBee_EL_Sequencer.ino’ sketch to your board. In the first section, the status LED is declared as an output, and the Serial connection is opened at 9600bps.

language:c
//Declare character 'val'
char val;

/*******************Setup Loop***************************/
void setup(){
  Serial.begin(9600); //Begin Serial communication for debugging
  pinMode(13, OUTPUT); //Set pin mode as output for status LED
  val = 'A';// button pressed, therefore sending  letter A

  Serial.println("EL Sequencer's XBee is Ready to Receive Characters");
  digitalWrite(13,LOW); //set Status LED off
  delay(1000); //Wait 1 second
}

The main loop of the code simply waits for the XBee unit to receive the character ‘A’ from a remote XBee unit. If the character is received, the status LED is turned on, and a message is output to the serial terminal.

language:c
/*******************Main Loop***************************/
void loop(){

  //Check if XBee is receiving data from other XBee
  if(Serial.available()){
    val = Serial.read();

    //Check to see if character sent is letter A
    if(val == 'A'){
        digitalWrite(13,HIGH); //turn ON Status LED
        delay(50);
      Serial.println("Character Received");
    }

    else{
      digitalWrite(13,LOW); //turn OFF Status LED
    }
  }
}

If using an NRF24L01+:

You will need to use the RF24 library with the nRF24L01+ boards. We have a tutorial with more information regarding installing this library here.

We recommend using the RF24/examples/Usage/led_remote.ino example sketch. This is already configured to be compatible with the EL Sequencer with 6 channels of EL wire attached and will trigger each channel based on buttons hit on the remote unit.

The EL Sequencer will trigger the channels on and off based on the LED role in the code.

      //
      // LED role.  Receive the state of all buttons, and reflect that in the LEDs
      //

      if ( role == role_led )
      {
        // if there is data ready
        if ( radio.available() )
        {
          // Dump the payloads until we've gotten everything
          while (radio.available())
          {
            // Fetch the payload, and see if this was the last one.
            radio.read( button_states, num_button_pins );

            // Spew it
            printf("Got buttons\n\r");

            // For each button, if the button now on, then toggle the LED
            int i = num_led_pins;
            while(i--)
            {
              if ( button_states[i] )
              {
                led_states[i] ^= HIGH;
                digitalWrite(led_pins[i],led_states[i]);
              }
            }
          }
        }
      }

The code waits until the receiver gets data coming in and then swaps the LED states accordingly (in this case, the LEDs will be replaced with the EL channels).

That’s it!

That’s all you need to do to add wireless capabilities to your EL project. You can now remotely control your EL Sequencer project.

Resources and Going Further

Now that you have your EL Sequencer or EL Escudo Dos up and running, you can start creating your own awesome art displays, interactive costumes, or colorful installations. Making something really neat? Let us know - we’d love to see it!

If you have any feedback, please visit the comments or contact our technical support team at TechSupport@sparkfun.com.

Check out these additional resources for more information and other project ideas.


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

FemtoBuck Constant Current LED Driver Hookup Guide V12

$
0
0

FemtoBuck Constant Current LED Driver Hookup Guide V12 a learn.sparkfun.com tutorial

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

Introduction

Note: This tutorial is for the latest version of the FemtoBuck, V12. If you have an older version of the FemtoBuck, please consult this guide.

The FemtoBuck is a small-size, single-output constant current LED driver. By default, the FemtoBuck is driven at 330mA. That current can be reduced by either presenting an analog voltage or a PWM signal to the board. It can be increased to 660mA by closing a solder jumper on the board, as described later in this tutorial.

Product image

Suggested Reading

Here are some topics you should know before using the FemtoBuck. Have a look if you need more information.

FemtoBuck Overview

Connecting the FemtoBuck

For the version 1.2 of the FemtoBuck, we’ve increased the voltage ratings on the parts to allow the input voltage to cover the full 36V range of the AL8805. Note that the supply voltage must be at least 6.0V, and should be at least 2-3V higher than the forward voltage of the LED(s) to be driven.

Since the FemtoBuck is a constant current driver, the current drawn from the supply will drop as supply voltage rises. In general, efficiency of the FemtoBuck is around 95%, depending on the input voltage.

Labeled picture

One signal input is provided for dimming control. A ground pin (DGND) is provided to reference against the controlling module for accuracy. Dimming can be done by an analog voltage (20%-100% of max current by varying voltage from .5V-2.5V) or by PWM (so long as PWM minimum voltage is less than .4V and maximum voltage is more than 2.4V) for a full 0-100% range.

Another ground (PGND) pin is available next to the power supply pin to provide a high-current return path. The spacing on the four holes on the input side is 0.1" for standard headers.

The output side has a 0.1" spaced hole pair as well as a 3.5mm spaced hole pair, to allow the user to attach our 3.5mm screw terminals.

The notches on either end of the board allow you to use a zip tie to secure the wires to the board after soldering them down.

Closing the solder jumper

The most recent revision has a small solder jumper, highlighted above, that can be closed with a glob of solder to double the output current from 330mA to 660mA. We suggest closing this jumper before soldering headers, terminals, or wires to the nearby holes. Note that it’s very likely that you’ll get some solder on the adjacent resistor pads. That’s perfectly okay. Those pads will be shorted together when you’re done anyway.

Finally, take note of the size of the FemtoBuck. If desired, the entire board can be slid into a piece of 9mm heat shrink tubing to provide insulation and strain relief.

Connecting to an Arduino or Compatible Board

Connected to Arduino Uno

If you have only one or two LEDs, you can connect the FemtoBuck directly to the VIN pin on your Arduino. You will need to power the board from an external supply, as the 5V provided by USB isn’t high enough to power the FemtoBuck (the FemtoBuck won’t turn on below 6V).

Multiple FemtoBucks or high current mode

If you want more than one FemtoBuck, or if you’ve closed the solder jumper to increase the drive current, you’ll need to add an external power supply. It’s not good to try to run too much current through the traces on the Arduino. Note that the LEDs are wired separately to each FemtoBuck! This is very important; the output of each FemtoBuck must be completely isolated from any other! That means that RGB LEDs with “common” pins (common anode or common cathode) cannot be used with the FemtoBuck!

Multiple LEDs in series

Multiple LEDs can be connected in series, as shown, and the supply voltage should be at least 2-3V higher than the sum of the forward voltages of the LEDs.

For instance, our blue 3W LEDs have a forward voltage of 3.2V to 3.8V. To be on the safe side, use the highest voltage in the range. If you want to connect four of them, you’d need a power supply of ~17V or greater (3.8V + 3.8V + 3.8V + 3.8V = 15.2V; add 2V of “head room”).

Since 17V is greater than the Arduino can tolerate on its input, we have to provide an external supply for the Arduino as well. This can be the standard 5V USB supply.

Further Increasing Current Drive Strength

If even 660mA isn’t enough current for you, it is possible to increase the maximum current of the FemtoBuck board up to 1A per channel. To do so, replace the current sense resistors with smaller values. To calculate the new value for the resistor, use this formula:

ILED = 0.1 / Rset


Thus, for a 1A current, you’d want a 0.1Ω resistor. Don’t forget to be wary of current ratings; at 1A, the sense resistor will be dissipating 1/10W, so you probably want a resistor of at least 1/8W rating. The package is a standard 0805.

Resources and Going Further

Consider checking out these other tutorials for more information about concepts in this guide:

  • Light - Covers some useful concepts, such as why doubling the current doesn’t appear to double the brightness.
  • Diodes - Diodes are a slightly more complex beast than resistors. Our diodes tutorial will help you understand why we need a special device to power them.
  • Pico Buck Hookup Guide - Need to control more LEDs? The PicoBuck is just like the FemtoBuck except it has three channels, each capable of providing 350mA. Perfect for controlling high powered RGB LEDS that require control of each color individually.

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

SparkFun Inventor's Kit for Edison Experiment Guide

$
0
0

SparkFun Inventor's Kit for Edison Experiment Guide a learn.sparkfun.com tutorial

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

Introduction

The SparkFun Inventor’s Kit for Intel® Edison, otherwise known as the Edison SIK, introduces the Edison as a powerful Internet of Things (IoT) platform. The experiments contained within these pages will guide you through programming the Edison using JavaScript and controlling various electronics. Whether you are new to electronics and JavaScript or are looking to take your skills to the next level (to the “cloud!”), this kit is a great starting point.

Set Aside Some Time - Please allow yourself ample time to complete each experiment. You may not get through all the experiments in one sitting. Each experiment also contains suggestions on project ideas and taking the examples to the next level. We suggest that you challenge yourself and try some of them!

Included Materials

Here is a complete list of all the parts included in the Edison SIK.

Inventor's Kit for Intel Edison components

The SparkFun Inventor’s Kit for Intel® Edison includes the following:

If, at any time, you are unsure which part a particular experiment is asking for, reference this section.

Suggested Reading

The following links may help guide you in your journey through the Edison SIK.

Each experiment will also have a Suggested Reading section to aid you in understanding the components and concepts used in that particular experiment.

NOTE: If you would like to see all of the example code in one place, it can be found on GitHub! Just click the button below to be taken to the GitHub repository and click the link to Download ZIP.

Edison SIK Example Code

Using the Kit

Before exploring the experiments, there are a few items to cover first. If you have completed one of our other Inventor’s Kits before, you should already be familiar with most of the concepts in this section. If this is your first Inventor’s Kit, please read this part carefully to ensure the best possible SIK experience.

Intel® Edison

The Intel® Edison acts as the brain for the kit. The Edison sports a dual-core, 500 MHz Atom Z34XX processor, 1 GB of RAM, and 4 GB of onboard flash storage. It has built-in WiFi and Bluetooth. Those are some impressive statistics, but what does that mean? Well, the Edison is a complete computer in a tiny package. It is even capable of running a Linux operating system! To learn more about the Edison, visit the Edison Getting Started Guide.

Edison Getting Started Guide

December 5, 2014

An introduction to the Intel® Edison. Then a quick walk through on interacting with the console, connecting to WiFi, and doing...stuff.

Breadboard

Solderless breadboards are the go-to prototyping tool for those getting started with electronics. If you have never used a breadboard before, we recommend reading through our How to Use a Breadboard tutorial before starting with the experiments.

How to Use a Breadboard

May 14, 2013

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.

Jumper Wires

This kit includes thirty 7" long jumper wires terminated as male to male. You can use these to connect terminal strips on a solderless breadboard or connect them to the header on the ADC Block.

M/M jumper wires

Screwdriver

We’ve included a pocket screwdriver to aid you in any mechanical portions of this guide. Note that the screwdriver bit can be pulled out from the plastic handle. The bit can be turned around and inserted back into the handle if you need to choose between a Phillips or a flathead driver.

SparkFun Mini Screwdriver

USB Ports

The Edison Base Block has 2 USB ports.

USB ports on the Edison Base Block

  • Console - This port is attached to an FTDI chip that converts USB signals to serial. This allows you to connect to a serial terminal on the Edison. Only the USB microB cable (the 6-foot cable) can fit into this port.
  • OTG - OTG stands for On-the-Go, and it means that the Edison can act as a USB host or a USB device. You may plug either the USB microB cable (for using the Edison as a USB device) or the 4-inch USB microA cable (for using the Edison as a USB host) into this port.

Building the Block Stack

Before we can use the Edison in any of our circuits, we must first attach it to the Blocks in the kit. The Blocks stack in a particular order to work best with the kit.

Parts needed

You will need the following parts:

  • 1x Intel® Edison
  • 1x ADC Block
  • 1x Base Block
  • 1x GPIO Block
  • 1x Edison Hardware Pack
Don't have the kit? No worries! You can still have fun and follow along with these experiments. We suggest using the parts below:
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
SparkFun Block for Intel® Edison - ADC

DEV-13327
19.9500$14.95
Intel® Edison Hardware Pack

COM-13187
$2.95
7
NOTE: If you do not have the kit, you will need to soldermale headers to the GPIO Block and female headers to the ADC Block.

Attach the Edison to the ADC Block

Open the Edison Hardware Pack. Put 2 screws through the mounting holes in the Edison, such that the screws' heads are facing up (we’ll call “up” the surface of the Edison with the “Intel® Edison” logo).

Screws through the Edison

Attach 2 standoffs to the screws sticking out the bottom of the Edison. Use the pocket screwdriver to carefully tighten the screws.

Standoffs on the Edison

Snap the Edison into the socket on the ADC Block. Make sure that the bottoms of the standoffs are protruding through the mounting holes on the ADC Block.

Edison and ADC Block

Screw 2 nuts onto the standoffs, securing the Edison to the ADC Block. You can use the pocket screwdriver to hold the screws in place while you tighten the nuts. Go slowly! The nuts can be tightened by hand, but it requires some finesse as they are quite small.

Nuts tightened on ADC Block

Attach the Base Block

Put 4 screws through the mounting holes on the corners of the ADC Block, such that the screws' heads are facing up (the same direction as the screws securing the Edison).

Screws in the ADC Block

Attach 4 standoffs to those screws. Use the pocket screwdriver to carefully tighten the screws.

Standoffs on the ADC Block

Snap the ADC Block (which has the Edison on top) into the socket on the Base Block. Make sure that the bottoms of the standoffs are protruding through the mounting holes on the Base Block.

Base Block attached to stack

Attach the GPIO Block

Attach 4 standoffs to the bottoms of the standoffs that are protruding from the mounting holes on the Base Block.

Standoffs attached to Base Block

Snap the Base Block (which has the ADC and Edison mounted on top) into the socket on the GPIO Block. Make sure that the bottoms of the standoffs are protruding through the mounting holes on the GPIO Block.

GPIO Block attached to stack

Screw the remaining 4 nuts onto the standoffs, securing the entire stack of Blocks together.

Nuts tightened on GPIO Block

Flip the entire stack around, and make sure it is in the following order:

  1. Edison
  2. ADC Block
  3. Base Block
  4. GPIO Block

Full Edison Block stack

Installing the Intel® XDK IoT Edition

The Intel® XDK is Intel’s integrated development environment (IDE) for creating, testing, and deploying mobile apps. We will be using the XDK IoT Edition, which was specifically designed to help users develop Node.js and HTML5 applications for the Intel® Edison and Intel® Galileo.

XDK Project view

NOTE: You will need to sign up for an Intel® Developer Zone Account to use the XDK. If you would prefer not to use the XDK, you can program Node.js applications directly in the Edison (you will just miss out on cool things like code completion, and you might have to skip some of the phone app exercises.). Visit Appendix B: Programming Without the XDK to learn how.

Download the Installer

The easiest way to install the XDK is to use the Intel® Edison Integrated Installer. This contains the XDK, drivers, and Flashing Tool (to update the Edison Firmware). Follow the link below and download the Installer for your operating system:

Intel® Edison Integrated Installer

WARNING: Make sure you do not have any Edisons plugged in to your computer for the installation!

Windows

Run the Installer that you just downloaded. You will see a splash screen as it unzips and prepares to install.

XDK Splash Screen

Once you get the “Welcome to Intel® Edison” screen, click Next. You might get a screen telling you to install “Java SE Runtime.” Just ignore it, as we will not be developing in Java (JavaScript is not the same as Java!).

Ignore the warning about installing Java

Click Next to continue the installation process. The ubiquitous License Agreement will pop up. Feel free to read it (or not).

Eek! A EULA!

Select I accept the terms of the license and click Next. You will then be presented with options to install. Deselect Update Image (we will do that separately in the next section), deselect Arduino Software, and select Intel® XDK IoT Edition.

We want to install the XDK IoT Edition

Click Next. On the next screen, make sure that you have enough space to install the programs. Leave the installation directory as default.

Installation directory for the XDK

Click Next, verify that the installation summary looks correct, and click Next again. Wait a few minutes while the installation completes.

NOTE: The installation process might attempt to install other drivers and programs. Accept all the defaults and choose to install additional programs. This is especially true on Windows where the Installer will want to install drivers, which are necessary for deploying code to the Edison. This includes things like "FTDI Drivers" and the "Phone Flash Tool Lite." Also, if the installation seems to have frozen, check for new windows that may have been opened.

Once the installation process is done, you will see a “Complete” window.

XDK installation is complete

Click Finish. If the Intel® Phone Flash Tool Lite opened during the process, you can leave it open if you wish (we will use it in the next section).

The installer or drivers may ask you to restart your computer.

OS X

The OS X Installer link will download a .tar.gz file. Double-click on that file to extract it. Double-click on the extracted file to run the installer.

Downloaded XDK IoT Edition

Follow the prompts, clicking Next to advance to the next screen. Accept the End User License Agreement when prompted. On the Installation summary screen, click Customize Installation.

Customize XDK IoT Edition install

Keep the destination folder (/Applications) at the default and click Next. You will be presented with the option to select the components to install. Deselect Arduino Software, and select Intel® XDK IoT Edition.

Select the right options for the Edison installer

Click Next and deselect Update firmware image (we will do that manually in the next section).

Do not update the Edison firmware now

Click Next and then Install. Wait while the installer downloads. You will then be prompted to install the Phone Flash Tool Lite.

Install the Phone Flash Tool Lite

Click Continue and follow the prompts. Once the XDK has finished installing, the XDK can be found under Applications.

The XDK can be found in Applications in OS X

Linux

Download the installer, double-click on the file to extract it, and navigate into the directory that it creates.

Install script for XDK

Double-click on the install.sh script (select Run if prompted) to begin the installer.

Install as root for XDK

If you want the XDK to be available to all users, select Install as root. Otherwise, select Install as root using sudo. Accept the terms of the End User License Agreement, and accept all defaults until you are presented with a summary screen.

Customize installation on XDK

Click Customize installation, and accept the default installation directory on the next screen. You will be presented with some installation options.

Select to install the XDK

Deselect Arduino Software, and select Intel® XDK IoT Edition. Click Next.

Do not update firmware for the Edison

Deselect Update firmware image, and click Next. There is a chance that your system might be missing some dependencies (e.g. “Dependencies not resolved”).

Phone Flash Tool Lite dependencies not resolved

If so, you will need to open a command prompt and install them using apt-get. For example, I am missing fping, gdebi, and p7zip-full. So, I entered the following commands:

sudo apt-get update
sudo apt-get install fping gdebi p7zip-full

Wait for those to finish installing, and click Re-check on the missing dependencies screen. You should be good to install.

XDK Installer summary

Click Install and wait for the installation to complete (clicking to accept any defaults on prompts). The XDK IoT Edition can be found in /usr/share/applications when the installation is complete.

XDK in installation directory

NOTE: If the Phone Flash Tool Lite failed to install, you can install it manually by following these instructions.

Updating the Edison Firmware

Most Edisons will ship with an older firmware (perhaps many months out of date). They will either contain bugs or simply not work with the latest version of the XDK IoT Edition. To remedy this problem, we highly recommend updating the firmware on the Edison.

To begin, download the latest firmware. Navigate to Intel’s site using the link below and click to download the latest release of the Yocto complete image.

Intel® Downloads Page

Intel downloads page

In this example, the latest firmware is “Release 2.1 Yocto complete image”

Once the download is complete, locate the file on your computer, and unzip it.

NOTE: If you did not install the XDK or do not wish to use the Phone Flash Tool Lite to update your Edison, you may try the Manual Firmware Update method in Appendix D.

Updating the Firmware with the Phone Flash Tool

If it is not open already, open the Intel® Phone Flash Tool Lite program that we installed in the last section.

[[Intel® Phone Flash Tool Lite](https://cdn.sparkfun.com/assets/learn_tutorials/4/4/8/FW_Update_01_annotated.png)

Click Browse, and navigate to the unzipped Edison firmware directory. Locate the FlashEdison.json file, and click Open. This will load the firmware into the Phone Flash Tool.

[[Edison firmware loaded into the Phone Flash Tool](https://cdn.sparkfun.com/assets/learn_tutorials/4/4/8/FW_Update_02_annotated.png)

Click the Start to flash button. The Phone Flash Tool will tell you to plug in your Edison. Plug the USB micro cable into the OTG Port on the Base Block, and plug the other end into an open USB port of your computer.

Edison Base Block OTG USB port

The Phone Flash Tool should begin to flash the Edison with a new firmware image.

Flashing the Edison's firmware

The updating process can take anywhere from 5-10 minutes. We recommend making a sandwich and catching up on web comics in that time. The Edison will restart once or twice after the installation is complete. Wait at least 2 more minutes after the update to allow the Edison to finish rebooting. Do not unplug the Edison in that time!

That’s it! You should see a “Flash success” message in the Phone Flash Tool. If this worked, you can close the Phone Flash Tool Lite, and move on to the next section.

Successful firmware update in the Edison

NOTE: If the Edison failed to flash, try the process again from the beginning. Close the Flash Tool Lite and unplug the Edison. Start the Flash Tool Lite again. This might take a few tries. If that still does not work, try the Manual Firmware Update method.

Using the XDK

If you have used other Integrated Development Environments before, the Intel® XDK IoT Edition might look familiar. If not, no worries! We will walk you through how to use the XDK (don’t worry, it’s not very complicated). If you would like to take a look at Intel’s official documentation on the XDK, it can be found here:

Intel® XDK IoT Edition Guide

Starting the XDK for the First Time

Start the Intel® XDK IoT Edition program, and you should be presented with a login screen.

XDK login or account creation screen

Click Sign Up if you do not already have an Intel Developer Zone Account, and follow the on-screen instructions to create a new account. You will need to accept another Terms and Conditions statement.

The Welcome Screen

Once you have created an account (or not), you will be presented with the welcome screen. In this screen, you can choose an existing project to work on or create a new one.

XDK welcome screen annotated

Click the image above for a larger view.

Creating a Project

To familiarize ourselves with the XDK IDE, we will create a blank project. Click on Templates under the Internet of Things Embedded Application tab. You will see a number of different templates appear that will help you get started with your IoT program. Select the Blank Template.

Selecting a template in the XDK

Click Continue, and you will be presented with a pop-up window to name your project. You can name it anything you want, as we are just using it to explore the IDE right now. To keep all my XDK projects together, I like to use the prefix “XDK_”. I will use “XDK_Blank” for this example.

Creating a new project in the XDK

Click Create. The project screen will greet you with a mostly empty JavaScript file.

NOTE: You might be asked to take a quick tour of the XDK when you first create a project. Feel free to do it or skip it.

The Project Screen

XDK project screen annotated

We use the XDK to write code. There are several tools available that help us do that: code examples, syntax completion, a debugging interface, and so on. Once we have finished writing code, we click the Upload button to send that code to the Edison. The Run button then tells the Edison to run the code we just sent to it.

By default, the Yocto image on the Edison contains an “XDK Daemon.” A daemon is a computer program that runs in the background (at least according to Wikipedia). The XDK Daemon begins running as soon as the Edison boots and listens for a connection from a host computer (i.e. one running the XDK IoT Edition). It knows how to receive and store new code, and it will accept commands from the host computer to run, stop, and debug that program.

NOTE: You can click the word PROJECTS at the top-left of the window to return to the navigation screen.

Connecting to WiFi

We will want connect our Edison to a local WiFi network if we want to program it using the XDK or complete some of the experiments that require Internet access.

NOTE: Alternatively, you can use a USB Network to program the Edison from the XDK. Refer to Appendix C to see how to use a USB network with your Edison. Note that without a WiFi connection, you will not be able to complete the exercises that require Internet access.

Connecting Over Serial

Unplug the USB cable from the OTG port on the Base Block, and plug it into Console port.

Edison Base Block Console USB port

If it is not already open, start the XDK, and create a blank project (like we did in Using the XDK). Click on the Serial Terminal tab.

Serial terminal in XDK

At the very bottom, click the drop-down list for Port and select the Edison device. This will change depending on the operating system. For example, it might be /dev/tty.usbserial-A402IXA0 in OS X, /dev/ttyUSB0 in Linux, or COM78 in Windows. Note that in Windows, you want COMxx[FTDI], not the Standard Serial Port option.

Selecting a serial terminal in XDK

Make sure that the Baud Rate is 115200, Data Bits is 8, Stop Bits is 1, and Parity is “none.” Click Connect, and you should see the Edison’s terminal login appear.

Connecting to Edison's serial terminal with the XDK

Getting on the Internet

Click in the Serial Terminal window and log in to the Edison:

Username: root

Hit ‘enter’ (there is no password). You should be presented with a root command prompt.

Logging in as root

Enter configure_edison --setup. You will be walked through a series of steps. The first will ask you to create a password.

Configure the Edison

We definitely recommend you set a password! It can be anything you want, so long as you can remember it. If you don’t set a password, evil hackers might be able to control your lights from their car. Or read your emails. That would be bad.

Press ‘enter’ and enter your password again. On the next screen, you will be asked to rename the Edison. You can give it a unique name or just press ‘enter’ to keep the default name. I shall call mine squishy.

My Edison called squishy

The Edison will ask you to confirm the name. Type ‘y’ and press ‘enter’. You will then be asked to set up WiFi. Enter ‘y’ again.

Yes, we want to set up WiFi on the Edison

Wait while the Edison scans for networks. You will then be presented with a list of available networks.

Available WiFi access points

Type the number of the network you would like to join and press ‘enter’. Enter ‘y’ to accept the network, and enter the password for that network.

Enter the password for the WiFi network

The Edison should automatically connect to the network. Enter ping 8.8.8.8 to try pinging one of Google’s Public DNS servers.

Successful pings from the Edison

You should see a few responses in the form of “bytes received from 8.8.8.8.” Press ‘ctrl+c’ to stop the pinging. You can get the IP address of the Edison by entering ifconfig.

Edison ifconfig

Under the wlan0 entry, make a note of the inet addr. In my case, it is 10.8.0.171. You can use this to connect to your Edison manually from the IoT Device drop-down menu if, for example, the Bonjour service is not running (if you ran the Installer and accepted all the defaults, Bonjour should have been installed).

NOTE: If you restart your Edison, it should auto-connect to the last network you set. However, you might not get the same IP address. We recommend connecting over serial and typing ifconfig to see that address if you need it. You can also give your Edison a static IP address, if you so desire. See here to lear more about networking in Linux.

Experiment 1: Hello, World!

Introduction

We realize that starting with “Hello, World!” is a cliché in the programming world, but it really is the perfect starting place with the XDK and Edison. We spent quite some time installing the XDK, flashing new firmware, and configuring the Edison. We can test all these things with one line of code!

Parts Needed

You will need the Edison and Block stack that we constructed in Building the Block Stack section.

Suggested Reading

  • JavaScript Syntax– Whether you are new to JavaScript or a seasoned developer, you might want to look at how JavaScript statements are structured. For example, JavaScript uses semicolons.
  • Oject-Oriented Programming (OOP)– JavaScript relies on objects to get work done. Reading about the history of OOP might be enlightening and entertaining.

Concepts

A Very Light Introduction to Objects

In JavaScript almost everything is an object. What is an object? In the real world, an object is just another word for a thing. A dog, for example, is a type of object.

A dog object

A dog has properties, such as a breed, a fur color, a name, and so on. Dogs can also do things, like bark, sleep, play, etc.

OK, so how does this translate to the programming world? In most object-oriented languages, an object is a collection of data (bytes stored somewhere on the computer) that has been grouped together and wrapped up in a way that makes for easy access. If we wanted to make a JavaScript version of our dog, we might write something like:

language:javascript
var dog = {
    name: "Roland",
    color: "fawn",
    bark: function() {
        console.log("woof");
    }
};

In this example, we created a variable (as noted by the keyword var) called dog. A variable is a way to store things. In this case, we are storing our object (a collection of properties) in a storage container called dog.

All of the properties for this object are defined between the outside set of curly braces {}. We create a property called name and assign it the value "Roland". If we wanted to get the name of our dog object, we could access that property with:

language:javascript
dog.name;

Calling dog.name results in “Roland”.

In addition to our name and color properties, we also defined a function as a property. If we called

language:javascript
dog.bark();

the dog would do something. Functions are actions! They cause the object to do something. The parentheses () after dog.bark let us know that it is a function. They can also be used to pass parameters to the function, which we will see in a minute. Because bark() is a function inside an object, it is known as a method (functions not part of objects are just called functions).

If we dig into the bark() method, we see that it contains console.log("woof");. console is a special object that is known by most implementations of JavaScript (i.e. it is an object that always exists when we run the program). .log() is a method of the console object. By calling console.log() we can print something to the screen (assuming we have access to some kind of text output console).

"woof" is a parameter, which is a value that is passed to a function. In this case, “woof” is a string (as noted by the double quotes), which is a collection of characters. The function then, ideally, uses that value in its own code. In this case, console.log("woof") prints the word woof to the screen.

Ultimately, calling dog.bark(); prints woof to the screen.

This might be a lot to take in, but never fear! We will revisit these concepts over the course of these experiments. For now, know that objects are containers for properties and methods. We will be using the special console object to output text to the screen.

Hardware Hookup

We won’t need any new hardware. Just connect the USB cable from your computer to the Console Port on the stack you made in Building the Block Stack.

Edison Base Block USB Console port

The Code

Open the XDK, and create a new project. Use the Blank Template, and give it an appropriate name (we’ll call this one “XDK_Hello”). If you need a refresher on creating projects, see Using the XDK.

NOTE: The Edison is remotely programmable, but your host computer must be on the same network (subnet) as the Edison if you want to use the XDK (i.e. both your computer and Edison are connected to the same WiFi network). Alternatively, you can use a USB cable to create a USB network between your computer and the Edison.

The first thing we want to do is connect to our Edison. To do that, click the drop-down list by IoT Device, and select your Edison device.

Select Edison device

NOTE: If the Edison device does not appear automatically (e.g. you don't have Bonjour installed), then you can select Add Manual Connection and fill in the IP address of the Edison you got from Connecting to WiFi.

You should be presented with a connection screen. Type in the password you set for the Edison in the Password field.

IoT Device connection screen

Click Connect. If you get presented with a message claiming that the “Intel XDK Daemon is old” or that you need to sync clocks with the Edison, choose to Update the Dameon or Sync as appropriate and follow the prompts.

What do you mean my XDK daemon is old?

Once you have updated, synced, and connected, you should see a message in the console of the Intel XDK IoT tab.

XDK connected to Edison

In main.js, add the following line:

language:javascript
console.log("Hello, World!");

Find and click the Upload button.

Upload code to the Edison

If you are presented with a message exclaiming that you have “Modified Project Files,” click Save and Proceed.

In the console, you should see the message “Upload Complete.” Press the Run button.

Run code on the Edison

What You Should See

The phrase “Hello, World!” should appear in the console.

Edison Hello World

If you see this, feel free to celebrate. We’ll wait a moment while you do that.

Why is this simple phrase monumental? Well, it means all our preparing and configuring worked! We wrote a simple program, sent it to the Edison, and had the Edison run it. Cool.

Code to Note

The Console Object

console is a special object that has been pre-defined elsewhere in our JavaScript environment. It outputs to standard output, which is a text display device (real or virtual) for most computer systems.

The Edison relies on Node.js to run JavaScript programs. More information about the console object can be found in the official documentation.

Methods

We mentioned methods briefly in our introduction to objects. In this exercise, we used the .log() method, which takes input in the form of a string (a parameter) and displays it on a new line in the console. The Node.js documentation contains a section on .log().

Comments

There are different ways to make comments in your code. Comments are a great way to quickly describe what is happening in your code.

// This is a comment - anything on a line after "//" is ignored by the computer.

/* This is also a comment - this one can be multi-line, but it must start and end with these characters */

Troubleshooting

  • The Edison won’t connect– This is possible if the Edison is not powered or configured properly. See the “Edison won’t connect” section in the Appendix A: Troubleshooting.
  • Code will not upload– Make sure the Edison is on the same network as your computer and you have selected your Edison from the IoT Device drop-down menu in the XDK.
  • Nothing prints on the console– Make sure that the Edison is connected. Additionally, if you see any errors on the console, read them carefully, as they will often tell where to look in your code (for example, you might have forgotten the quotation marks around “Hello, World!”).
  • Nothing works!– Don’t worry! We have an awesome tech support staff to help you out if there is something wrong. Please contact our tech support team.

Going Further

Now that you see how to connect your Edison to the XDK, upload code, and run a program, we will move on to more advanced topics including connecting other pieces of hardware to the Edison Block stack. After each experiment, we will give you a few challenges to try on your own as well as some suggested reading.

Challenges

  1. Remember the description of the dog object in the beginning of this chapter? Copy the definition of the dog object (the snippet of JavaScript code) into the XDK. Write some code that has the dog bark (e.g. you will see woof appear in the console). Hint: you will need to use console.log().
  2. Using the same dog object example, print out the dog’s name and color to the console.

Digging Deeper

Experiment 2: Pushing Some Buttons

Introduction

In the previous exercise, we tested the connection to the Edison and showed that we could upload code. Now, we can move on to more interesting circuits and examples. In this section, we introduce the humble push button. We connect it to one of the Edison’s general-purpose input/output (GPIO) pins and write some code that does something whenever the button is pushed.

This experiment has 2 parts. Both parts use the same hardware, but each has its own code. We recommend you try them both to get an understanding of the different ways to use button pushes.

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x Push Button
  • 1x 1kΩ Resistor
  • 4x Jumper Wires

1k resistor

The 1kΩ resistor has the color bands brown, black, red, gold

Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
Tactile Button Assortment

COM-10302
$4.95

Suggested Reading

Concepts

Functions

We mentioned briefly in the last section that functions are pieces of code that do things. To make this more clear, a function is a block of code created to perform a particular task. Functions are useful because they can be written once and called many, many times from other parts of code (we call this code reuse).

In our two code examples below, we will write our own functions and then call them. In JavaScript, functions looks like this:

language:JavaScript
function doSomething( /* parameters */ ) {
    /* Things happen here */
}

We know it is a function because we used the function keyword. Thanks for making this explicit, JavaScript. We can also have 0 to any number of parameters in our function. Parameters are variables that are used to store pieces of information passed to the function. For example:

language:JavaScript
function saySomething(thing) {
    console.log(thing);
}

saySomething("Hi");

We first created a function that outputs something to the console. In this case, the function accepts the parameter thing, which becomes a variable. We can access the contents of that variable by writing thing.

Then, we call our function by writing saySomething(). In between the parentheses, we wrote the string "Hi". This string is passed to the saySomething() function as a parameter and assigned to the variable thing. We then print the contents of thing (“Hi” in this example) to the console.

If we wanted to print something else, we could write saySomething("Something else");. And that’s a simple form of code reuse!

Libraries

A particularly grand library

OK, not THAT kind of library

Libraries are pieces of code that have been packaged up for easy reuse. Often, they are written by someone else (or a group of people).

Node.js (the runtime environment that runs our code on the Edison) uses modules, which are very similar to libraries. Modules are just other pieces of code that we can reuse in our code. In these experiments, we rely heavily on MRAA, which is a library (and subsequent Node.js module) created by Intel and allows us to easily communicate with the hardware pins on the Edison.

We can import the MRAA module with the line

language:JavaScript
var mraa = require('mraa');

With that, all the objects, variables, and functions in the MRAA module are loaded into the variable mraa. We can access those objects, variables, and functions by calling mraa. For example, mraa.Gpio() creates a new GPIO pin that we can access.

The Pull-Up Resistor

We can use a resistor to set a default state of a pin on a microcontroller (or, in this case, the Edison). The pull-up resistor, specifically, sets the state of the pin to a voltage (VCC in the diagram below). For our circuit, we will be using 3.3V as the high voltage. Low will be ground (GND or 0V).

Example of a pull-up resistor

When the switch (or button) is open (as in the diagram), the input pin is VCC. Because little or no current flows through R1, the voltage at the pin is the same (or very nearly the same) as VCC. We will say that the pin is in the “high state” or “logic ‘1’”.

When the switch (or button) is closed, the input pin is the same voltage as GND (0V). The switch creates a short circuit to GND, which causes some current to flow from VCC, through R1, to GND. However, because of the short circuit, the input pin has the same voltage as GND. We will say that the pin is in the “low state” or “logic ‘0’”.

Hardware Hookup

Your kit comes with a bunch of different color push button. All push buttons behave the same, so go ahead and use your favorite color! Follow the Fritzing diagram below.

NOTE: We are using GP14 on the GPIO Block, which connects to GPIO pin 14 on the Edison's 70-pin Hirose connector (see here for the pinout). However, the MRAA library uses a different numbering scheme. GP14 is actually pin 36 according to MRAA. The GPIO pin to MRAA pin mapping can be found in Appendix E: MRAA Pin Table. Find the GPIO number you are using on the left-most column and lookup the MRAA number on the next column. The MRAA number is what you will use in software.

Fritzing Diagram

Edison SIK button Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Tips

The leads across each other on the push buttons are always connected to each other. The leads on the same side are only connected when button is pressed.

Push button connections

Part 1: Polling

The Code

language:JavaScript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 2 - Part 1: Pushing Some Buttons
 * This sketch was written by SparkFun Electronics
 * October 27, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * This is a simple example program that displays the state of a button
 * to the console.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA module
var mraa = require('mraa');

// Set up a digital input/output on MRAA pin 36 (GP14)
var buttonPin = new mraa.Gpio(36);

// Set that pin as a digital input (read)
buttonPin.dir(mraa.DIR_IN);

// Call the periodicActivity function
periodicActivity();

// This function is called forever (due to the setTimeout() function)
function periodicActivity() {

    // Read the value of the pin and print it to the screen
    var val = buttonPin.read();
    console.log('Button is ' + val);

    // Wait for 250 ms and call this function again
    setTimeout(periodicActivity, 250);
}

What You Should See

Try pushing the button.

Button connected to the Edison

The console should start outputting “Button is 1”, which means that the pin connected to the button is currently in the high state (3.3V, logic ‘1’). When you push the button (hold it down for a second), the console should show “Button is 0”, which means that the pin is in the low state (0V, logic ‘0’).

Polling button output

Code to Note

In JavaScript, functions are objects. Say what? I know it is weird to think about, but they are. The good news is that we can pass functions (like objects) as parameters to other functions. For example, we pass periodicActivity (a function) to setTimeout (another function), which causes periodicActivity to be called every 250 ms (in this example).

Additionally, note that we told MRAA that we want to use pin 36. Pin 36 is defined by MRAA and mapped to GP14, which is the pin definition according to the Edison hardware. Knowing which MRAA pin maps with which GP pin can be confusing, so we crated a nice table in Appendix E. The Edison pinout can be found here.

Part 2: Interrupt Service Routine

The Code

language:JavaScript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 2 - Part 2: Interrupt Service Routine
 * This sketch was written by SparkFun Electronics
 * October 27, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * This is a simple example program that prints an incrementing number
 * to the console every time a button is pushed.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA module
var mraa = require('mraa');

// Set up digital input on MRAA pin 36 (GP14)
var buttonPin = new mraa.Gpio(36);
buttonPin.dir(mraa.DIR_IN);

// Global counter
var num = 0;

// Our interrupt service routine
function serviceRoutine() {
    num++;
    console.log("BOOP " + num);
}

// Assign the ISR function to the button push
buttonPin.isr(mraa.EDGE_FALLING, serviceRoutine);

// Do nothing while we wait for the ISR
periodicActivity();
function periodicActivity() {
    setTimeout(periodicActivity, 1000);
}

What You Should See

You should not see anything when you first run the program. Press the button, and the word “BOOP” should appear along with a number. Press the button again, and that number should increment by 1.

Boop

Code to Note

Interrupt service routines (ISRs) are important in the world of embedded electronics. It is very similar to JavaScript’s notion of event-driven programming. When a user or some other external force performs an action, the program responds. In this case, whenever a button was pushed, the serviceRoutine() function gets called.

As in the previous polling example, we use a function as a parameter. We pass the function serviceRoutine to the buttonPin.isr() function. We use mraa.EDGE_FALLING to declare that serviceRoutine should be called whenever the pin’s voltage goes from high (3.3V) to low (0V).

Troubleshooting

  • The Edison won’t connect– This is possible if the Edison is not powered or configured properly. See the “Edison won’t connect” section in the Appendix A: Troubleshooting.
  • Nothing happens when the button is pushed– Double-check the wiring. Often, a jumper wire is off by 1 hole!

Going Further

Challenges

  1. Add a second button so that when the first button is pushed, it prints “BOOP” to the console, and when the second button is pushed, it prints “BEEP” to the console.
  2. You might have noticed that pushing the button on the second example causes more than one “BOOP” to appear (if not, try pushing the button many times to see if you can get more than one “BOOP” to appear per button push). This is a phenomenon known as bouncing. Modify the Part 2 example to prevent this from happening (known as debouncing).

Digging Deeper

Experiment 3: Blinky

Introduction

Often, blinking an LED is the first step in testing or learning a new microcontroller: a veritable “Hello, World!” of embedded electronics. However, the GPIO Block requires that we introduce a new component, the transistor, into the mix. As a result, we saved the blinky example for the third experiment.

We will connect an LED to the Edison (using the GPIO Block and a transistor). With some JavaScript, we can control that LED by turning it on and off.

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x RGB LED
  • 1x NPN Transistor
  • 1x 1kΩ Resistor
  • 1x 100Ω Resistor
  • 5x Jumper Wires

100 Ohm resistor

The 100Ω resistor has the color bands brown, black, brown, gold

1k resistor

The 1kΩ resistor has the color bands brown, black, red, gold

Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
LED - RGB Diffused Common Cathode

COM-09264
$1.95
2
Transistor - NPN (2N3904)

COM-00521
$0.5

Suggested Reading

Concepts

The Transistor

The GPIO Block is not capable of sourcing more than a few milliamps, which is not enough to fully light up an LED. To do that, we will use a transistor. A transistor is a device that can be used to amplify or switch electrical current. We will be using a bipolar junction transistor (BJT), which allows current to flow through the collector and emitter pins whenever a (much smaller) current flows into the base pin.

In this experiment, we will connect the base of the BJT to GP12 on the GPIO Block. When the GP12 pin goes high (3.3V), this causes a little bit of current to flow from GP12 through the base, which turns the transistor on. This allows current to flow from the 3.3V supply (also on the GPIO Block), through the collector, and out the emitter. This current then flows through the 100Ω resistor and LED, turning the LED on.

Transistor switch for LED

We can calculate the amount of current flowing through the LED, as we want to make sure it is not over 20mA, as per the RGB LED datasheet. To do that, we need to figure out what the voltage drop across the 100Ω resistor. Starting with 3.3V, we can determine that the voltage across the collector and emitter (Vce) is 0.2V (Vce(sat) in the datasheet) when the transistor is fully on. Again from the LED’s datasheet, we see that that typical drop across the red LED is 2V. As a result, the voltage drop across the resistor can be calculated:

Calculating the voltage drop across the resistor

Knowing that the drop across the resistor is 1.1V, we can use Ohm’s Law (V = I x R) to calculate the current flowing through the resistor:

Finding the current through the resistor

Current through limiting resistor

How to Use Logic Like a Vulcan

One of the things that makes the Edison so useful is that it can make complex decisions based on the input it’s getting. For example, you could make a thermostat that turns on a heater if it gets too cold, or a fan if it gets too hot, and it could even water your plants if they get too dry. In order to make such decisions, JavaScript provides a set of logic operations that let you build complex “if” statements. They include:

==EQUIVALENCEA == B is true if A and B are the SAME.
!=DIFFERENCEA != B is true if A and B are NOT THE SAME.
&&ANDA && B is true if BOTH A and B are TRUE.
||ORA || B is true if A or B or BOTH are TRUE.
!NOT!A is TRUE if A is FALSE.!A is FALSE if A is TRUE.

You can combine these functions to build complex if() statements. For example:

language:c

if ((mode == heat) && ((temperature < threshold) || (override == true))) {
    turnOnHeater();
}

…will turn on a heater if you’re in heating mode AND the temperature is low, OR if you turn on a manual override. Using these logic operators, you can program your Edison to make intelligent decisions and take control of the world around it!

In addition to the comparator ‘==’ and ‘!=’, JavaScript also has the strict comparators ‘===’ and ‘!==’ where the two values being compared need to be the same type (e.g. both a string). See this page to learn more about JavaScript comparators.

Hardware Hookup

Fritzing Diagram

Red LED with Edison Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Tips

RGB LED

You can use a set of needle nose pliers to bend the LED’s leads and a pair of cutters to fit the LED in the breadboard. Note that there is a flat side on the plastic ring around the bottom of the LED. This denotes the side with the pin that controls the red color. See this tutorial to learn more about polarity.

Common cathode RGB LED

NPN Transistor
WARNING: The 2N3904 transistor and TMP36 temperature sensor look very similar! Examine the flat face of the TO-92 packages very carefully and find one that says 2N 3904.

Note that the flat face with the ‘N’ of the transistor in the Fritzing diagram matches up with the flat face (with the writing) of the physical part. With the flat edge facing you, the pins are as follows:

Annotated 2N3904 NPN transistor

The Code

language:JavaScript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 3: Blinky
 * This sketch was written by SparkFun Electronics
 * October 29, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Blink an LED connected to GP12 (need a transistor if using the Base Block).
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA module
var mraa = require('mraa');

// Set up a digital output on MRAA pin 20 (GP12)
var ledPin = new mraa.Gpio(20);
ledPin.dir(mraa.DIR_OUT);

// Global variable to remember the LED state
var led = 0;

// Call this function over and over again
periodicActivity();
function periodicActivity() //
{
    // Switch state of LED
    if (led === 0) {
        led = 1;
    } else {
        led = 0;
    }

    // Turn the LED on
    ledPin.write(led);

    // Wait for 500 ms and call this function again
    setTimeout(periodicActivity, 500);
}

What You Should See

Upload and run the program. The LED should start flashing red.

Edison flashing an LED

Code to Note

After we declare the ledPin as an output with mraa.DIR_OUT, we create the variable led that stores the state of the led (‘1’ for on and ‘0’ for off). Because this variable (and similarly mraa and ledPin) is declared outside of any object or function, they are considered global variables, which means they can be accessed by any function, object, etc. in the entire program. In most programming circles, using global variables is considered very bad practice. However, we rely on them in most of our examples because:

  1. JavaScript makes creating and accessing global variables very easy. This is not a legitimate excuse, but it does make the examples easier to follow.
  2. Most of the examples are simple, 1-file programs where we can keep track of all the global variables. Global variables are still used by embedded programmers, as most embedded programs are relatively small and they allow for different types of CPU, RAM, or storage optimization.

Troubleshooting

  • The Edison won’t connect– This is possible if the Edison is not powered or configured properly. See the “Edison won’t connect” section in the Appendix A: Troubleshooting.
  • The LED doesn’t flash– Once again, check the wiring. Make sure you are connecting the base of the transistor to GP12 (through a 1kΩ resistor). Additionally, you can add some console.log() statements in the code to see if certain parts are being executed.

Going Further

Challenges

  1. Make the LED turn on for 1 second and off for 1 second.
  2. Make the LED turn on for 200 ms and off for 1 second.
  3. Add a button (like in the previous experiment). Create a program such that the LED turns on only when the button is pushed.

Digging Deeper

Experiment 4: Email Notifier

Introduction

While flashing an LED is not the most interesting activity, we could use the LED as a way to notify us if something is happening. For example, we could turn on an LED if we have a new email. That way, we would know that we needed to check our inbox!

To do this, we will have the Edison log in to an email account, read the number of unread emails, and turn on an LED if it is over 0.

NOTE: This example shows how to connect to Gmail and Yahoo mail servers. If you are not using one of those, you still might be able to connect (see here for a list of IMAP servers), but only Gmail and Yahoo have been tested. Also, you will need to enter your username and password as plain text into the code. It's a fun project, but you don't have to do it if you are not comfortable with that!

Parts Needed

We’ll be using the same circuit as in the previous example, so you don’t need to build anything new! In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x RGB LED
  • 1x NPN Transistor
  • 1x 1kΩ Resistor
  • 1x 100Ω Resistor
  • 5x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
LED - RGB Diffused Common Cathode

COM-09264
$1.95
2
Transistor - NPN (2N3904)

COM-00521
$0.5

Suggested Reading

Concepts

External Modules

In the previous few examples, we have been relying on the MRAA module to control various hardware from the Edison. MRAA comes pre-installed on the Edison, so we did not have to perform any extra steps to install it. However, in this example, we will use node-imap, which contains several useful functions for connecting to Internet Message Access Protocol (IMAP) servers and retrieving email.

If we were to log in to the Edison via SSH or serial terminal, we could install Node.js packages (e.g. modules) using the npm command (e.g. npm install imap). However, with the XDK, we can tell the IDE to install necessary modules automatically whenever we upload code. This is accomplished by adding the library name to a list of dependencies in the project. The specifics on how to do this can be found in “The Code” section.

Callbacks

MicroTAC Elite VIP cellular phone

I wonder if caller ID was a feature

A callback is a piece of code (often a function) that is expected to be called by another piece of code at a convenient time. A popular way to use callbacks in web programming is to assign a function to a mouse click event. For example:

language:JavaScript
element.on('click', myFunction);

myFunction() {
    console.log("Hi!");
}

Whenever a user clicks on the web page element (called element in this example), myFunction() gets called. In this instance, myFunction() is the callback, and our assignment, element.on('click', myFunction);, is known as creating an event handler. See here to learn more about the .on() event handler.

Hardware Hookup

The circuit is the same as in the previous experiment.

Red LED with Edison Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

The Code

Create a new project in the XDK. Click on package.json in the files browser on the left pane. Add the line

language:JavaScript"imap": "0.8.16"

under "dependencies". This will tell the XDK to download and install the node-imap v0.8.16 module before running the program.

Adding a new library

NOTE: If you are using Gmail, you will need to go to the account security settings page and turn access for less secure apps to ON. We recommend turning it off once you are done with this exercise (unless you want to keep a permanent email notifier!).

Copy the following code into main.js. If you are not using Gmail, you can comment out (or delete) the part labeled “Set email credentials (Gmail)”. If you are using Yahoo, you will want to uncomment the part labeled “Set email credentials (Yahoo)”.

Finally, change the <username> and <password> parts to your actual email username and password.

language:JavaScript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 4: Email Notifier
 * This sketch was written by SparkFun Electronics
 * October 29, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Connect to an email service and turn on an LED if there are any unread
 * emails.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA and IMAP modules
var mraa = require('mraa');
var Imap = require('imap');

// Set up a digital output on MRAA pin 20 (GP12)
var ledPin = new mraa.Gpio(20);
ledPin.dir(mraa.DIR_OUT);

// It's usually a good idea to set the LED to an initial state
ledPin.write(0);

// Global LED variable to know if the LED should be on or off
var led = 0;

// Set email credentials (Gmail)
// Turn on "Acess for less secure apps" in Google account settings
// https://www.google.com/settings/security/lesssecureapps
var imap = new Imap({
  user: "<username>@gmail.com",
  password: "<password>",
  host: "imap.gmail.com",
  port: 993,
  tls: true
});

// Set email credentials (Yahoo)
/*var imap = new Imap({
  user: "<username>@yahoo.com",
  password: "<password>",
  host: "imap.mail.yahoo.com",
  port: 993,
  tls: true
});*/

// Open the mail box with the name "INBOX"
function openInbox(cb) {
  imap.openBox("INBOX", true, cb);
}

// This is called when a connection is successfully made to the IMAP server.
// In this case, we open the Inbox and look for all unread ("unseen")
// emails. If there are any unread emails, turn on a LED.
imap.on('ready', function() {
    openInbox(function(err, box) {
        if (err) throw err;

        // Search for unread emails in the Inbox
        imap.search(["UNSEEN"], function(err, results) {
            if (err) throw err;

            // Print the number of unread emails
            console.log("Unread emails: " + results.length);

            // If there are unread emails, turn on an LED
            if (results.length > 0) {
                ledPin.write(1);
            } else {
                ledPin.write(0);
            }

            // Close the connection
            imap.end();
        });
    });
});

// If we get an error (e.g. failed to connect), print that error
imap.on('error', function(err) {
    console.log(err);
});

// When we close the connection, print it to the console
imap.on('end', function() {
  console.log("Connection closed.");
});

// Call this function over and over again
periodicActivity();
function periodicActivity() //
{
    // Perform a quick connection to the IMAP server and look for unread emails
    imap.connect();

    // Wait for 10 seconds before checking for emails again
    setTimeout(periodicActivity, 10000);
}

What You Should See

When uploading the code, you might see some notifications that the XDK is downloading and installing npm packages. Just be patient while the packages are installed.

XDK installing npm packages

When you run the code, it should connect to your email account and print to the console the number of unread emails every 10 seconds.

Unread emails

I really should get in the habit of checking my emails more often

If you have one or more unread emails, the red LED should come on.

Edison email notifier

Code to Note

Callbacks

I know that we talked about callbacks in the Concepts section, but now we get to see them in action. The node-imap package heavily relies on them, so it is important to get used to them if you plan to use that package in the future.

imap.on is used several times. This function gets called when something particular happens in our program. These are known as “Connection Events” according to the Application Program Interface (API) documentation. We can define particular connection events using strings.

For example, imap.on('ready', function() {...}); allows us to define a function (as noted by the function() keyword) that is called whenever a successful connection is made with the IMAP server.

imap.on('error', function() {...}); is called if there is a problem making a connection.

imap.on('end', function() {...}); is called whenever the connection with the server is closed.

There is another seemingly odd callback. In our imap.on('ready',...) code, we call openInbox(function(err, box) {...});. A few lines above, we define the openInbox() function, which tells the imap object to open our inbox and then call another function (as denoted by cb for “callback”). This callback function (cb) is the function we defined inside openInbox(function(err, box) {...});. So yes, we call a function that accepts another function as a parameter, which then calls that function as a callback. Don’t worry if this was confusing; it is a bit hard to follow. Knowing how to use the .on() callback functions is the most important part of this exercise.

Error Handling

Being able to appropriately deal with errors is a very useful ability in a program. The example relies on if (err) throw err; to determine if an error has occurred (e.g. could not connect to the IMAP server).

If we dig into the node-imap code, we would likely find a few catch statements. if (err) only executes the second part (throw err) if an err actually exists (not null or undefined). throw stops execution within that loop, function, etc., and program control is passed to the first catch statement it finds within the calling stack (e.g. look for a function that called the callback withing a try/catch statement).

If an error occurs, the node-imap module calls our callback function imap.on('error', function() {...});, which lets us handle the error. In this case, all we do is print the error to the console.

Troubleshooting

  • It won’t connect to the IMAP server– This could be caused by several reasons:
    • Make sure your Edison has Internet access
    • Ensure you are using the correct IMAP server settings (Gmail and Yahoo examples are given in the code)
    • Check that your email and password are correct in the code
  • The LED won’t come on– As always, double-check the wiring. Make sure you are seeing Unread emails: is appearing in the console, and that number is at least 1. Be patient, as it can take a few seconds for the program to make a connection to the IMAP server.

Going Further

Challenges

  1. Have the LED flash rapidly when there are unread emails.
  2. Have the LED turn on only when there are unread emails from a particular sender (e.g. a friend or your boss). You will need to carefully read the examples in the node-imap documentation.
  3. When you receive a new email, print its contents to the console and flash the LED. Hint: Take a look at the mail(...) callback in Connection Events in the node-imap documentation.

Digging Deeper

Experiment 5: Web Page

Introduction

We know that we are exhausting this one LED circuit, but it really does prove useful in showing different features of the Edison. Hopefully, it spawns some cool project ideas for you! Just remember, if you can blink an LED, you can connect that output to any number of electrical devices. Relays, for example, are great for controlling more powerful components, like light bulbs, ceiling fans, and toasters. Additionally, going from an output (e.g. an LED) to an input (e.g. a button) is not too difficult.

Now that we have reached out to our email inbox to light an LED, why don’t we serve up a web page that allows us to control that LED? This experiment is divided into 2 parts. In the first section, we will create a basic web page that we can navigate to from any computer on the network. In the second section, we add a button to that page to allow control over an LED attached to the Edison.

Parts Needed

We’ll be using the same circuit as in the previous example, so you don’t need to build anything new! In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x RGB LED
  • 1x NPN Transistor
  • 1x 1kΩ Resistor
  • 1x 100Ω Resistor
  • 5x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
LED - RGB Diffused Common Cathode

COM-09264
$1.95
2
Transistor - NPN (2N3904)

COM-00521
$0.5

Suggested Reading

  • How Web Servers Work– A look at how information is served to your computer when you browse a web site
  • Introduction to HTML– HyperText Markup Language (HTML) is a fairly old computer language still in use today to create web pages. We will be using some HTML to make our web page.
  • WebSockets– We will use the socket.io module in the second part of this exercise to implement WebSockets. This will allow us to create a connection between the Edison and another computer so we can simple commands (like toggle an LED).

Concepts

Browsing to a Web Page

Connected computers and the Internet

It’s like a series of tubes!

In simplest terms, when you “browse to a web page,” your computer makes a request to a remote server somewhere on the Internet. The actual server (physical computer) you are accessing can be anywhere in the world (assuming it also has Internet access). The server then sends an HTML file back to your computer, which your browser (Chrome, Safari, Firefox, IE, etc.) parses and displays the HTML elements in a human-readable format.

We will be constructing a very simple web page on our Edison using HTML. We will use the Node.js http module to create this page and host it as a web server from within the Edison. As a result, we can browse to the Edison from any computer on the same network, and it will show us a web page!

WebSockets

WebSockets is another protocol for sending and receiving messages across the Internet (or other networked computers). As long as Transmission Control Protocol (TCP) can be realized on the network, WebSockets can be used to transmit messages. WebSockets is similar to HyperText Transfer Protocol (HTTP) in that they both rely on TCP and are used for transmitting data across a network. However, WebSockets uses far less overhead and can be used for communication between client and server with lower latency than HTTP. See this article to read more about WebSockets vs. HTTP.

In the second part of this experiment, we rely on the socket.io module to handle WebSockets in JavaScript for us. This allows us to create a connection from our browser (on our host computer) to the web server running on the Edison and send messages back and forth. We will use a simple message that causes an LED connected to the Edison to turn on and off.

Hardware Hookup

The circuit is the same as in the previous experiment.

Red LED with Edison Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Part 1: A Simple Web Page

The Code

language:JavaScript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 5 - Part 1: Web Page
 * This sketch was written by SparkFun Electronics
 * November 1, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Serves a very simple web page from the Edison.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the HTTP module
var http = require('http');

// Which port we should connect to
var port = 4242;

// Create a web server that serves a simple web page
var server = http.createServer(function(req, res) {
    res.writeHead(200);
    res.write("<!DOCTYPE html>                                             \<html>                                                      \<head>                                                      \<title>My Page</title>                                  \</head>                                                     \<body>                                                      \<p>This is my page. There are many like it,             \
                    but this one is mine.</p>                               \</body>                                                     \</html>");
    res.end();
});

// Run the server on a particular port
server.listen(port, function() {
    console.log('Server listening on port ' + port);
});

What You Should See

Upload and run the code on the Edison. The console should notify you with Server listening on port 4242. Open a web browser and navigate to http://<Edison's IP address>:4242. You can find the Edison’s IP address from the XDK under the IoT Device: drop-down menu. For example, my Edison had the IP address of 10.8.0.171, so I navigated to http://10.8.0.171:4242 in my browser.

Edison hosting a web page

Viewing our web page from the host computer

If you have another computer or a smartphone that is on the same network as the Edison, you can also try navigating to the same page.

alt text

Viewing the same web page from a smartphone

Note that we are not using the LED in this part, that’s next!

Code to Note

This example is a special case where we write 2 different languages in one file. While most of our code is JavaScript, we write HTML as one long string as an input to the res.write() function. res is the response of our server, so it sends out the string inside res.write() to the client whenever a request is made. Note that we use the character ‘\’ to separate lines in a string in JavaScript. The ‘\’ is ignored, but it prevents the string from ending when we move to a new line.

HTML uses tags, as noted by the <> characters, to tell the browser how to structure the page and display text. For example, you could put <b> and </b> around some text to make it bold (try it!). In our example, we use <head> to mark the header of the page, which appears in the tab or title bar, and <body> to mark the main part of the page, which is the text that appears in the browser window. To learn more about tags, see here.

Part 2: Web Page Button

The Code

Add "socket.io": "1.3.7" to "dependencies" in package.json, which should look like:

language:JavaScript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"socket.io": "1.3.7"
  }
}

In main.js, copy in the following code:

language:JavaScript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 5 - Part 2: Web Page Button
 * This sketch was written by SparkFun Electronics
 * November 1, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Serves a web page that allows users to turn an LED on and off remotely.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA and HTTP modules
var mraa = require('mraa');
var http = require('http');

// Set up a digital output on MRAA pin 20 (GP12) for the LED
var ledPin = new mraa.Gpio(20);
ledPin.dir(mraa.DIR_OUT);
ledPin.write(0);

// Global LED variable to know if the LED should be on or off
var led = 0;

// Which port we should connect to
var port = 4242;

// Create a web server that serves a simple web page with a button
var server = http.createServer(function(req, res) {
    res.writeHead(200);
    res.write("<!DOCTYPE html>                                             \<html>                                                      \<head>                                                      \<title>LED Controller</title>                           \<script src='/socket.io/socket.io.js'></script>         \</head>                                                     \<body>                                                      \<p><button onclick='toggle()'>TOGGLE</button></p>       \<script>                                                \
                        var socket = io.connect('http://" +
                            req.socket.address().address + ":" +
                            port + "');                                     \
                        function toggle() {                                 \
                            socket.emit('toggle');                          \
                        }                                                   \</script>                                               \</body>                                                     \</html>");
    res.end();
});

// Listen for a socket connection
var io = require('socket.io').listen(server);

// Wait for a client to connect
io.on('connection', function(socket) {
    console.log('A client is connected!');

    // Look for the "toggle" message from the client, and toggle the LED
    socket.on('toggle', function() {
        led = led ? 0 : 1;
        ledPin.write(led);
    });
});

// Run the server on a particular port
server.listen(port, function() {
    console.log('Server listening on port ' + port);
});

What You Should See

Like in the previous part, run the code and navigate to http://<Edison's IP address>:4242 with your browser. You should see a button labeled TOGGLE. Push it.

Edison running a web page with socket.io

We doubt you will be able to resist the allure of a single button

When you click the button, the LED connected to the Edison should come on. Click the button again, and the LED should turn off.

Toggle the LED connected to the Edison

Code to Note

If you thought HTML inside a JavaScript file was bad, take a look at the code for this example. We have JavaScript inside HTML inside a JavaScript file. Mind = blown. The JavaScript inside HTML is denoted by the <script> and </script> tags. As before, we are constructing one long string to send to the client’s browser. The client’s browser should be able to interpret the HTML and display a simple web page. Additionally, most modern browsers are capable of running JavaScript.

The JavaScript embedded in the HTML actually runs on the client’s browser (not the Edison). src='/socket.io/socket.io.js' requests the socket.io library from the server (assuming the server is running socket.io). var socket = io.connect('http://" + req.socket.address().address + ":" + port + "'); creates a socket.io connection back to the Edison (we get the Edison’s IP address from the client’s request in req and the port from the global port value). We also define function toggle() { socket.emit('toggle'); } that sends the very simple message “toggle” back to the Edison over the socket.io connection. This function is called whenever the button is pushed, as per <button onclick='toggle()'>TOGGLE</button>.

On the server (Edison), serving the web page is accomplished in the same manner as in the first part of this experiment. The difference is we add a socket.io server that listens for incoming socket.io (WebSocket) connections in addition to listening for requests for a web page. We define var io = require('socket.io').listen(server); to listen to connections using the same web page server we created in the beginning of the code. We can then handle incoming socket.io connections with io.on('connection', function(socket) { ... });.

Within the io.on('connection', ... ); code, we define the callback socket.on('toggle', function() { ... });, which listens for the message “toggle” on the socket that we created (the variable socket was passed as a parameter from function(socket) { ... }). In this case, we simply toggle the LED (the ternary operator ? is a shortcut for a simple if statement; read more about it here).

Troubleshooting

  • My browser can’t find the web page– Double-check the HTML in your code to make sure it matches the example. Then, make sure your client computer is on the same network (e.g. if the Edison has the IP address 10.8.0.x, then your computer should also have an IP address on the same 10.8.0.x subnet).
  • I don’t see a TOGGLE button– If you just completed the first part and are moving to the second part, make sure you refresh the page in your browser to get the new HTML from the Edison.
  • Nothing happens when I push the TOGGLE button– Make sure that you are actually connecting to the Edison server (you should see A client is connected! appear in the XDK console). If not, double check the HTML and IP addresses of the Edison and your computer.

Going Further

Challenges

  1. Change the web page in part 1 so that it contains the name of your favorite famous scientist and a link to their Wikipedia page (hint).
  2. Have the web page button in part 2 change to say “ON” and “OFF” as appropriate to reflect the state of the LED. When you click on the button, it should update to show the LED’s state.
  3. We’ve shown you how to make a web page interact with the physical world. Now, it’s your turn to make the physical world interact with a web page. Add a button circuit (see Experiment 2) and have it so that when you push the physical button, a piece of text changes on the website (for example, you could have a counter showing how many times the button was pushed).

Digging Deeper

Experiment 6: RGB LED Phone App

Introduction

In the previous experiment, we used WebSockets to create a connection from a client (browser) to the server (Edison). With them, we can send data back and forth to control a simple LED.

In this experiment, we introduce the concept of Web Apps, which are applications designed to run in a browser. Specifically, we will create an HTML application intended for a smartphone. Because the application is written in HTML, it should be capable of running on most phone operating systems, including iOS, Android, and Windows Phone/Mobile.

NOTE: The examples in this part require a smartphone or tablet capable of running HTML5. Feel free to skip this exercise if you do not have access to a phone or do not wish to run applications on one.

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x RGB LED
  • 3x NPN Transistor
  • 3x 1kΩ Resistor
  • 3x 100Ω Resistor
  • 12x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
LED - RGB Diffused Common Cathode

COM-09264
$1.95
2
Transistor - NPN (2N3904)

COM-00521
$0.5

Suggested Reading

Concepts

Web App

XDK Web App Emulator

A web application (or web app for short) is a program that runs on a client’s browser (although, some of the computing may be shared by the server). With the rise of HTML5 and JavaScript, most browsers are capable of running simple (or even complex) programs with these now ubiquitous languages.

Many smartphones have built-in or third-party browsers capable of running HTML5 and JavaScript. As a result, we can write software in the XDK that runs inside a phone’s browser. This allow us to make programs that run across a variety of operating systems and can make network connections (e.g. to the Internet or the Edison). The down side is that some of the phone’s native capabilities (e.g. accelerometer, GPS, camera) are not available to web apps. If we want native functionality, we either need to create a native app, designed specifically for a particular phone or operating system, or we need to make a hybrid app, which combined native functionality and web app portability.

We will cover hybrid apps (with Cordova) in a future exercise.

Web App Libraries

In previous examples, we included libraries by adding the appropriate name and version (usually found from npmjs.com) into the package.json file. This told the XDK to download the Node library, build it (if needed), and transfer it to the Edison along with the other necessary program files.

When building a web app, it is often necessary to include other pieces of code as a library, much like we did with Node modules. However, the XDK does not have a good way of automatically knowing which libraries to find when it comes to web apps. As a result, we will need to manually download the library (often packaged as a .js file) and include it with the project files.

Basic file organization of a web app

The suggested file structure of a web app looks slightly different from the file structure of the Node.js IoT application. In fact, it looks very much like the suggested file structure for web pages. We will keep HTML (user interface) in index.html, JavaScript in js/app.js, and libraries (usually, third-party .js files) in the js directory.

LED Current

The brightness of an LED is controlled by the amount of current flowing through it. LEDs, generally, have a fixed voltage drop across their anode and cathode. In order to fix the amount of current, we usually need to choose the right resistor for the LED.

In our previous circuit, we used just the red channel of the RGB LED, which we will assume is 1 LED. We found that the red LED has a voltage drop of about 2.0V, and by using a 100Ω resistor and a 3.3V rail, we could get 11mA to pass through the resistor (well below its maximum current rating of 20mA.

Now, we want to add 2 more LEDs into the mix. The green and blue LEDs (all packaged within the same RGB LED housing) have a voltage drop of about 3.2V (according to the RGB LED datasheet). If we connect a 100Ω resistor to each of the green and blue LEDs and connect that to the 3.3V rail through a transistor (like we did for red), we would end up with almost no current flowing through them. They probably wouldn’t turn on!

Voltage drop for green and blue channels on 3.3V

That can’t happen! So, we need to increase the rail voltage that we are using for the green and blue LEDs (and not for the red channel). We will connect the collector of the transistors for green and blue to the VSYS rail, which is nominally 4.2V.

RGB LED schematic

Now, we should have some current flowing through our green and blue LEDs. We can calculate that voltage drop across the 100Ω resistor:

Voltage drop across limiting resistor

With that, we can calculate the current flowing through the resistor (and, as a result, the LED):

Calculating current through resistor

Current through resistor and LED

8mA is not exaclty the same as the current flowing through the red LED (11mA), so the brightnesses will be different. For our purposes, it will be good enough to demonstrate how to mix red, green, and blue into different colors.

Pulse Width Modulation

In addition to controlling the current, we can also rapidly turn the LED off and on to give the appearance of a dimmer LED. This is known as “Pulse-Width Modulation” (PWM). Note that we are flipping the LED off and on so fast that generally our eyes cannot see the flickering.

We adjust the “duty cycle” of this flipping process in order to control the brightness. Duty cycle just refers to how long our LED stays on in relation to how long it stays off.

Duty cycle example

The higher the duty cycle (e.g. 75% in the image above), the brighter the LED will appear to be. At lower duty cycles (e.g. 25%) the LED will hardly appear to be on. For a full tutorial on PWM, see Pulse-width Modulation.

In our program, we will rely on the Edison’s built-in PWM functionality (using MRAA’s PWM class) to control the duty cycle of the individual red, green, and blue channels of the LED.

Hardware Hookup

Fritzing Diagram

We build upon the previous, single LED example and add another set of transistors and resistors.

RGB LED with Edison Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Part 1: Simple Web App

Create a Web App

In the XDK, create a new project, and under HTML5 Companion Hybrid or Web App select Templates and Blank. Select Standard HTML5, and click Continue.

Creating a web app in the Intel XDK

Give your new app a name (e.g. “XDK_MyApp”), and click Create. You will notice that the files and folders in the web app template are different from the ones in IoT project templates.

XDK Web App files

Our code will live in www/index.html and www/js/app.js

Libraries

Similar to loading Node.js modules for code that runs on the Edison, we will rely on JavaScript libraries in our web app. In the first part, we will include jQuery, which makes it easier to select HTML elements (from the index.html page) in our JavaScript (app.js) code and handle events like text entry or button clicks.

Navigate to http://jquery.com/download/ and download the latest, uncompressed version (e.g. “Download the uncompressed, development jQuery 2.1.4”). That will download a .js JavaScript file, which we need to copy into our project.

Navigate to your Downloads directory, and copy the newly downloaded .js file. Then, navigate to your project directory. In the www directory (e.g. <Your XDK Web App Directory>/www), create a directory named lib.

Create lib directory in project

In that directory, create another directory named jquery.

jquery directory in project

Finally, paste the jQuery JavaScript (.js) file in the jquery directory.

Copying in the jQuery file

The XDK should now show the jQuery file in the file browser pane (if not, switch to another project and then back to the web app project to reload the file browser).

XDK file browser with jQuery

HTML

Open the index.html file (found in the www directory in the project), and copy in the code below. Don’t forget to save the file (File → Save) when you are done!

language:html<!DOCTYPE html><!--
SparkFun Inventor's Kit for Edison
Experiment 6 - Part 1: Simple Web App
This sketch was written by SparkFun Electronics
November 10, 2015
https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments

Create a some dynamic text that appears when a button is pushed.

Released under the MIT License(http://opensource.org/licenses/MIT)
--><html><head><title>Simple Web App</title><meta http-equiv="Content-type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=no"><style>
        @-ms-viewport { width: 100vw ; min-zoom: 100% ; zoom: 100% ; }  @viewport { width: 100vw ; min-zoom: 100% zoom: 100% ; }
        @-ms-viewport { user-zoom: fixed ; min-zoom: 100% ; }           @viewport { user-zoom: fixed ; min-zoom: 100% ; }</style></head><body><!-- Static text --><div><h2>The Button</h2><p><button id="toggle_button">Push Me!</button></p></div><!-- Text that appears on button push --><div id="toggle_text" style="display: none;"><p>Boo!</p></div><!-- Load the various JavaScript files --><script type="text/javascript" src="lib/jquery/jquery-2.1.4.js"></script><script type="text/javascript" src="js/app.js"></script></body></html>

JavaScript

Open the app.js file (found in the www/js directory), and copy in the following code. Don’t forget to save the file (File → Save) when you are done!

language:javascript
/*jslint unparam: true */
/*jshint strict: true, -W097, unused:false,  undef:true, devel:true */
/*global window, document, d3, $, io, navigator, setTimeout */

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 6 - Part 1: Simple Web App
 * This sketch was written by SparkFun Electronics
 * November 10, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Create a some dynamic text that appears when a button is pushed.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Make the toggle text div appear and disappear
function toggleText() {

    // Put in strict mode to restrict some JavaScript "features""use strict";

    // Declare our variables at the beginning of the scope
    var toggleTextEl = $('#toggle_text');

    // Toggle the visibility of the text
    toggleTextEl.fadeToggle();

    // Print the visibility to the console
    console.log("Visibility: " + toggleTextEl.css('visibility'));
}

// Short for jQuery(document).ready() method, which is called after the page
// has loaded. We can use this to assign callbacks to elements on the page.
$(function() {
    "use strict";

    // Assign a callback to the "Push Me" button
    $('#toggle_button').on('click', function(){
        toggleText();
    });
});

What You Should See

To test the program in the XDK’s phone emulator, click on Run My App in the right-side pane. Click on the “Play” symbol (triangle) next to Run in Emulator. The XDK Emulator should boot up and give you a phone-like interface running our web app. Click the “Push Me!” button for a (very insignificant) surprise.

XDK Phone Emulator

In the top-left pane, you can also select the model of phone you wish to test. It may not be as good as the real thing, but it’s a start!

To test the program on a real phone, we will first need to download and install the Intel App Preview from the appropriate app store. App Preview can be found here for iOS, here for Android, or here for Windows.

For the next steps, you must be logged into the Intel® Developer Zone in the XDK.

In the XDK, go to the TEST tab, and click on the Push Files button. This will upload the project to Intel’s servers, where you will be able to download it on your phone.

Pushing files to Intel's test servers with the XDK

On your phone, open the Intel® App Preview app (don’t think about the redundancy too hard). Press the Login button, and enter your Intel® Developer Zone username and password. Press the Server Apps tab on the bottom of the screen to view your uploaded projects (at this point, you should only see one).

App Preview server apps

Press on your project’s name, and you will be presented with a launch screen.

App Preview launch screen

Press the rather large Play button to start your app.

App running

And that’s it! Your web app is now running on your phone. To exit, tap the screen with three fingers simultaneously.

To build and deploy your app (i.e. run without the App Preview app), navigate to the BUILD tab in the XDK. There, you will see several options on building your app. To build your program as a Web App, click the WebApp button. To learn more about building XDK apps, read this article.

Code to Note

The <html>, <head>, and <body> tags should look very similar to how we created a simple web page in the previous experiment. The difference here is that the HTML is located in a separate file (index.html) than the JavaScript (app.js).

We load the JavaScript file with

language:html<script type="text/javascript" src="js/app.js"></script>

at the end of the body. This allows us to make functions calls to JavaScript as well as have HTML elements be referenced by the JavaScript. For example, we create a button with <button id="toggle_button"> that has the id “toggle_button”. In app.js, we assign an event handler (the function .on()) to the toggle_button element.

To make the HTML-JavaScript communication easier, we rely on the jQuery library. jQuery adds event handling, page manipulation, and animations to JavaScript in an easy-to-use fashion. The syntax might take some time to get used to, but for starters, know that $ is short for the class jQuery. That means $('#toggle_button') is really jQuery('#toggle_button') (i.e. it’s just a shortcut).

The piece of code

language:javascript
$('#toggle_button').on('click', function(){
    toggleText();
});

assigned the function toggleText() to the on click action for the toggle_button HTML element, which we created in index.html.

Finally, "use strict"; is an odd piece of code that sits in the beginning of functions. This line puts JavaScript into “strict mode” running in browsers, which restricts certain functions and is generally considered more “safe.”

Part 2: RGB Color Picker

The Web App

In the previous part, we created a simple web app to demonstrate how web apps work. You might have noticed that we did not use the Edison at all. In this part, we will need to create 2 programs: one that runs on the Edison as a server and one that runs as a client on a smartphone.

Create a new Standard HTML5 app using the Blank Template (just like we did in part 1). Then, we need to add some libraries.

First, download the uncompressed, latest version of jQuery from http://jquery.com/download/. Copy that file (e.g. jquery-2.x.x.js) to <Your XDK Web App Directory>/www/lib/jquery (just like we did in part 1). Create any directories that do not exist.

Second, download the socket.io client library from https://github.com/socketio/socket.io-client (click Download ZIP). Unzip the .zip file, and copy socket.io.js to <Your XDK Web App Directory>/www/lib/socketio.

Third, download the JavaScript tinyColorPicker from https://github.com/PitPik/tinyColorPicker. Unzip the .zip file, and copy jqColorPicker.min.js to <Your XDK Web App Directory>/www/lib/jqColorPicker. Note that we are using the minified) version of the tinyColorPicker library.

You might have to refresh the project in the XDK (i.e. right-click in the file explorer pane and select Refresh File Tree).

Refresh file tree in XDK

In www/index.html, paste in the following code:

language:html<!DOCTYPE html><!--
SparkFun Inventor's Kit for Edison
Experiment 6 - Part 2: Phone RGB LED
This sketch was written by SparkFun Electronics
November 9, 2015
https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments

Runs as a web app on a smartphone. Creates a socket.io connection to the
Edison and sends RGB values.

Released under the MIT License(http://opensource.org/licenses/MIT)
--><html><head><title>Set RGB of Edison</title><meta http-equiv="Content-type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=no"><style>
        @-ms-viewport { width: 100vw ; min-zoom: 100% ; zoom: 100% ; }  @viewport { width: 100vw ; min-zoom: 100% zoom: 100% ; }
        @-ms-viewport { user-zoom: fixed ; min-zoom: 100% ; }           @viewport { user-zoom: fixed ; min-zoom: 100% ; }</style></head><body><!-- IP address and port inputs --><div id="connection"><h2>Edison Address</h2><p>Please provide the IP address &amp; port to the Edison</p><p><input id="ip_address" type="text" placeholder="IP Address"><input id="port" type="text" placeholder="Port"></p><p><button id="send_ip_port">Connect</button></p></div><!-- RGB Color Picker --><div id="rgb" style="display: none;"><h2>Color Selector</h2><input id="colorSelector" class="color"></div><!-- Load the various JavaScript files --><script type="text/javascript" src="lib/jquery/jquery-2.1.4.js"></script><script type="text/javascript" src="lib/jqColorPicker/jqColorPicker.min.js"></script><script type="text/javascript" src="lib/socketio/socket.io.js"></script><script type="text/javascript" src="js/app.js"></script></body></html>

Save the file, and in www/js/app.js, paste in the following code:

language:javascript
/*jslint unparam: true */
/*jshint strict: true, -W097, unused:false,  undef:true, devel:true */
/*global window, document, d3, $, io, navigator, setTimeout */

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 6 - Part 2: Phone RGB LED
 * This sketch was written by SparkFun Electronics
 * November 9, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Runs as a web app on a smartphone. Creates a socket.io connection to the
 * Edison and sends RGB values.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Connect to Edison server with socket.io
function connectIP() {

    // Put in strict mode to restrict some JavaScript "features""use strict" ;

    // Declare our variables at the beginning of the scope
    var scoket;
    var ipEl = $('#ip_address');
    var portEl = $('#port');
    var connectionEl = $('#connection');
    var rgbEl = $('#rgb');
    var colorSelectorEl = $('#colorSelector');

    // Attach a socket.io object tot he main window object. We do this to avoid
    // a global socket variable, as we will need it in the colorPicker callback.
    window.socket = null;

    // Connect to Edison
    console.log("Connecting to: " + ipEl.val() + ":" + portEl.val());
    window.socket = io.connect("http://" + ipEl.val() + ":" + portEl.val());

    // If we don't have a connection, disconnect and hide the RGB selector
    window.socket.on('connect_error', function() {
        window.socket.disconnect();
        alert("Could not connect");
        rgbEl.fadeOut();
    });

    // If we do have a connection, make the RGB selector appear
    window.socket.on('connect', function() {
        rgbEl.fadeIn();
        colorSelectorEl.trigger('click');
    });
}

// Short for jQuery(document).ready() method, which is called after the page
// has loaded. We can use this to assign callbacks to elements on the page.
$(function() {
    "use strict" ;

    // Assign a callback to the "Connect" port
    $('#send_ip_port').on('click', function(){
        connectIP();
    });

    // Assign initial properties to the color picker element
    $('.color').colorPicker({
        opacity: false,
        preventFocus: true,
        color: 'rgb(0, 0, 0)',

        // This is called every time a new color is selected
        convertCallback: function(colors, type) {
            if (window.socket && window.socket.connected) {
                window.socket.emit('color', colors.RND.rgb);
            }
        }
    });
});

Don’t forget to save!

Edison Code

Create a new project (Blank template under Internet of Things Embedded Application). This code will run on the Edison. Copy in the following code into main.js:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 6 - Part 2: Edison RGB LED
 * This sketch was written by SparkFun Electronics
 * November 9, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Waits for socket.io connections and received messages to change RGB LED.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA and HTTP modules
var mraa = require('mraa');
var server = require('http').createServer();
var io = require('socket.io').listen(server);

// Port
var port = 4242;

// Set up PWM pins
var rPin = new mraa.Pwm(20);
var gPin = new mraa.Pwm(14);
var bPin = new mraa.Pwm(0);

// Enable PWM
rPin.enable(true);
gPin.enable(true);
bPin.enable(true);

// Set 1000 Hz period
rPin.period(0.001);
gPin.period(0.001);
bPin.period(0.001);

// Turn off LEDs initially
pwm(rPin, 0.0);
pwm(gPin, 0.0);
pwm(bPin, 0.0);

// Wait for a client to connect
io.on('connection', function(socket) {
    console.log("A client is connected!");

    // Look for the "color" message from the client and set the LED
    socket.on('color', function(rgb) {
        console.log("RGB(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ")");
        pwm(rPin, rgb.r / 255);
        pwm(gPin, rgb.g / 255);
        pwm(bPin, rgb.b / 255);
    });
});

// PWM needs a "fix" that turns off the LED on a value of 0.0
function pwm(pin, val) {
    if (val === 0.0) {
        pin.write(0.0);
        pin.enable(false);
    } else {
        pin.enable(true);
        pin.write(val);
    }
}

// Run the server on a particular port
server.listen(port, function() {
    console.log("Server listening on port " + port);
});

What You Should See

Upload the Edison code to the Edison and run it. You should see a note in the console, “Server listening on port 4242”. Take note of the Edison’s IP address.

Open the web app project back up and run it in an emulator or your smartphone. You will be presented with a couple of fields for IP address and port number. Enter the IP address of the Edison and 4242 for the port.

Connecting to the Edison with a web app

Click Connect and the web app should make a connection with the Edison (assuming your phone/emulator and Edison are on the same network). If it was successful, you should see an RGB color selector appear.

RGB color picker as a web app

Try selecting different colors, and see how the LED connected to the Edison responds!

RGB LED on Edison

Code to Note

In the web app, we are using jQuery again to control elements, like in part 1. We rely on fadeIn() and fadeOut() to make the RGB selector appear and disappear. Additionally, we use the alert() function to make a pop-up appear letting the user that the connection failed.

You might have noticed that we used window.socket in connectIP(). The window object is pre-defined as the open window in a browser. It contains all the displayed HTML. As it turns out, we need to access a socket object in the function connectIP() as well as the callback for the RGB color picker. However, socket was never declared as a global variable, and as a result, the color picker callback (convertCallback) does not know about the existence of socket, as it was declared in connectIP(). This is a problem of “scope.”

To solve this issue (and without creating unnecessary global variables), we create a socket object inside the window object (we say that window owns a socket object) with window.socket. Because window is global, we can then access window.socket anywhere in our code! To make sure that the window.socket object exists and has a connection before we use it to send data, we rely on the conditional

language:javascript
if (window.socket && window.socket.connected) {
    ...
}

in convertCallback. That way, we don’t throw any undefined errors when we try to use the socket.

In the Edison code, we use the MRAA Pwm object to control the brightness of the RGB LED, which is created with an MRAA pin number. To find the MRAA pin number, first find the pin number as it is listed on the GPIO Block, and find the associated MRAA pin number in Appendix E: MRAA Pin Table. For example, GP12 is MRAA pin 20.

Troubleshooting

  • The web app does not start– Try it in the XDK emulator first. In the emulator, click on the “debug” button (bug icon with an ‘X’ in the upper-left corner), and click on the Console tab to view error messages.
  • The web app won’t run on my phone– Your phone might not be supported. If it is an older phone, read about legacy phone support for the XDK.
  • The web app won’t connect to the Edison– Make sure the Edison and phone are on the same network (e.g. the phone must be connected to WiFi and on the same subnet as the Edison).

Going Further

Challenges

  1. Make a modified email notifier that changes the color of the LED depending on different parameters of your inbox. For example, you could have the LED be green for 1-10 new emails and red for 11+ emails.
  2. Add an image to the web app that turns the LED off and back on when you press it (hint).

Digging Deeper

Experiment 7: Speaker

Introduction

Many microcontrollers have the ability to create analog voltages using a digital-to-analog converter (DAC). DACs are incredibly useful for connecting to a speaker (usually through an amplifier) to make sounds.

Many other microcontrollers and computer modules (like our Edison) do not have an onboard DAC. While separate DAC chips can be added, we are often left with using PWM to approximate sounds with a speaker.

In this experiment, we will read musical note information from a file and use that to create PWM signals. We then amplify the PWM signals and feed it to a small speaker that converts those signals to sound.

WARNING: This exercise is not for the faint of heart nor people with perfect pitch. We will create some sounds that approximate basic musical notes, but they will be far from pleasing. It is, however, a useful exercise in learning how to read files and discovering why Linux makes for a poor real-time operating system (RTOS).

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x Piezo Speaker
  • 1x NPN Transistor
  • 1x 1kΩ Resistor
  • 1x 100Ω Resistor
  • 6x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
Piezo Speaker - PC Mount 12mm 2.048kHz

COM-07950
$1.95
5
Transistor - NPN (2N3904)

COM-00521
$0.5

Suggested Reading

Concepts

Reading a File

The ability to read and write to and from a file in a program can be incredibly useful. Often, we want to store settings and other parameters in a piece of plain text so that users can adjust the configuration of the program without digging through code.

To accomplish that, we will rely on the node module fs. Specifically, we want to use fs.readFileSync().

fs.readFile() will also read the contents of a text file, but it does so asynchronously, which means other parts of the program might execute before the file is completely read. This could result in the variable that’s supposed to hold the file contents being undefined.

fs.readFileSync()blocks execution of the program until the file has been completely read.

POSIX

JavaScript, in its attempt to be as asynchronous (e.g. non-blocking) as possible, does not have a built-in wait() or sleep() function. As JavaScript is primarily intended for use in browsers, telling a client’s computer to sleep on a thread is generally considered a bad idea.

As a result (and since we don’t care about browser behavior in this Node example), we will write our own sleep function.

We will use the Portable Operating System Interface (POSIX) API to tell the system to sleep for a specified amount of time. POSIX gives us a standardized interface to make system calls. In this case, we rely on the Node module posix-clock, which gives us a few JavaScript functions capable of making calls to the system’s clock.

PWM Sounds

While a DAC is normally used to make sounds with a speaker, we can approximate sounds with PWM. Because PWM is a digital signal (a square wave), it contains a lot of harmonic frequencies on top of the original frequency, and thus producing an unclean sound (i.e. not a true representation of the actual frequency). Played through a speaker, a square wave sounds very different from a sine wave.

Without a true DAC on the Edison, we can use a 50% PWM signal (a basic square wave) to create sounds. Played at the correct frequency, we can even make notes!

Based on some testing with an oscilloscope, the fastest the Edison is able to switch a pin on and off is about 475 μs, which translates to about 2.1 kHz. As a result, we need to keep notes to C7 (2093.00 Hz) or lower. A note-to-frequency table can be found here.

Real-Time Operating System

A real-time operating system (RTOS) is an operating system (OS), but unlike popular operating systems like Linux, OS X, or Windows, an RTOS is intended to meet strict timing deadlines.

For example, an HDTV receiver often relies on an RTOS within a microcontroller (or microprocessor) to receive a digital signal and decode it within a very small amount of time (every frame!). If deadlines are missed, the TV’s picture may be garbled or worse, not displayed at all.

Linux (like the one running in your Edison), generally, is NOT an RTOS! Linux was originally designed as a general-purpose OS with the focus on user experience. If we give Linux several tasks, there is no guarantee as to when those tasks will execute, when they will finish, and in what order. There are several versions of real-time Linux available and in the works, but the default Yocto image on the Edison is not one.

If we create a fast switching signal (a square wave) in our Edison and output it to a pin, we can measure it with an oscilloscope. In this example, we create a square wave with a frequency of 440 Hz.

Square wave with the Edison

See anything wrong?

Well, first of all, the measured frequency is WAY off from 440 Hz! The period of a 440 Hz signal is about 2.27 ms, and we measured 2.84 ms. That means Linux is taking its sweet time (around 0.57 ms in this case) to do whatever it needs (switch to some other task, run it for a while, switch back, and then notice that we should toggle that pin). 0.57 ms may not seem like a lot (especially when we are talking about doing things like browsing sites and reading text files), but when it comes to music, that means the difference between reading an A and playing an F note. Talk about tone deaf.

Secondly, not all of the highs and lows in that oscilloscope image are the same width. That means that Linux is not even guaranteeing the frequency will be constant! Unless it is an intentional fluctuation, it often makes a note very unpleasing.

If you still decide to go through with this experiment, please forgive me for assaulting your ears.

Hardware Hookup

Fritzing Diagram

Speaker connected to the Edison Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Tips

Speaker

Note the + marking on the top side of the speaker (there are also + and - markings on the underside).

Polarity marking on the piezo speaker

The pin associated with the positive (+) polarity should be connected to the 100Ω resistor. Negative (-) should be connected to the ground rail on the breadboard.

The Code

Normally, we build Node modules on our host machine and then transfer the build to the Edison. However, posix-clock will fail to build on Windows machines. To get around this, we can install the module directly on the Edison.

Use the SSH tab (USB connected to “OTG” port) or the Serial Terminal tab (USB connected to “CONSOLE” port), connect to the Edison, and enter the command (make sure the Edison is connected to the Internet):

npm install posix-clock

That will install the posix-clock module.

Installing posix-clock on the Edison

Back in the XDK, create a new directory named songs in the file browser, and in that, a file named song.txt. In song.txt, copy in the following text:

523.251,100
0,100
523.251,100
0,100
466.164,100
0,100
523.251,100
0,100
0,100
0,100
391.995,100
0,100
0,100
0,100
391.995,100
0,100
523.251,100
0,100
698.456,100
0,100
659.255,100
0,100
523.251,100
0,100

Save that file.

Song file

Then, copy the following code into main.js:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 7: Speaker
 * This sketch was written by SparkFun Electronics
 * November 17, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Plays a tune using a PWM speaker.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA, file system, and POSIX clock modules
// NOTE: You must build posix-clock (npm install posix-clock) on the Edison
// iteslf. Building on a Windows machine will fail!
var mraa = require('mraa');
var fs = require('fs');
var clock = require('posix-clock');

// Global constants
var MAX_FREQ = 2100;

// Set up a digital output on MRAA pin GP13 for the speaker
var speakerPin = new mraa.Gpio(13, true, true);
speakerPin.dir(mraa.DIR_OUT);
speakerPin.write(0);

// Read and parse song file
var song = fs.readFileSync(__dirname + "/songs/song.txt", 'utf-8');
song = song.replace(/\r/g, '');
song = song.split('\n');

// Play song
console.log("Playing...");
for (var t = 0; t < song.length; t++) {

    // Read the frequency and time length of the note
    var note = song[t].split(',');

    // Play the note
    playNote(speakerPin, parseInt(note[0], 10), parseInt(note[1], 10));
}
console.log("Done!");

// Play a note with a given frequency for msec milliseconds
function playNote(pin, freq, msec) {

    // Check to make sure we actually have valid numbers
    if (freq === "NaN" || msec === "NaN") {
        return;
    }

    // Make sure we don't go over the maximum frequency
    if (freq >= MAX_FREQ) {
        freq = MAX_FREQ;
    }

    // If the frequency is 0, don't play anything
    if (freq === 0) {
        console.log("Silence for " + msec + "ms");
        sleepUsec(msec * 1000);
        return;
    }

    // Define the note's period and how long we play it for
    var period = 1 / freq;
    var length = msec / (period * 1000);

    console.log("Playing " + freq + "Hz for " + msec + "ms");

    // For one period, send pin high and low for 1/2 period each
    for (var i = 0; i < length; i++) {
        pin.write(1);
        sleepUsec((period / 2) * 1000000);
        pin.write(0);
        sleepUsec((period / 2) * 1000000);
    }
}

// Sleep for a number of given microseconds using the POSIX clock
function sleepUsec(usec) {
    var s = Math.floor(usec / 1000000);
    var ns = Math.floor((usec - (s * 1000000)) * 1000);
    clock.nanosleep(clock.MONOTONIC, 0, {sec: s, nsec: ns});
}

What You Should See

Well, you shouldn’t actually see anything. However, you should hear an awful rendition of a popular ‘70s song. Bonus points if you can name that tune (and with it being horribly off key, those bonus points really count).

Speaker connected to the Edison

Code to Note

Regular Expressions (Regex)

We get the contents of our song file with fs.readFileSync(), but then we must parse that file to know which notes we need to play and for how long. To do that, we get rid of all the carriage return characters (‘\r’) by using the regular expression/\r/g, which says “find all \r characters in the string.”

We can use the .replace(regex, string), which finds all the occurrences of the regex and replaces it with the given string. In this case, we replace all ‘\r’ with ‘’ (nothing).

String Manipulation

JavaScript plays very nicely with strings. You have just seen the .replace() method, and there are many others.

We also rely on .split() to split up the string containing the file contents into an array of smaller strings. We first split on the newline character \n. We iterate (using a for loop) over that array, and in each case, we split the substring even further.

In each substring, we look for the comma ‘,’ character. As the song.txt file is set up, we list the frequency we want to play first (the note) and for how long (milliseconds) next. They make up the first and second (0 and 1) elements of the array, respectively.

GPIO Raw Pin Numbers

A few pin objects in MRAA (for example, GPIO) allow us to use “raw” pin numbers (e.g. GP13). To do that, we need to pass true to the third parameter. For example:

var speakerPin = new mraa.Gpio(13, true, true);

The second parameter says that we “own” the pin (the descriptor to the pin will automatically close when we exit). The third parameter says that we want to use “raw” values (by default, this value is false, and says that we should treat the first parameter as the MRAA pin number). The number 13 actually corresponds to GP13 on the board!

This does not work for all pin-related objects. For example, PWM does not support raw pin numbers. More about raw pin numbers can be found here.

Troubleshooting

  • There is no sound– Double-check the wiring of the speaker and the transistor. Make sure the + symbol on the speaker is on the same row as the 100Ω resistor in the breadboard.
  • posix-clock is not found– This means that the posix-clock module was not installed properly. Make sure you manually install it in the Edison with npm install posix-clock.

Going Further

Challenges

  1. Create a new song! Take a look at how the song.txt file is organized (frequency,time) and generate a new song text file with one of your favorite tunes. Don’t forget to change the file location in fs.readFileSync()!
  2. Make it non-blocking. Re-write the program so that there is no sleep function. Hint: Take a look at the clock_gettime() method in posix-clock.

Digging Deeper

Experiment 8: Temperature and Light Logger

Introduction

On its own, the Edison is not capable of taking analog voltage readings, unlike many other microcontrollers (such as the Arduino). The kit, however, contains an analog-to-digital converter (ADC) Block for the Edison. On this Block is a special chip that is capable of measuring analog voltages and reporting them over the I2C bus.

Because the Edison has built-in networking capabilities, we can use WiFi (and the power of the Internet!) to log these analog readings to a remote site. In this case, we are going to use SparkFun’s own data.sparkfun.com. By constructing a simple HTTP request, we can post values to our own feed on data.sparkfun. That way, we can monitor various sensor readings from anywhere in the world!

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x TMP36 Temperature Sensor
  • 1x Photocell
  • 1x 1kΩ Resistor
  • 7x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Mini Photocell

SEN-09088
$1.5
5
Female Headers

PRT-00115
$1.5
5
Temperature Sensor - TMP36

SEN-10988
$1.5
15
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
SparkFun Block for Intel® Edison - ADC

DEV-13327
19.9500$14.95

Suggested Reading

Concepts

Voltage Divider

Our two sensors, the TMP36 and the photocell, change their voltage or resistance based on the property they are measuring. The TMP36, luckily, changes the voltage on its VOUT pin directly as the temperature changes.

The photocell, on the other hand, varies its resistance as the measured light changes. Since we don’t have a good way to measure resistance on the Edison, we can set up a voltage divider to measure the voltage.

Photocell voltage divider

As the photocell detects more light, its resistance decreases (down to about 1kΩ). Conversely, as it detects less light, its resistance increases (up to about 10kΩ). The voltage divider allows us to measure that change is resistance through a change in voltage at AIN1. The equation for this circuit is:

Equation for voltage divider

We know that VIN is 3.3V and R1 is 1kΩ. In a light environment, we can calculate that the voltage measured at VOUT (AIN1) should be around:

Equation for finding output voltage in light environment

and in a dark environment:

Equation for finding output voltage in dark

Luckily, that voltage can be measured with an analog-to-digital converter!

Analog-to-Digital Conversion

Being able to measure an analog voltage is extremely useful in the world of digital electronics. Many sensors, like our TMP36 temperature sensor and photocell, vary output voltage or resistance based on its measured value. For example, the resistance in the photocell increases as the amount of light falling on the sensor decreases.

The ADC on the ADC Block (a TI ADS1015) is capable of measuring the voltage on some of pins within a given range (for example, +/- 4.096 V). Many ADC chips, like our ADS1015, determine analog voltage by measuring the amount of time it takes that voltage to charge a capacitor. That time is converted to a quantized level that corresponds to the measured voltage.

3-bit quantization levels

Image courtesy of Hyacinth of Wikimedia Commons.

In the example above, the analog signal was converted to a 3-bit digital value. Because analog values are continuous and digital values are discrete, we are essentially rounding analog values to fit within the digital value’s resolution (e.g. 3 bits).

Luckily for us, the ADS1015 offers 12 bits of resolution for its conversion values. That allows us to measure voltages down to the 2 mV resolution (assuming the +/-4.096 V range), which should be good enough for most basic sensor readings.

I2C

I2C is communication protocol capable of supporting multiple masters and peripheral devices on the same 2-wire bus.

I2C block diagram

For now, we will use 1 master (the Edison) and 1 peripheral device (ADS1015). The master is in control of the SCL (clock) line, which it toggles at a pre-determined rate (generally, 100 kHz). To make sure that the master talks to the correct peripheral, we can send a specific address across the SDA line first (e.g. 0x48 for our ADS1015).

Most I2C peripherals rely on a series of registers to store data that should be written to or read from over I2C. If you look at the datasheet for the TI ADS1015 (p. 15), you will notice that there are 4 registers: conversion, config, low threshold, and hi threshold. We won’t need to worry about the last two, as we are not using the threshold capabilities on the ADS1015 for this experiment.

To request an analog sample be taken, we need to write 16 bits to the config register (register address 0x01). First, we write the peripheral address (0x48), then we write the register we want (0x01), and finally, we can send the data we want. The specific bits for the config register can be found on pp. 15-16 in the datasheet.

Once the sampling has been taken and stored in the ADS1015, we can then read it back by using a similar method: the master sends the peripheral device and the conversion register address. The ADS1015 will then send the data in the conversion register back across the I2C bus.

Once again, we can rely on the MRAA library to handle much of the I2C communication for us.

NTP

The Network Time Protocol (NTP) is a relatively old (1985) networking protocol intended to synchronize clocks on interconnected computer systems. There are several NTP servers in the world, and we can use one of them (pool.ntp.org), which connects to the NTP Pool Project. By requesting the time, the NTP server responds with a value corresponding to the current date and time given in Greenwich Mean Time (GMT).

For our purposes, we can use the ntp-client module to assist with making NTP requests to servers.

Phant

Phant is SparkFun’s software for logging data to a web server.

Phant logo

data.sparkfun is a site that runs Phant. Using data.sparkfun, we can create our very own data stream and log values to it. This can be anything from local computer time to wind speed. Anything we can measure (and store as a number or string), we can log to data.sparkfun.

To post something to a stream, we need the Public Key and Private Key for that stream, which we will create later. Knowing those, we can log values to the individual streams with the HTTP GET request:

http://data.sparkfun.com/input/<YOUR PUBLIC KEY>/?private_key=<YOUR PRIVATE KEY>&field1=<VALUE 1>&field2=<VALUE 2>

For our purposes, we will be logging a relative light value (as a voltage), the ambient temperature (in Celsius), and the current time (Greenwich Mean Time, taken at the time of the readings). We will be able to access a page on data.sparkfun to view these logs.

Hardware Hookup

Fritzing Diagram

Temperature and light sensors connected to the Edison Frtizing diagram

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Tips

TMP36 Temperature Sensor
WARNING: The 2N3904 transistor and TMP36 temperature sensor look very similar! Examine the flat face of the TO-92 packages very carefully and find one that says TMP.

Like some of the other components that we’ve used, we need to care about polarity when it comes to the TMP36 temperature sensor. With the flat edge of the component body facing toward you, note the pins.

Annotated TMP36 temperature sensor

data.sparkfun Stream

In order to log data to data.sparkfun, we first need to create a stream. The good news is that we don’t even need an account! Navigate to data.sparkfun.com.

data.sparkfun welcome page

Click the CREATE button. You will be presented with a form to fill out for your stream. Go ahead and create a name and description for it. You need to add the following fields:

  • time
  • temperature
  • light

Make sure they are spelled just like that! They need to match the field names in the code below. You can optionally fill out the rest of the form, if you wish.

Creating a new stream on data.sparkfun

Click Save at the bottom of the page, and you will be presented with the keys (public, private, and delete) for your stream.

Keys for your stream on data.sparkfun

Make sure you write them down, save them as a file, or email them to yourself! Once you exit out of this screen, you can’t go back.

The three keys are quite important:

  • Public Key– Used for accessing and viewing your stream. Notice that the URL to your stream is http://data.sparkfun.com/streams/<YOUR PUBLIC KEY>
  • Private Key– Used to post data to your stream (it’s like password). Don’t share this with people if you don’t want them to post, modify, or delete your stream!
  • Delete Key– Use this to permanently delete your stream. If used, your stream will be gone forever!

Click on the Public URL link to go to your stream’s page.

Blank stream on data.sparkfun

As you might have noticed, there is nothing in the stream, right now.

The Code

Create a new Blank Template in IoT Application in the XDK. In package.json, we need to add a couple of libraries:

language:javascript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"request": "2.67.0","ntp-client": "0.5.3"
  }
}

In main.js, copy in the following:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 8: Temperature and Light Logger
 * This sketch was written by SparkFun Electronics
 * December 2, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Reads temperature and light values from ADC Block and posts them to
 * data.sparkfun.com.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// MRAA, as per usual
var mraa = require('mraa');

// The Request module helps us make HTTP calls (e.g. to data.sparkfun)
var request = require('request');

// The ntp-client module allows us to get the current time (GMT)
var ntp = require('ntp-client');

// Save our keys for data.sparkfun
var phant = {
    server: "data.sparkfun.com",        // Base URL of the feed
    publicKey: "xxxxxxxxxxxxxxxxxxxx",  // Public key, everyone can see this
    privateKey: "xxxxxxxxxxxxxxxxxxxx", // Private key, only you should know
    fields: {                           // Your feed's data fields"time": null,"temperature": null,"light": null
    }
};

// Define a timeout period for the HTTP request (2 seconds)
var reqTimeout = 2000;                  // milliseconds

// TI ADS1015 on ADC Block (http://www.ti.com.cn/cn/lit/ds/symlink/ads1015.pdf)
var adc = new mraa.I2c(1);
adc.address(0x48);

// Read from ADC and return voltage
adc.readADC = function(channel) {

    // The ADC Block can't have more than 4 channels
    if (channel <= 0) {
        channel = 0;
    }
    if (channel >= 3) {
        channel = 3;
    }

    // We will use constant settings for the config register
    var config = 0;                 // Bits     Description
    config |= 1 << 15;              // [15]     Begin a single conversion
    config |= 1 << 14;              // [14]     Non-differential ADC
    config |= channel << 12;        // [13:12]  Choose a channel
    config |= 1 << 9;               // [11:9]   +/-4.096V range
    config |= 1 << 8;               // [8]      Power-down, single-shot mode
    config |= 4 << 5;               // [7:5]    1600 samples per second
    config &= ~(1 << 4);            // [4]      Traditional comparator
    config &= ~(1 << 3);            // [3]      Active low comparator polarity
    config &= ~(1 << 2);            // [2]      Non-latching comparator
    config |= 3;                    // [1:0]    Disable comparator

    // Write config settings to ADC to start reading
    this.writeWordFlip(0x01, config);

    // Wait for conversion to complete
    while (!(this.readWordFlip(0x01) & 0x8000)) {
    }

    // Read value from conversion register and shift by 4 bits
    var voltage = (adc.readWordFlip(0x00) >> 4);

    // Find voltage, which is 2mV per incement
    voltage = 0.002 * voltage;

    return voltage
};

// The ADS1015 accepts LSB first, so we flip the bytes
adc.writeWordFlip = function(reg, data) {
    var buf = ((data & 0xff) << 8) | ((data & 0xff00) >> 8);
    return this.writeWordReg(reg, buf);
};

// The ADS1015 gives us LSB first, so we flip the bytes
adc.readWordFlip = function(reg) {
    var buf = adc.readWordReg(reg);
    return ((buf & 0xff) << 8) | ((buf & 0xff00) >> 8);
};

// Send an HTTP request to data.sparkfun to post our data
function postData(values) {

    var prop;

    // Construct the HTTP request string
    var req = "https://data.sparkfun.com/input/" + phant.publicKey +"?private_key=" + phant.privateKey;
    for (prop in values) {
        req += "&" + prop + "=" + encodeURI(values[prop].toString());
    }

    // Make a request and notify the console of its success
    request(req, {timeout: reqTimeout}, function(error, response, body) {

        // Exit if we failed to post
        if (error) {
            console.log("Post failed. " + error);

        // If HTTP responded with 200, we know we successfully posted the data
        } else if (response.statusCode === 200) {
            var posted = "Posted successfully with: ";
            for (prop in values) {
                posted += prop + "=" + values[prop] + "";
            }
            console.log(posted);
        } else {
            console.log("Problem posting. Response: " + response.statusCode);
        }
    });
}

// Take temperature and light readings at regular intervals
takeReadings();
function takeReadings() {

    // Read temperature sensor (on ADC0) and calculate temperature in Celsius
    var v0 = adc.readADC(0);
    var degC = (v0 - 0.5) * 100;

    // Read light sensor (on ADC1)
    var v1 = adc.readADC(1);

    // Get the current time and post to data.sparkfun
    ntp.getNetworkTime("pool.ntp.org", 123, function(error, datetime) {

        // If it's an error, don't post anything
        if (error) {
            console.log("Error getting time: " + error);

        // Otherwise, post all the data!
        } else {

            // Construct a values object to send to our function
            phant.fields.time = datetime;
            phant.fields.temperature = degC.toFixed(1);
            phant.fields.light = v1.toFixed(3);

            // Post to data.sparkfun
            postData(phant.fields);
        }

        // Wait 10 seconds before taking another reading
        setTimeout(takeReadings, 10000);
    });
}

Find the phant object in the beginning of the code:

language:javascript
var phant = {
    server: "data.sparkfun.com",        // Base URL of the feed
    publicKey: "xxxxxxxxxxxxxxxxxxxx",  // Public key, everyone can see this
    privateKey: "xxxxxxxxxxxxxxxxxxxx", // Private key, only you should know
    fields: {                           // Your feed's data fields"time": null,"temperature": null,"light": null
    }
};

Replace the first "xxxxxxxxxxxxxxxxxxxx" with your data.sparkfun public key and the second "xxxxxxxxxxxxxxxxxxxx" with your private key. For example, my code would look like:

language:javascript
publicKey: "XGLgRQp4Aoh1nmxbowjQ",  // Public key, everyone can see this
privateKey: "1JlR9pMr2Dcjp9y7mdJE", // Private key, only you should know

What You Should See

Save, upload, and run the code on the Edison. If all goes well (and your Edison has a connection to the Internet), you should get a “Posted successfully” note in the console.

Edison successfully posting to data.sparkfun

The Edison will sample the temperature from the sensors and attempt to post to data.sparkfun every 10 seconds.

Refresh your stream’s page, and you should see new values in each of the fields.

New values in data.sparkfun stream

Try breathing on the temperature sensor and covering the photocell with your finger. How does that affect the readings?

Temperature and light sensors connected to the Edison

See the buttons at the top of the stream in the page? You can download a snapshot of your data as a JSON, CSV, etc. file if you wish to graph it. You can also try exporting it to analog.io for some browser-based graphing abilities.

Code to Note

Endianness

“Endianness” refers to how a system stores bytes. The Edison, for example, is “big endian,” which means that in a 2-byte “word,” the first byte is the most significant byte (MSB). If you stored the value 0x12AB (decimal: 4779) into memory, the first byte would be 0x12 and the second byte would be 0xAB.

The ADS1015, however, communicates the least significant byte (LSB) first (“little endian”) when it transmits and receives values over I2C. For example, if we wanted to send the number 4779 to the ADS1015, we would have to send 0xAB followed by 0x12. As you might have noticed, that is flipped from how the Edison stores values.

In our code, we need to create a couple of helper functions, writeWordFlip() and readWordFlip(), as part of the adc object. Before we send data (often in the form of 16 bits or 2 bytes), we need to flip the two bytes. We do that with ((data & 0xff) << 8) | ((data & 0xff00) >> 8);. The first part masks the lower 8 bits of our 2-byte value and shifts it left by 8 bits. The second part masks the upper 8 bits of the 2-byte value and shifts it right 8 bits. In effect, this swaps the high and low bytes in our 16-bit word.

HTTP Requests

We’ve used HTTP requests in the past when we were creating web servers. To that end, we waited for an HTTP request to come in, and we responded with HTML text that was then rendered on the client’s broswer.

This time, however, we are creating our own HTTP request. To send something to data.sparkfun, we used the HTTP GET request (not the POST request, as you might think). With a specially crafted Uniform Resource Locator (URL), we can tell data.sparkfun which stream to post to, to which fields, and with what data.

We accomplish that in code by creating a string for our URL. We do that with

language:javascript
// Construct the HTTP request string
var req = "http://data.sparkfun.com/input/" + phant.publicKey +"?private_key=" + phant.privateKey;
for (prop in values) {
    req += "&" + prop + "=" + values[prop].toString().replace(/ /g, "%20");
}

This snippet of code constructs the URL consisting of the host site (data.sparkfun), the page we want (/input), the stream (phant.publicKey), and our password (phant.privateKey).

The next part is interesting and requires its own section.

for…in Loop

JavaScript offers us a unique way to deal with properties in an object: the for…in loop. Much like the basic for loop, we can iterate over several properties. Instead of an array, however, we use an object with several properties.

Given our object values (which is actually phant.fields as passed into our postData() function), we can iterate over arbitrary property names and values in that object. For example, let’s say we have the following within our values object:

language:javascript
values: {"time": "Fri Dec 04 2015 17:43:03 GMT 0000 (UTC)","temperature": 24.2,"light": 0.980
}

The for…in loop would, on each iteration, give us one of the property names in the parameter prop. So,

language:javascript
for (prop in values) {
    console.log(prop);
}

would output:

time
temperature
light

If we want to access the value within each property, we can do so with brackets ([]), much like an array. So,

language:javascript
for (prop in values) {
    console.log(values[prop]);
}

would output:

Fri Dec 04 2015 17:43:03 GMT 0000 (UTC)
24.2,
0.980

In our experiment code, we simply append the property name and value (as strings) to the HTTP request (making sure to replace all spaces with %20, first!).

NOTE: for...in does not guarantee any particular order for the properties that it iterates over. It will likely be the order in which they are defined, but there is no guarantee.

Light Value

You might have noticed that we are posting the raw voltage level of the photocell to data.sparkfun. Why? Well, as it turns out, most photocells are not very accurate. Additionally, the color of the light affects the measured value. For instance, our photocell is more sensitive to green light than red light. As a result, coming up with an equation to convert voltage to a light measurement (e.g. lux) is extremely difficult, especially without the ability to accurately calibrate each photocell.

So, for our purposes, we will just post the raw voltage measured from the photocell. That acts as a good relative measure for how bright the surroundings are.

Troubleshooting

  • NTP keeps failing– Check for an Internet connection with the Edison, and make sure that the NTP server is set to "pool.ntp.org".
  • Posting to data.sparkfun keeps failing– Ensure that your public and private keys are set properly. You can also add a console.log(req) just before the request(req, ...) line to verify the HTTP request string.
  • My values seem off– More than likely, this is a problem with wiring, so double-check that.

Going Further

Challenges

  1. Just something to think about: why do we need to replace all the spaces in a URL with “%20”?
  2. Change the setTimeout() function to log data once per minute (instead of once per 10 seconds). Find somewhere you can leave your Edison with the temperature and light sensors (making sure it still has an Internet connection) for a day. We recommend somewhere indoors, since the Edison is not exactly waterproof. Log data for a day, and create a graph using something like Excel, Google Sheets, or Google Charts. What interesting patterns do you notice?
  3. Create another field (of your choosing) in your stream and post a value to it along with time, temperature, and light. This can, for example, be something like the state of a button connected to the Edison.

Digging Deeper

Experiment 9: Weather on an LCD

Introduction

While the Edison itself has no standard port for monitors, we can make use of the GPIO pins to drive a different type of display: the character LCD! These somewhat simplistic liquid crystal displays (LCDs) are capable of drawing characters (and some basic shapes) in 1 or more rows.

In this exercise, we will show how to first display simple strings on the character LCD and then pull weather forecast data from the Internet and display it on the LCD.

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x Character LCD
  • 1x 10k Potentiometer
  • 16x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
Trimpot 10K with Knob

COM-09806
$0.95
6
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
Basic 16x2 Character LCD - White on Black 3.3V

LCD-09052
$14.95
1

Suggested Reading

Concepts

Parallel Interface

The character LCD that we will be using relies on a parallel interface. Instead of a predefined protocol like I2C or UART, the parallel interface sets up the bits on the wires and clocks them in on another wire.

Character LCD pinout

In our case, we will be using the LCD in 4-bit mode. We write a half-byte (nybble) by setting D4-D7 to the nybble. For example, b1011 would be HIGH, LOW, HIGH, HIGH on D4-D7. Then, we would set the R/W pin to LOW (for “write”). Finally, we toggle the E pin from LOW to HIGH, hold it for at least 150 ns, and then toggle it back LOW. This “latches” the data into the LCD. We can send all sorts of commands and data over to LCD with this!

Luckily, we won’t have to write that interface in code ourselves. We have Johnny Five to the rescue!

Johnny Five

Johnny-Five and JavaScript

Johnny-Five is a JavaScript framework for programming robotics. Much like MRAA, it simplifies the calls we need to make to control various pieces of hardware. At the time of this writing, MRAA did not support parallel interface character LCDs, but Johnny-Five does!

Johnny-Five has support for several boards, and the Edison is one of them. As a result, we can include Johnny-Five in our program (like any Node module), and have it handle LCD communications for us.

Yahoo Weather

There are plenty of weather APIs out there, and all of them would likely work for getting current weather data about a particular city. However, Yahoo Weather allows us to make calls without signing up for an account and returns data in JSON format, which is easily parsed by JavaScript.

We can perform a database lookup on Yahoo’s weather servers by constructing a SQL-like string called “YQL”. In this example, we will ultimately create a program that constructs a YQL that requests weather data for a particular city and sends it to Yahoo. Yahoo then returns a JSON object that we can parse for temperature and weather conditions.

We realize that we are glossing over SQL and YQL, as they are languages in their own right. To learn more about YQL, visit the Yahoo YQL page.

JSON

JavaScript Object Notatation, or JSON, is a text format for exchanging data between computers. It has the benefit of also being easily read by humans. It consists of a collection of name and value pairs (given as “name” : “value”) within an object (as denoted by curly braces {}).

Objects and strings within JSON can aslo be stored in an ordered array (as denoted by brackets []).

Here is an example of a JSON object (from http://json.org/example.html):

language:javascript
{"glossary": {"title": "example glossary","GlossDiv": {"title": "S","GlossList": {"GlossEntry": {"ID": "SGML","SortAs": "SGML","GlossTerm": "Standard Generalized Markup Language","Acronym": "SGML","Abbrev": "ISO 8879:1986","GlossDef": {"para": "A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso": ["GML", "XML"]
                    },"GlossSee": "markup"
                }
            }
        }
    }
}

Because this looks very much like a JavaScript object, we can easily parse it with the JSON.parse() method. After that, we can access values just by giving the name. For example, if we assigned the above example to myJSON and parsed it, myJSON.glossary.GlossDiv.title would return the string S.

Hardware Hookup

Edison LCD Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Part 1: A Simple LCD Message

The Code

Create a new Blank Template IoT Application. In package.json, paste in the following:

language:javascript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"johnny-five": "0.9.11","edison-io": "0.8.18"
  }
}

In main.js, paste in the following:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 9 - Part 1: Character LCD
 * This sketch was written by SparkFun Electronics
 * November 28, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Display a simple string on the character LCD.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// We'll need johnny-five and its Edison wrapper
var five = require('johnny-five');
var Edison = require('edison-io');

// Create a new Johnny-Five board object that we will use to talk to the LCD
var board = new five.Board({
    io: new Edison()
});

// Global variables
var lcd;

// Initialization callback that is called when Johnny-Five is done initializing
board.on('ready', function() {

    // Create our LCD object and define the pins
    // LCD pin name:    RS  EN DB4 DB5 DB6 DB7
    // Edison GPIO:     14  15  44  45  46  47
    lcd = new five.LCD({
        pins: ["GP14", "GP15", "GP44", "GP45", "GP46", "GP47"],
        rows: 2,
        cols: 16
    });

    // Make sure the LCD is on, has been cleared, and the cursor is set to home
    lcd.on();
    lcd.clear();
    lcd.home();

    // Print our string
    lcd.print("Hello, world...");

    // Move to the second line, and continue our thought
    lcd.cursor(1, 0);
    lcd.print("...again.");
});

What You Should See

Run the program, and you should see some familiar text on the LCD. Turn the potentiometer’s knob to adjust the contrast of the LCD until you see the text appear.

Edison and character LCD

Code to Note

Like any good asynchronous JavaScript library, Johnny-Five requires us to create an instance of the boarr, which we do with new five.Board(), and then wait for the board to finish initializing. We provide a callback function within board.on('ready', ...) that is run when Johnny-Five is done initializing.

Within that callback, we create an instance of our LCD (affectionately named lcd), which is part of hte Johnny-Five library. When we create the LCD object, we assign raw pin numbers to the LCD. After that, we are free to use any of the LCD methods as defined by the API. For our purposes, we make sure the LCD is on, clear it, move the cursor back to the starting position, and write some text to it.

Part 2: Weather Information

The Code

NOTE: This part of the experiment requires the Edison to have an Internet connection.

Now, we get to make our LCD do something a little more interesting. Create a new blank IoT Application template, and copy the following into package.json:

language:javascript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"johnny-five": "0.9.11","edison-io": "0.8.18"
  }
}

In main.js, copy in the following code:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 9 - Part 2: Weather
 * This sketch was written by SparkFun Electronics
 * November 29, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Download a city's weather information from Yahoo Weather
 * (https://developer.yahoo.com/weather/) and display that city's
 * temperature and current condition.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// We'll need johnny-five, the Edison wrapper, and OpenWeatherMap
var five = require('johnny-five');
var Edison = require('edison-io');
var http = require('http');

// Replace this with the city you want to get the weather from
var cityStr = "Boulder, CO";

// Create a new Johnny-Five board object that we will use to talk to the LCD
var board = new five.Board({
    io: new Edison()
});

// Initialization callback that is called when Johnny-Five is done initializing
board.on('ready', function() {

    // Create our LCD object and define the pins
    // LCD pin name:    RS  EN DB4 DB5 DB6 DB7
    // Edison GPIO:     14  15  44  45  46  47
    lcd = new five.LCD({
        pins: ["GP14", "GP15", "GP44", "GP45", "GP46", "GP47"],
        rows: 2,
        cols: 16
    });

    // Make sure the LCD is on, has been cleared, and the cursor is set to home
    lcd.on();
    lcd.clear();
    lcd.home();

    // Print a splash string
    lcd.print("My Weather App");

    // Start getting weather data
    setInterval( function() {
        getTemperature(cityStr, lcd);
    }, 5000);
});

// A function to make a request to the Yahoo Weather API
function getTemperature(cityReq, lcd) {

    // Construct YQL (https://developer.yahoo.com/weather/)
    var yql = "select * from weather.forecast where woeid in " +"(select woeid from geo.places(1) where text='" + cityReq + "')";

    // Construct GET request
    var getReq = "http://query.yahooapis.com/v1/public/yql?q=" +
                    yql.replace(/ /g,"%20") +"&format=json&env=store%3A%2F%2Fdatatables.org%2" +"Falltableswithkeys";

    // Make the request
    var request = http.get(getReq, function(response) {

        // Where we store the response text
        var body = '';

        //Read the data
        response.on('data', function(chunk) {
            body += chunk;
        });

        // Print out the data once we have received all of it
        response.on('end', function() {
            if (response.statusCode === 200) {
                try {

                    // Parse the JSON to get the pieces we need
                    var weatherResp = JSON.parse(body);
                    var channelResp = weatherResp.query.results.channel;
                    var conditionResp = channelResp.item.condition;

                    // Extract the city and region
                    var city = channelResp.location.city;
                    var region = channelResp.location.region;

                    // Get the local weather
                    var temperature = conditionResp.temp;
                    var tempUnit = channelResp.units.temperature;
                    var description = conditionResp.text;

                    // Construct city and weather strings to be printed
                    var cityString = city + ", " + region;
                    var weatherString = temperature + tempUnit + "" +
                                        description;

                    //Print the city, region, time, and temperature
                    console.log(cityString);
                    console.log(weatherString + "\n");

                    // Truncate the city and weather strings to fit on the LCD
                    cityString = cityString.substring(0, 16);
                    weatherString = weatherString.substring(0, 16);

                    // Print them on the LCD
                    lcd.clear();
                    lcd.home();
                    lcd.print(cityString);
                    lcd.cursor(1, 0);
                    lcd.print(weatherString);

                } catch(error) {

                    // Report problem with parsing the JSON
                    console.log("Parsing error: " + error);
                }
            } else {

                // Report problem with the response
                console.log("Response error: " +
                            http.STATUS_CODES[response.statusCode]);
            }
        })
    });

    // Report a problem with the connection
    request.on('error', function (err) {
        console.log("Connection error: " + err);
    });
}

What You Should See

Run the code on the Edison, and you should see a splash screen of “My Weather App”, which will then change into the weather for Boulder, CO.

Edison and LCD showing current weather in Boulder, CO

Code to Note

We have used the http module before to create a server, but now, we are using it to issue HTTP GET requests to a remote server. In this case, we construct a query consisting of the city we want to search for usign YQL. We send that request to Yahoo with http.get().

Once again, we create a callback, but this time in http.get(). If all goes well, Yahoo’s server responds with the code “200” (which means “OK” in HTTP code-speak) along with a JSON containing the requested data.

We parse that data with JSON.parse() and extract the pieces we want (city, region, temperature, temperature unit, and weather condition. We then display that information both in the console and on the LCD.

Troubleshooting

  • The LCD does not work or displays garbage– More than likely, this is a wiring problem. Double-check the wires and move them around to make sure they are making good contact in the breadboard.
  • The LCD is on but not displaying anything– Turn the knob on the potentiometer to adjust the contrast on the LCD.
  • I get errors trying to request weather data– This could be a few things:
    • Make sure the Edison has an Internet connection (try logging in and issuing a ping command from the Edison)
    • Make sure that citystr is a viable location request to YQL. Try a known location first, such as “Boulder, CO”.

Going Further

Challenges

  1. Go back to part 1 and make the LCD say something of your choosing, for example, your name.
  2. Notice that we are truncating the strings before we send them to the LCD in part 2. Have the LCD scroll the text so that we don’t have to truncate it. Hint: See the Johnny-Five LCD API.
  3. Display a different piece of weather information on the LCD. For example, show the wind speed of a city of your choosing.

Digging Deeper

Experiment 10: Keyboard

Introduction

The Edison, luckily for us, has a USB On-the-Go (OTG) port, which means that we can optionally treat the Edison as a USB host or a USB device. In this experiment, we will use the OTG port as a USB host port and connect a keyboard to our Edison. We will then be able to type and have the characters appear on the LCD.

In the second part of the experiment, we take the concept one step further and have the Edison host a web page that acts as a simplistic chat room. Anyone on the same network can view the page, post messages, and see messages from the Edison (as they were typed into the keyboard).

You will need to provide your own USB keyboard for this example. Not all keyboards will work. Do not feel obligated to complete this experiment if you cannot find a USB keyboard that will work.
NOTE: Because we are using the OTG port in this experiment, you will not be able to use it to create a USB network with the Edison. You will need to connect the XDK to your Edison over WiFi instead.

Parts Needed

We’ll be using the same circuit as in the previous example. The only thing we will be adding is the USB OTG cable, which will be plugged into the Base Block. In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x Character LCD
  • 1x 10k Potentiometer
  • 16x Jumper Wires
  • 1x USB OTG Cable
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
Trimpot 10K with Knob

COM-09806
$0.95
6
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
Basic 16x2 Character LCD - White on Black 3.3V

LCD-09052
$14.95
1
USB OTG Cable - Female A to Micro A - 4"

CAB-11604
$2.95
1

Suggested Reading

Concepts

USB OTG

USB OTG is an interesting concept in the world of computer peripherals. Most USB connections require a host and a device (or several devices that have been plugged into a hub that goes to a host). However, OTG allows for a device to automatically detect whether it should play the role of a host or a peripheral.

Normally, USB plugs have 4 pins. OTG introduces a fifth pin (known as the “ID pin”) that allows the device to determine if it should be a host or a peripheral.

USB AB pinout

In our case, we will be using a special OTG cable that enumerates that ID pin and terminates with a normal type-A receptacle. This allows us to plug in USB peripherals (such as keyboards and mice) and the Edison will become the USB host.

If you were using the OTG port for previous exercises to create a USB network, you were putting the Edison into device mode. The powers of OTG are very useful.

Linux Hacking

OK, we’re not going to actually hack Linux. However, we are going dig into the file system in order to detect key presses on the keyboard.

Whenever we plug in a keyboard, Linux creates a file in /dev/input/ with the name eventX, where X is a number assigned to that device. In our Edison, the keyboard is event2, assuming no other devices are plugged in (you can also figure out which device is your keyboard by logging into the Edison and executing the command cat /proc/bus/input/devices).

If we read the contents of this file, it updates every time a keyboard event occurs (e.g. key down, key up). We can create a stream listener with fs.readStreamListener() on this file that calls a function every time new data appears in the file.

The data that is provided to the callback is in the form of a fairly large buffer of raw bytes. Knowing that, we can look at specific bytes to figure out what kind of event is occurring:

  • Byte 24 is a key event
  • Byte 28 is the type of event (0x01 means “key down”)
  • Bytes 26 and 27 refer to the key that has been pressed (for example, 19 is the ‘r’ key)

The input event codes can be found in the input-event-codes.h file.

Chat Room

Chat rooms are nearly as old as the Internet itself. Dating back to the early 1970s, users could send text messages to everyone viewing a page or connected with a special program.

We are going to construct a very simple chat room using Socket.IO. In this exercise, we create a web page with three fields. At the bottom, users can enter a text message and send it with a button. Taking up most of the page is the “room” itself.

When a user sends a message, the text is sent to the server running the chat room (the Edison, in this case), and the server then sends out that text to all users currently looking at the page in a browser.

Hardware Hookup

The circuit is the same as in the previous experiment.

Edison LCD Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Plug the USB OTG cable into the port labeled “OTG” on the Base Block. Plug your USB keyboard into the other end of the OTG cable.

Keyboard plugged into USB OTG port of the Edison

Part 1: Keyboard to LCD

The Code

Create a new Blank IoT Application Template. Copy the following into package.json:

language:javascript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"johnny-five": "0.9.11","edison-io": "0.8.18"
  }
}

In the file explorer, create a new directory named libs. In libs, create a file named keymap.js. In that file, copy in the following:

language:javascript
// Puts all key presses into a lookup table
module.exports = {
    keys: [     // code key
        null,   // 0    reserved
        null,   // 1    esc"1",    // 2    1"2",    // 3    2"3",    // 4    3"4",    // 5    4"5",    // 6    5"6",    // 7    6"7",    // 8    7"8",    // 9    8"9",    // 10   9"0",    // 11   0"-",    // 12   minus"=",    // 13   equal"bksp", // 14   backspace
        null,   // 15   tab"q",    // 16   q"w",    // 17   w"e",    // 18   e"r",    // 19   r"t",    // 20   t"y",    // 21   y"u",    // 22   u"i",    // 23   i"o",    // 24   o"p",    // 25   p"[",    // 26   left brace"]",    // 27   right brace"enter",// 28   enter
        null,   // 29   left ctrl"a",    // 30   a"s",    // 31   s"d",    // 32   d"f",    // 33   f"g",    // 34   g"h",    // 35   h"j",    // 36   j"k",    // 37   k"l",    // 38   l";",    // 39   semicolon"'",    // 40   apostrophe"`",    // 41   grave
        null,   // 42   left shift"\\",   // 43   backslash"z",    // 44   z"x",    // 45   x"c",    // 46   c"v",    // 47   v"b",    // 48   b"n",    // 49   n"m",    // 50   m",",    // 51   comma".",    // 52   dot"/",    // 53   slash
        null,   // 54   right shift
        null,   // 55   kpasterisk
        null,   // 56   left alt""     // 57   space
    ]
};

Your project should have the following files:

Add the keymap file to the XDK

In main.js, copy in:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 10 - Part 1: Keyboard
 * This sketch was written by SparkFun Electronics
 * November 18, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Capture keystrokes from a USB-connected keyboard and display them on a
 * character LCD.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the filesystem module and our keymap table
var fs = require('fs');
var keymap = require('./libs/keymap.js');

// We'll also need johnny-five and its Edison wrapper
var five = require('johnny-five');
var Edison = require('edison-io');
var board = new five.Board({
    io: new Edison()
});

// Global variables
var lcd;
var cursorPos;

// Johnny Five initialization
board.on('ready', function() {

    // Create our LCD object and define the pins
    // LCD pin name:    RS  EN DB4 DB5 DB6 DB7
    // Edison GPIO:     14  15  44  45  46  47
    lcd = new five.LCD({
        pins: ["GP14", "GP15", "GP44", "GP45", "GP46", "GP47"],
        backlight: 6,
        rows: 2,
        cols: 16
    });

    // Turn on LCD, clear it, and set cursor to home
    lcd.on();
    lcd.clear();
    lcd.home();
    lcd.blink();
    cursorPos = 0;
    console.log("Start typing!");
});

// Create a stream that emits events on every key stroke
var readableStream = fs.createReadStream('/dev/input/event2');

// Callback for a key event
readableStream.on('data', function(buf) {

    // Check for key down event and determine key pressed
    if ((buf[24] == 1) && (buf[28] == 1)) {
        var keyCode = ((buf[27] & 0xff) << 8) | (buf[26] & 0xff);
        var keyChar = keymap.keys[keyCode];

        // Make the character appear on the LCD
        if (lcd !== undefined) {

            // If it is a backspace, delete the previous character
            if (keyChar === 'bksp') {
                cursorPos--;
                if (cursorPos <= 0) {
                    cursorPos = 0;
                }
                lcd.print("");
                lcd.cursor(
                    Math.floor(cursorPos / lcd.cols),
                    (cursorPos % lcd.cols)
                );
                lcd.print("");
                lcd.cursor(
                    Math.floor(cursorPos / lcd.cols),
                    (cursorPos % lcd.cols)
                );

            // If it is a return character, clear the LCD
            } else if (keyChar == 'enter') {
                lcd.clear();
                cursorPos = 0;

            // Otherwise, print the character to the LCD
            } else if ((keyChar !== null) && (keyChar !== undefined)) {
                lcd.print(keyChar);
                cursorPos++;
            }

            // Stop the cursor at the end of the LCD
            if (cursorPos >= (lcd.rows * lcd.cols)) {
                cursorPos = (lcd.rows * lcd.cols) - 1;
            }

            // Update the cursor position (wrap to second line if needed)
            lcd.cursor(
                Math.floor(cursorPos / lcd.cols),
                (cursorPos % lcd.cols)
            );
        }
    }
});

What You Should See

Make sure that your keyboard is plugged into the OTG port and run the program. You should be able to type on the keyboard and have the text appear on the LCD!

Typing on a USB keyboard connected to the Edison

Code to Note

readableStream.on('data', function(buf) {...}) is the callback for when the /dev/input/event2 file receives new data (e.g. a key was pressed). Within the function of the callback, we figure out which key was pressed by looking at specific bytes in buf.

Using bytes 26 and 27 of buf, we create an index for our lookup table (called keymap). This keymap was created in the keymap.js file. The keymap is just an array. When we index into the array with the number created from bytes 26 and 27, we are returned a string corresponding to the key that was pushed.

You might have noticed that we defined our keymap table in a separate file (keymap.js). We can store functions, variables, objects, etc. in another file and access them if we do 2 things:

  1. Define an exports object in the external file with module.exports. This allows properties of that object to be accessed by code in the importing file. In this case, we want access to the keys array.
  2. In the importing file (main.js in this instance), include the external file with a require() statement and assign it to a variable. In this case, we included the keymap.js file with var keymap = require('./libs/keymap.js');. Then, we were able to access the keys variable with keymap.keys later in the code.

Part 2: Chat Room

The Code

NOTE: This part of the experiment requires the Edison to have an Internet connection.

Create another project with the Blank IoT Application Template. In package.js, copy in:

language:javascript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"socket.io": "1.3.7","express": "4.10.2","johnny-five": "0.9.11","edison-io": "0.8.18"
  }
}

Like in part 1, create a new directory and file within the project: libs/keymap.js. In that file, copy in:

language:javascript
// Puts all key presses into a lookup table
module.exports = {
    keys: [     // code key
        null,   // 0    reserved
        null,   // 1    esc"1",    // 2    1"2",    // 3    2"3",    // 4    3"4",    // 5    4"5",    // 6    5"6",    // 7    6"7",    // 8    7"8",    // 9    8"9",    // 10   9"0",    // 11   0"-",    // 12   minus"=",    // 13   equal"bksp", // 14   backspace
        null,   // 15   tab"q",    // 16   q"w",    // 17   w"e",    // 18   e"r",    // 19   r"t",    // 20   t"y",    // 21   y"u",    // 22   u"i",    // 23   i"o",    // 24   o"p",    // 25   p"[",    // 26   left brace"]",    // 27   right brace"enter",// 28   enter
        null,   // 29   left ctrl"a",    // 30   a"s",    // 31   s"d",    // 32   d"f",    // 33   f"g",    // 34   g"h",    // 35   h"j",    // 36   j"k",    // 37   k"l",    // 38   l";",    // 39   semicolon"'",    // 40   apostrophe"`",    // 41   grave
        null,   // 42   left shift"\\",   // 43   backslash"z",    // 44   z"x",    // 45   x"c",    // 46   c"v",    // 47   v"b",    // 48   b"n",    // 49   n"m",    // 50   m",",    // 51   comma".",    // 52   dot"/",    // 53   slash
        null,   // 54   right shift
        null,   // 55   kpasterisk
        null,   // 56   left alt""     // 57   space
    ]
};

Create a new file in the project called index.html, and copy in the following:

language:html<!doctype html><html><head><title>Socket.IO chat</title><style>
            * { margin: 0; padding: 0; box-sizing: border-box; }
            body { font: 13px Helvetica, Arial; }
            form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
            form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
            form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
            #messages { list-style-type: none; margin: 0; padding: 0; }
            #messages li { padding: 5px 10px; }
            #messages li:nth-child(odd) { background: #eee; }</style></head><body><ul id="messages"></ul><form action=""><input id="m" autocomplete="off" /><button>Send</button></form><script src="/socket.io/socket.io.js"></script><script src="http://code.jquery.com/jquery-1.11.1.js"></script><script src="http://code.jquery.com/jquery-2.1.4.js"></script><script>

            // Create our socket.io object
            var socket = io();

            // Get content from the input box and sent it to the server
            $('form').submit(function() {
                socket.emit('chat message', $('#m').val());
                $('#m').val('');
                return false;
            });

            // If we receive a chat message, add it to the chat box
            socket.on('chat message', function(msg) {
                $('#messages').append($('<li>').text(msg));
            });</script></body></html>

Save that file. You should have the following files:

Hosting a chat room from the Edison

In main.js, copy in:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 10 - Part 2: Chat Room
 * This sketch was written by SparkFun Electronics
 * November 20, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Serves a chat room where users can post messages. Captures keyboard input
 * and posts messages to the chat room.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the filesystem module and our keymap table
var fs = require('fs');
var keymap = require('./libs/keymap.js');

// We'll also need johny-five and its Edison wrapper
var five = require('johnny-five');
var Edison = require('edison-io');
var board = new five.Board({
    io: new Edison()
});

// Import HTTP and Express modules
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

// Global variables
var port = 4242;
var lcd;

// Johnny Five initialization
board.on('ready', function() {

    // Create our LCD object and define the pins
    // LCD pin name:    RS  EN DB4 DB5 DB6 DB7
    // Edison GPIO:     14  15  44  45  46  47
    lcd = new five.LCD({
        pins: ["GP14", "GP15", "GP44", "GP45", "GP46", "GP47"],
        backlight: 6,
        rows: 2,
        cols: 16
    });

    // Turn on LCD, clear it, and set cursor to home
    lcd.on();
    lcd.clear();
    lcd.home();
    lcd.blink();
    lcd.cursorPos = 0;
    lcd.msg = "";
    console.log("Start typing!");
});

// Create a stream that emits events on every key stroke
var readableStream = fs.createReadStream('/dev/input/event2');

// Callback for a key event
readableStream.on('data', function(buf) {

    // Check for key down event and determine key pressed
    if ((buf[24] == 1) && (buf[28] == 1)) {
        var keyCode = ((buf[27] & 0xff) << 8) | (buf[26] & 0xff);
        var keyChar = keymap.keys[keyCode];

        // Make the character appear on the LCD
        if (lcd !== undefined) {

            // If it is a backspace, delete the previous character
            if (keyChar === 'bksp') {
                if (lcd.msg !== "") {
                    lcd.msg = lcd.msg.slice(0, -1);
                }
                lcd.cursorPos--;
                if (lcd.cursorPos <= 0) {
                    lcd.cursorPos = 0;
                }
                lcd.print("");
                lcd.cursor(
                    Math.floor(lcd.cursorPos / lcd.cols),
                    (lcd.cursorPos % lcd.cols)
                );
                lcd.print("");
                lcd.cursor(
                    Math.floor(lcd.cursorPos / lcd.cols),
                    (lcd.cursorPos % lcd.cols)
                );

            // If it is a return character, post message and clear the LCD
            } else if (keyChar == 'enter') {
                console.log("Server: " + lcd.msg);
                io.emit('chat message', "Server: " + lcd.msg);
                lcd.clear();
                lcd.cursorPos = 0;
                lcd.msg = "";

            // Otherwise, print the character to the LCD
            } else if ((keyChar !== null) && (keyChar !== undefined)) {

                // Have the character appear on the LCD and append to message
                lcd.print(keyChar);
                lcd.cursorPos++;

                // Stop the cursor at the end of the LCD
                if (lcd.cursorPos >= (lcd.rows * lcd.cols)) {
                    lcd.cursorPos = (lcd.rows * lcd.cols) - 1;
                }

                // Remove the last char if we reached the end of the buffer
                if (lcd.msg.length >= (lcd.rows * lcd.cols)) {
                    lcd.msg = lcd.msg.slice(0, -1);
                }

                // Append character to message
                lcd.msg = lcd.msg.concat(keyChar);
            }

            // Update the cursor position (wrap to second line if needed)
            lcd.cursor(
                Math.floor(lcd.cursorPos / lcd.cols),
                (lcd.cursorPos % lcd.cols)
            );
        }
    }
});

// Send the web page on client request
app.get('/', function(req, res) {
    res.sendFile(__dirname + "/index.html");
});

// Create a handler for when a client connects
io.on('connection', function(socket) {
    var clientIP = socket.client.conn.remoteAddress;

    // If we get a chat message, send it out to all clients
    socket.on('chat message', function(msg) {
        console.log(clientIP + ": " + msg);
        io.emit('chat message', clientIP + ": " + msg);
    });
});

// Start the server
http.listen(4242, function() {
    console.log('Server listening on port ' + port);
});

What You Should See

You should be able type on the keyboard and have the text appear on the LCD, like in part 1.

Entering a message for the chatroom on the Edison

However, if you open a browser on a computer that is on the same network as the Edison, you should be able to browse to http://<Edison's IP address>:4242 and see a simple chat room. Enter in some text at the bottom. Then, type in some text on the keyboard attached to the Edison. Press ‘enter’ to send that message to the chat room!

Simple chat room with the Edison

Code to Note

language:javascript
app.get('/', function(req, res) {
    res.sendFile(__dirname + "/index.html");
});

Serves the web page (index.html) to the client’s browser on a request.

language:javascript
// If we get a chat message, send it out to all clients
socket.on('chat message', function(msg) {
    console.log(clientIP + ": " + msg);
    io.emit('chat message', clientIP + ": " + msg);
});

This is the crux of the chat room. Any new message we receive from the socket.io connection, we broadcast it to all other clients connected.

In index.html, we handle text entry with:

language:javascript
$('form').submit(function() {
    socket.emit('chat message', $('#m').val());
    $('#m').val('');
    return false;
});

When we click the “Send” button, we capture the text in the input box and send it to the server (Edison). the Edison then relays that text, and we look for messages from the Edison with:

language:javascript
socket.on('chat message', function(msg) {
    $('#messages').append($('<li>').text(msg));
});

On a message from the Edison, we add it as a list item in the main messages pane.

Troubleshooting

  • The LCD isn’t working!– Double-check the wiring and adjust the potentiometer.
  • Nothing happens when I type on the keyboard– Make sure that the keyboard is plugged into the OTG port on the Base Block. Additionally, some keyboards are not supported, so we recommend trying a different USB keyboard, if you can.

Going Further

Challenges

  1. You might have noticed that capital letters are not supported from the keyboard. We can detect that the shift key has been pushed, but in our examples, we ignore it. Make the shift key work and have capital letters actually appear on the LCD and in the chat room!
  2. Create a chat room log. By default, once messages are broadcast, they only appear in the browsers for clients who are connected. Sometimes, it is helpful for the server to maintain a log of all the messages that appeared in the chat room. Devise a way to store all messages into a file on the Edison so that it can later be read (also known as “auditing”).

Digging Deeper

Experiment 11: Phone Accelerometer

One interesting feature of the XDK is its ability to let us create cross-platform programs for various phone operating systems without having to rewrite code in different langauges. This ability is possible thanks to a framework called Cordova. Cordova allows us to write programs in HTML and JavaScript (much like the web apps we wrote in previous exercises) but includes plugins that allow us to control hardware components in the phone (e.g. GPS, accelerometer, etc.).

In addition to Cordova, we are also going to introduce Bluetooth Low Energy (BLE) communication. BLE is very useful for communicating between devices within a very short distance of each other.

In the end, we want to turn our phone into a type of controller that reads accelerometer data, sends it to the Edison over BLE, and moves a character on an LCD attached to the Edison.

IMPORTANT: Cordova needs to run native code on your smartphone in order to operate. As a result, you will need to be able to install native apps.
  • If you have an iPhone, you will need to enroll in the Apple Developer Program (there is a yearly membership fee) and create Ad Hoc Provisioning Profiles (discussed later)
  • If you have an Android, you can allow the installation of apps from "Unknown Sources" and install the app from a downloaded .apk file

Parts Needed

We’ll be using the same circuit as in the previous example, only without the keyboard and USB OTG cable. In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x Character LCD
  • 1x 10k Potentiometer
  • 16x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
Trimpot 10K with Knob

COM-09806
$0.95
6
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
Basic 16x2 Character LCD - White on Black 3.3V

LCD-09052
$14.95
1

Suggested Reading

Concepts

Accelerometer

Most modern accelerometers measure acceleration (or g-force) by using a tiny electromechanical system: small beams that moves when the system undergoes some type of acceleration. The chip can measure the capacitance between sets of beams and determine the acceleration of the device.

Example of an accelerometer

Most modern cell phones contain built-in accelerometers. Most often, they are used to determine the orientation of the phone (as gravity offers a 9.8 m/s acceleration toward the center of the Earth). This information allows the phone to adjust the contents of the screen to always be “up” for the user!

In this experiment, we are going to use our smartphone’s internal accelerometer to control something on the Edison.

Cordova

Cordova bot

Cordova is an open-source framework for creating smartphone apps in standard web languages (e.g. JavaScript, HTML, CSS). It allows developers to access low-level features of the phone, such as GPS and the accelerometer as well as create apps that compile for multiple mobile operating systems, such as iOS and Android, with one set of code.

Cordova relies on a set of plugins that enables developers to call native phone features without having to write native code. In essence, the plugins offer a JavaScript API for calling native features. We will use some of these plugins to access the accelerometer and Bluetooth radio in the phone.

Bluetooth Low Energy

Bluetooth logo

Bluetooth is a protocol for sending and receiving data over a 2.4 GHz wireless link. It was designed to be low-power, low-cost, and short-range. Many devices, including most smartphones, have embedded Bluetooth radios, which allow them to talk to other devices and peripherals, like keyboards and pedometers.

Bluetooth Low Energy is an extension of Bluetooth that was introduced in the Bluetooth 4.0 standard. It offers a huge reduction in power consumption by sacrificing range and data throughput.

Along with great power savings came a new set of terminology and programming model. BLE uses the concept of “servers” and “clients.”

  • Client– A device that initiates a commands and connections. For example, your smartphone.
  • Server– A device that accepts commands and returns responses. For example, a temperature sensor.

We also need to be aware of how BLE groups data:

  • Service– A group of related characteristics
  • Characteristic– A data value to be transferred between a server and a client
  • Descriptor– Additional information about the characteristic. For example, an indication of units (e.g. Celsius).

Note that what we have described is the Generic Attribution Profile (GATT). BLE also defines a Generic Access Pofile (GAP) that allows a peripheral to broadcast to multiple central devices, but we will not be using it in this experiment.

In our example, we will treat the Edison as the server (using the bleno module) and the smartphone as the client (using cordova-plugin-ble-central).

Hardware Hookup

The circuit is the same as in the previous experiment.

Edison LCD Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

The Code

Edison Code

Unfortunately, at this time, the Edison does not enable its Bluetooth radio by default and runs bluetoothd on default, which conflicts with our bleno module. To fix it, we need to issue a few commands in order to use it. Log in to the Edison over SSH or serial and enter your credentials (username root and the password you’ve created).

Enter the following commands:

rfkill unblock bluetooth
killall bluetoothd
hciconfig hci0 up
IMPORTANT! The Edison will re-block bluetooth and begin running bluetoothd on every reboot. As a result, you will need to issue these commands every time you boot up the Edison before running a Bluetooth Low Energy application.

We will need to copy the Bluetooth MAC address of the Edison so that we can connect to it from our phone. To do that, enter the following command into your SSH or serial console:

hciconfig dev

You should have 1 (possibly more) entries. One of them should be labeled “hci0,” which is our Bluetooth device. Copy or write down the 6 hexadecimal numbers under BD Address.

Learning the Bluetooth MAC address

Create a new Blank IoT Application and copy the following into package.json:

language:javascript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"bleno": "0.3.3","johnny-five": "0.9.14","edison-io": "0.8.18"
  }


}

Copy the following into main.js:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 11: Edison BLE Display
 * This sketch was written by SparkFun Electronics
 * November 30, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Accepts a connection from a smartphone and processes accelerometer data
 * from the cell phone (sent over BLE). Displays a character on the LCD that is
 * moved with the phone's accelerometer data.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// bleno makes the Edison act as a BLE peripheral
var bleno = require('bleno');

// We'll also need johnny-five and its Edison wrapper
var five = require('johnny-five');
var Edison = require('edison-io');

// Global game object
var game = {
    lcd: null,
    charX: 7,
    prevX: 0
};

// Create a new Johnny-Five board object that we will use to talk to the LCD
var board = new five.Board({
    io: new Edison()
});

// BLE service and characteristic information
var edison = {
    name: "Edison",
    deviceId: null,
    service: "12ab",
    characteristic: "34cd"
};

// Define our display characteristic, which can be subscribed to
displayCharacteristic = new bleno.Characteristic({
    uuid: edison.characteristic,
    properties: ['write'],
    onWriteRequest : function(data, offset, withoutResponse, callback) {

        // Parse the incoming data into X, Y, and Z acceleration values
        var accel = {
            x: data.readInt16LE(0) / 100,
            y: data.readInt16LE(2) / 100,
            z: data.readInt16LE(4) / 100
        };

        // Write the X, Y, and Z values to the console
        console.log("Write request: X=" + accel.x +" Y=" + accel.y +" Z=" + accel.z);

        // Update character's position and bound it to the limits of the LCD
        game.charX += accel.y / 10;
        if (game.charX < 0) {
            game.charX = 0;
        }
        if (game.charX > 15) {
            game.charX = 15;
        }

        callback(this.RESULT_SUCCESS);
    }
});

// Once bleno starts, begin advertising our BLE address
bleno.on('stateChange', function(state) {
    console.log('State change: ' + state);
    if (state === 'poweredOn') {
        bleno.startAdvertising(edison.name,[edison.service]);
    } else {
        bleno.stopAdvertising();
    }
});

// Notify the console that we've accepted a connection
bleno.on('accept', function(clientAddress) {
    console.log("Accepted connection from address: " + clientAddress);
});

// Notify the console that we have disconnected from a client
bleno.on('disconnect', function(clientAddress) {
    console.log("Disconnected from address: " + clientAddress);
});

// When we begin advertising, create a new service and characteristic
bleno.on('advertisingStart', function(error) {
    if (error) {
        console.log("Advertising start error:" + error);
    } else {
        console.log("Advertising start success");
        bleno.setServices([

            // Define a new service
            new bleno.PrimaryService({
                uuid: edison.service,
                characteristics: [
                    displayCharacteristic
                ]
            })
        ]);
    }
});

// Initialization callback that is called when Johnny-Five is done initializing
board.on('ready', function() {

    // Create our LCD object and define the pins
    // LCD pin name:    RS  EN DB4 DB5 DB6 DB7
    // Edison GPIO:     14  15  44  45  46  47
    game.lcd = new five.LCD({
        pins: ["GP14", "GP15", "GP44", "GP45", "GP46", "GP47"],
        rows: 2,
        cols: 16
    });

    // Make sure the LCD is on, has been cleared, and the cursor is set to home
    game.lcd.on();
    game.lcd.clear();
    game.lcd.home();

    // Start running the game thread
    setInterval(draw, 50);
});

// Main game thread
function draw() {

    // Erase previous character
    game.lcd.cursor(0, game.prevX);
    game.lcd.print("");

    // Set cursor to character's current position
    var x = Math.round(game.charX);
    game.lcd.cursor(0, x);

    // Draw character
    game.lcd.print("o");

    // Set previous character location
    game.prevX = x;
}

Upload and run the code. We want the Edison to be looking for connection requests from the smartphone when we start running the phone app.

Phone App

We need to create a Cordova app. To do that, create a new project in the XDK and select HTML5 + Cordova under Blank Templates in HTML5 Companion Hybrid Mobile or Web App.

Creating a Cordova app in XDK

Give your app some appropriate name and click Create. You should be presented with a development environment much like the one for the web app. In the upper-left corner of the XDK, click the word Projects.

Project settings for the XDK

You will be brought to the project settings. Under Cordova Hybrid Mobile App Settings, expand Plugin Management, and click Add plugins to this project.

Add a new plugin to Codova

Click on Third-Party Plugins and enter cordova-plugin-ble-central into the Plugin ID field.

Adding BLE plugin to Cordova

Click Add Plugin, and repeat this same process to add cordova-plugin-device-motion, which allows us to access the phone’s accelerometer. Once you have added the two plugins, you should see them listed under Plugin Management in the project settings.

Two plugins added to Cordova in XDK

Before we can add code, we need to include jQuery. Download the latest, uncompressed version of jQuery from http://jquery.com/download/. Create two new directories in your project so that you have /www/lib/jquery. Copy the .js file into the jquery directory.

Go back to the Develop tab. In www/index.html, copy in the following:

language:html<!DOCTYPE html><!--
SparkFun Inventor's Kit for Edison
Experiment 11: Accelerometer Demo
This sketch was written by SparkFun Electronics
November 29, 2015
https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments

Runs as BLE central on smartphone. Connects to the Edison and sends
accelerometer data.

Released under the MIT License(http://opensource.org/licenses/MIT)
--><html><head><title>Accelerometer</title><meta http-equiv="Content-type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=no"><style>
        @-ms-viewport { width: 100vw ; min-zoom: 100% ; zoom: 100% ; }  @viewport { width: 100vw ; min-zoom: 100% zoom: 100% ; }
        @-ms-viewport { user-zoom: fixed ; min-zoom: 100% ; }           @viewport { user-zoom: fixed ; min-zoom: 100% ; }
        .accel {
            clear:both;
            font-family:Arial;
            font-size:14pt;
            margin: auto;
            text-align:right;
            width: 280px;
        }
        .accel:after {
            visibility: hidden;
            display: block;
            font-size: 0;
            content: "";
            clear: both;
            height: 0;
        }
        .accel * {
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
        }
        .accel div {
            background-color:#B6B6B6;
            float: left;
            padding: 3px;
            width: 20%;
        }
        .accel div.label {
            background: transparent;
            font-weight: bold;
            width: 10%;
        }</style></head><body><!-- Our header --><h3 style="text-align:center;">Accelerometer Demo</h3><style></style><!-- X, Y, Z accelerometer fields --><div class="accel"><div class="label">X:</div><div id="x">0.00</div><div class="label">Y:</div><div id="y">0.00</div><div class="label">Z:</div><div id="z">0.00</div></div><!-- Debugging --><div style="margin:auto;
                width:280px;
                height:20px;
                padding:1px;">
        Debugging console</div><div id="debug_box" style="margin:auto;
                               width:280px;
                               height:240px;
                               padding:1px;
                               overflow:auto;
                               background:#0d0d0d;"><ul id="debug" style="color:#00BB00;"></ul></div><!-- Load the various JavaScript files --><script type="text/javascript" src="cordova.js"></script><script type="text/javascript" src="lib/jquery/jquery-2.1.4.js"></script><script type="text/javascript" src="js/app.js"></script></body></html>

In www/js/app.js, copy in the following:

language:javascript
/*jslint unparam: true */
/*jshint strict: true, -W097, unused:false,  undef:true, devel:true */
/*global window, document, d3, $, io, navigator, setTimeout */
/*global ble*/

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 11: Accelerometer Demo
 * This sketch was written by SparkFun Electronics
 * November 29, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Runs as BLE central on smartphone. Connects to the Edison and sends
 * accelerometer data.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Put in strict mode to restrict some JavaScript "features""use strict" ;

// BLE service and characteristic information
window.edison = {
    deviceId: "98:4F:EE:04:3E:F9",
    service: "12ab",
    characteristic: "34cd"
};

/******************************************************************************
 * Bluetooth connection
 *****************************************************************************/

// Global app object we can use to create BLE callbacks
window.app = {

    // A way for us to reference the thread
    watchID: null,

    // Call this first!
    initialize: function() {
        window.app.connect();
    },

    // Scan for and connect to our statically-encoded Edison MAC address
    connect: function() {
        ble.scan([],
                 5,
                 window.app.onDiscoverDevice,
                 window.app.onError);
    },

    // Find BLE devices in range and connect to the Edison
    onDiscoverDevice: function(device) {
        debug("Found " + device.name + " at " + device.id);
        if (device.id === window.edison.deviceId) {
            debug("Connecting to: " + window.edison.deviceId);
            ble.connect(window.edison.deviceId,
                        window.app.onConnect,
                        window.app.onError);
        }
    },

    //  On BLE connection, notify the user
    onConnect: function() {
        debug("Connected to " + window.edison.deviceId);

        // Set the accelerometer to sample and send data every 100 ms
        window.watchID = navigator.accelerometer.watchAcceleration(
            function(acceleration) {
                window.app.onAccelerometer(acceleration, window);
            },
            window.app.onError,
            { frequency: 100 }
        );
    },

    // This gets executed on new accelerometer data
    onAccelerometer: function(accel, win) {

        // Create an array of accelerometer values
        var a = [accel.x, accel.y, accel.z];

        // Set new values for X, Y, and Z acceleration on phone
        $('#x')[0].innerHTML = a[0].toFixed(2);
        $('#y')[0].innerHTML = a[1].toFixed(2);
        $('#z')[0].innerHTML = a[2].toFixed(2);

        // Assign X, Y and Z values to a 16-bit, signed integer array
        var buf = new Int16Array(3);
        buf[0] = a[0] * 100;
        buf[1] = a[1] * 100;
        buf[2] = a[2] * 100;

        // Write data to the characteristic
        ble.write(win.edison.deviceId,
                  win.edison.service,
                  win.edison.characteristic,
                  buf.buffer);
                  //function() {debug("Acc data written!");},
                  //function() {debug("Acc data NOT written");});
    },

    // Alert the user if there is an error
    onError: function(err) {
        navigator.accelerometer.clearWatch(window.watchID);
        debug("Error: " + err);
        alert("Error: " + err);
    }
};

/******************************************************************************
 * Execution starts here after the phone has finished initializing
 *****************************************************************************/

// Wait for the device (phone) to be ready before connecting to the Edison
// and polling the accelerometer
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {

    // Prepare the BLE connection
    window.app.initialize();
}

// Create a pseudo-debugging console
// NOTE: Real apps can also use alert(), but list messages can be useful when
// you are debugging the program
function debug(msg) {
    $('#debug').append($('<li>').text(msg));
}

Remember the Bluetooth MAC address that we copied from the Edison? You will need to find the MAC address in the code and replace it with your MAC address. Look for "98:4F:EE:04:3E:F9" (my MAC address) under window.edison and replace it with the Bluetooth MAC address for your Edison.

Building the Phone App

Unlike the web apps we made in previous experiments, we need to actually build our project because we are including native code as part of the Cordova framework. In the XDK, go to the Build tab.

XDK Build tab

Click Build on the phone OS of your choice and follow the instructions.

iPhone

Intel’s

Go to the iOS Certs tab and follow the directions on the screen.

iOS certificate creation in XDK

You will first need to create an iOS Certificate Signing Request (CSR). Upload that file to the Apple Developers iOS certificate page in order to generate an ad-hoc certificate signed by Apple. Note that this requires you to be enrolled in the Apple Developer Program.

A walkthrough with screenshots for creating an ad-hoc certificate can be found here.

Android

Upload and build your program. Once it is complete, you should see an option to Download Build.

alt text

This will download a .apk file, which you can install directly from your Android phone. However, you will need to allow installation of apps from Unknown Sources from the Security features in Settings.

Unknown Sources in Android

From there, you can simply find the .apk package in a file browser and tap on it to install the program.

.apk in file browser

Other

More information about the build process for iOS, Android, and other phone operating systems can be found on Intel’s site.

What You Should See

With the Edison running, start the phone app. The app should automatically connect to the Edison over BLE. You will see a notification in the “debug” area.

Connecting to the Edison over BLE

Hold your phone parallel to the ground (in a landscape fashion), and tilt it from side to side. The character on the LCD should move based on the direction of the tilt!

Playing the tilt game with the Edison

Code to Note

bleno

Bleno, much like many other JavaScript packages, works asynchronously. That means we need to wait for events to happen rather than calling specific functions, and this is accomplished through several bleno.on() definitions.

We wait for bleno to initialize the Bluetooth driver with bleno.on('stateChange', function() {...}), which calls the callback parameter once its done. In our code, we tell bleno to start advertising our service and characteristic.

We define our own characteristic (bleno.Characteristic) near the beginning of the code, which we call displayCharacteristic. The characteristic contains a number of properties and callbacks. In displayCharactersitic, we only allow for writes to that characteristic, as given by properties in the displayCharacteristic definition. onWriteRequest is called whenever that characteristic is written to (from the phone in this example).

We don’t broadcast the name “displayCharacteristic.” Instead, we broadcast a universally unique identifier (UUID) for our service and characteristic (as given by the properties edison.service and edison.characteristic). Our phone also has those numbers (12ab and 34cd) hardcoded into its app, so it knows which service and characteristic to write to.

cordova-plugin-ble-central

cordova-plugin-ble-central is similar to bleno, but it is meant to be used as a Cordova plugin for phones (instead of bleno, which was created as a module for Node.js).

In our phone app, we wait for the device (our phone) to tell us that it has finished initializing with the "deviceReady" event. With that, we can start the Bluetooth driver and the plugin. To make the app easier to use, we don’t wait for the user to input anything; we try to connect immediately to the Edison using the hardcoded MAC address.

This connection process is accomplished by first scanning for available devices (ble.scan). When we find a device that matches our hardcoded MAC address (if (device.id === window.edison.deviceId)), we attempt to connect to it (ble.connect()).

Once a connection has been made, we immediately begin sampling the accelerometer once every 100 ms using the accelerometer.watchAccerlation() function built into device-motion Cordova plugin.

Scaling

Trying to disassemble and reassemble the bytes in a floating point number can prove troublesome. In order to make life easier, we round the X, Y, and Z acceleration data (measured in meters per second) to 2 decimal places and multiply each one by 100. This turns each one into an integer, which we then store in a 16-bit value before sending over the BLE link.

Once the Edison has received the 3 numbers, it divides each one by 100 to get the correct acceleration. This trick is known as “scaling,” and is often used to save space or reduce the required throughput on a communication channel.

Debugging

Many cell phones do not have a built-in consoles for debugging apps, like we did when simulating the web apps. We can, however, create a very simple debugging console in the app itself by using the same principles from the chatroom example in the last experiment.

In JavaScript, we create a function debug(msg) that we can call with a string. This function simply appends that string as a list element to a division (named “debug_box”), which we defined in index.html.

In the rest of the JavaScript portion of our program, we can call debug("Some message"); to have a message appear in our makeshift debugging console. This can be very useful to see if Bluetooth messages are being received or not!

CSS

We have been sneaking in yet another language in our HTML that you may or may not have noticed for the past few experiments.

We would like to introduce Cascading Style Sheets (CSS). Almost all modern websites use CSS to format text and media. Most of them keep CSS in a separate file along with the likes of index.html and app.js. For brevity, we are going to use CSS inline with the rest of our HTML.

CSS can be used to format pieces of HTML by using the HTML property style within a tag. For example:

language:html<div style="margin:auto; width:280px; padding:10px; font-size:14pt">
    ...</div>

The properties set by style are used to:

  • Center the division within the page
  • Set the width of the division box to 280 pixels
  • Create a buffer of 10 pixels between the border of the division box and the text within
  • Set the default font size of text in the division to 14-point

To learn more about CSS, see this guide.

Troubleshooting

  • Bluetooth doesn’t work– On the Edison, make sure you typed in the commands into an SSH or serial console to unblock the Bluetooth radio and kill bluetoothd. On your phone, make sure that Bluetooth is enabled (through the OS’s settings) and that the MAC address in the code matches the MAC address of the Edison.
  • Nothing happens when I tilt the phone– Make sure you are tilting along the long edge of the phone. Add a debug() statement in the phone code to make sure your phone is successfully reading the accelerometer. Finally, put a console.log() statement in the Edison code to make sure the Edison is correctly receiving the accelerometer data over BLE.
  • Bluetooth is showing up as “Dual Mode”– This happens sometimes on Android, even though the Edison does not support Dual Mode Bluetooth (at this time). Try powering down your Android phone and turning it on again to reset the Bluetooth driver.

Going Further

Challenges

  1. Have the character move whenever you tilt the phone along its short axis (instead of its long axis).
  2. Create a phone app that grabs GPS data (hint) and sends it over BLE to the Edison. Have the Edison animate a character that moves whenever you walk along a line (say, longitudinally).

Digging Deeper

Experiment 12: Bluetooth Game Controller

We will continue with the concept of BLE. This time, we will keep the phone as the central (master) device, but we will use the Edison as a controller to send data as notifications to the phone.

In this experiment, we are going to construct a type of very powerful (probably overkill) Bluetooth game controller out of the Edison with 4 buttons. The Edison will periodically poll the state of these buttons and notify the smartphone over BLE of any button pushes.

On the phone, we will create a very simple “game” that consists of a red ball in the middle of a box. Pushing one of the four buttons on the Edison will cause the ball to move in a cardinal direction (up, down, left, or right). While the game itself does not have a real purpose, it could easily be the starting point for a real video game that requires some kind of Bluetooth controller.

IMPORTANT: Cordova needs to run native code on your smartphone in order to operate. As a result, you will need to be able to install native apps.
  • If you have an iPhone, you will need to enroll in the Apple Developer Program (there is a yearly membership fee) and create Ad Hoc Provisioning Profiles (discussed later)
  • If you have an Android, you can allow the installation of apps from "Unknown Sources" and install the app from a downloaded .apk file

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 4x Push Buttons
  • 4x 1kΩ Resistors
  • 10x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

COM-10969
$7.95
65
SparkFun Block for Intel® Edison - Base

DEV-13045
32.9500$24.95
9
Breadboard - Self-Adhesive (White)

PRT-12002
$4.95
17
Break Away Headers - Straight

PRT-00116
$1.5
18
Jumper Wires Standard 7" M/M Pack of 30

PRT-11026
$4.95
18
Female Headers

PRT-00115
$1.5
5
SparkFun Block for Intel® Edison - GPIO

DEV-13038
14.9500$11.95
3
Intel® Edison

DEV-13024
$49.95
15
Tactile Button Assortment

COM-10302
$4.95

Suggested Reading

Concepts

The Class

In previous experiments, we have either used existing objects or created a one-off object in JavaScript with something like:

language:javascript
var oneOff = {
    prop1: "red",
    prop2: 42
};

In this experiment, we finally get to create our own object. If you are familiar with other object-oriented programming language, you might be familiar with the concept of a class. JavaScript is considered classless, since you can create objects without a blueprint (class). However, there are times when we want to create several instances of an object and don’t want to rewrite code. As a result, JavaScript still offers us a way to create classes.

The class is like a blueprint or a recipe. We create properties and functions that all objects of that type must have (it saves us rewriting lots of code when we want many ojects of the same type). To define this blueprint in JavaScript, we first create a constructor and assign any members (variables unique to that object).

language:javascript
function MyBlueprint() {
    this._member = 0;
}

Wait, this is a function! Correct. In order to create an instance of the class MyBlueprint, we need to use the special new keyword. The following creates one instance (named myInstance) from the class MyBlueprint (notice that we capitalize the first character in the class but not for instances):

language:java
var myInstance = new MyBlueprint();

We’ve just created an object from our class! It is very similar to following a blueprint, schematic, or recipe to make a bridge, circuit, or meal. myInstance, thanks to the constructor, contains a member variable called _member. The value of _member is unique to that one instance. We can access that value with myInstance._member in order to get or set its value.

In addition to members, we can create functions that are shared among all instances of our class. We need to use the special keyword prototype:

language:javascript
MyBlueprint.prototype.updateMember = function(num) {
    this._member = num;
};

This function (called a method), when called from an instance, allows you to set the value of that instance’s member variable (_member in this case). We use the this keyword to refer to the instance. For example, if we named our instance myInstance, this would refer to the myInstance object. By specifying this._member, we refer to the member variable within that particular instance.

Some jargon you should be aware of:

  • Object– A piece of code that contains properties (variables and/or functions)
  • Class– A blueprint to create several objects of the same type
  • Instance– An object created using a class (as a blueprint)
  • Member– A variable unique to an instance as defined within a class
  • Method– A function defined by a class

Here is a basic example of a class and some instances created from that class. Feel free to run the code on your Edison. What do you expect to see in the console when you run it? Can you identify the class, the instances, the member, and the methods?

language:javascript
// This is the constructor. Calling this with "new" creates a new object
// (instance) of type "MyBlueprint"
function MyBlueprint() {
    this._member = 0;
}

// Objects of type "MyBlueprint" will all have this function, which allows you
// to update the member variable within that instance.
MyBlueprint.prototype.updateMember = function(num) {
    this._member = num;
};

// Again, all instances of "MyBlueprint" will have this function. Calling this
// will print the member variable's value to the screen.
MyBlueprint.prototype.printMember = function() {
    console.log(this._member);
};

// Let's test this by creating 2 instances of our MyBlueprint class.
var instance_1 = new MyBlueprint();
var instance_2 = new MyBlueprint();

// To test the methods, we can update the member variable for one instance
instance_1.updateMember(42);

// Print the member's value to the console. What do you expect to see?
instance_1.printMember();
instance_2.printMember();

The Game Loop

Almost all video games rely on the Game Loop. This loop is a simple programming construct with 4 parts and executes endlessly (at least until the game ends).

The Game Loop

The Game Loop consists of the 4 main parts:

  1. Process Input– Look for input from the controller or input device. For example, the player is pushing a button.
  2. Update Game– Take input from the controller and update the game variables as a result. For example, the button input told the character to move up. Update the character’s Y position by -1 (toward the top of the screen).
  3. Render– Render is another fancy name for “draw.” Most simple games will clear the screen and re-draw the whole scene. In our example, this includes having the character appear 1 pixel above where they used to be.
  4. Wait– Do not do anything so that we can reach our target framerate (measured in frames per second or FPS). This is often variable. For example, if the first three steps took 32 ms, we need to wait 18 ms in order to meet our framerate goal of 20 FPS (1 frame every 50 ms).

In our experiment, our game loop is only going to consist of steps 3 and 4. Thanks to JavaScript’s asynchronous nature, we will update the game variables (the position of a ball) whenever a button push event arrives over BLE from the Edison. This means that the Edison is handling step 1 (polling for button pushes), and the phone is handling step 2 asynchronously (whenever a button push event arrives).

However, steps 3 and 4 will still execute in an endless loop. Every 50 ms, the game’s canvas (play area on the phone) is cleared and a new ball is drawn in the position determined by the ball’s x and y properties. We then wait for the rest of the 50 ms until the draw function is called again.

Hardware Hookup

Edison and buttons Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

The Code

Edison Code

Before we run any code on the Edison, we need to enable Bluetooth. Connect via SSH or Serial, and enter the following commands:

rfkill unblock bluetooth
killall bluetoothd
hciconfig hci0 up

In the XDK, create a new Blank IoT Application. In package.json, copy in the following:

language:javascript
{"name": "blankapp","description": "","version": "0.0.0","main": "main.js","engines": {"node": ">=0.10.0"
  },"dependencies": {"async": "1.5.0","bleno": "0.3.3"
  }
}

In main.js, copy in the following:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 12: Edison BLE Controller
 * This sketch was written by SparkFun Electronics
 * November 24, 2015
 * https://github.com/sparkfun
 *
 * Broadcasts as a BLE device. When a central device (e.g. smarthphone)
 * connects, it sends out button pushes as a notification on a characteristic.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// As per usual, we need MRAA. Also, bleno.
var mraa = require('mraa');
bleno = require('bleno');

// Define our global variables first
var bleno;
var controllerCharacteristic;

// BLE service and characteristic information
var edison = {
    name: "Edison",
    deviceId: null,
    service: "12ab",
    characteristic: "34cd"
};

// Create buttons on pins 44, 45, 46, and 47
var upPin = new mraa.Gpio(44, true, true);
var downPin = new mraa.Gpio(45, true, true);
var leftPin = new mraa.Gpio(46, true, true);
var rightPin = new mraa.Gpio(47, true, true);

// Set that pin as a digital input (read)
upPin.dir(mraa.DIR_IN);
downPin.dir(mraa.DIR_IN);
leftPin.dir(mraa.DIR_IN);
rightPin.dir(mraa.DIR_IN);

// Define our controller characteristic, which can be subscribed to
controllerCharacteristic = new bleno.Characteristic({
    value: null,
    uuid: edison.characteristic,
    properties: ['notify'],
    onSubscribe: function(maxValueSize, updateValueCallback) {
        console.log("Device subscribed");
        this._updateValueCallback = updateValueCallback;
    },
    onUnsubscribe: function() {
        console.log("Device unsubscribed");
        this._updateValueCallback = null;
    },
});

// This field holds the value that is sent out via notification
controllerCharacteristic._updateValueCallback = null;

// We define a special function that should be called whenever a value
// needs to be sent out as a notification over BLE.
controllerCharacteristic.sendNotification = function(buf) {
    if (this._updateValueCallback !== null) {
        this._updateValueCallback(buf);
    }
};

// Once bleno starts, begin advertising our BLE address
bleno.on('stateChange', function(state) {
    console.log('State change: ' + state);
    if (state === 'poweredOn') {
        bleno.startAdvertising(edison.name,[edison.service]);
    } else {
        bleno.stopAdvertising();
    }
});

// Notify the console that we've accepted a connection
bleno.on('accept', function(clientAddress) {
    console.log("Accepted connection from address: " + clientAddress);
});

// Notify the console that we have disconnected from a client
bleno.on('disconnect', function(clientAddress) {
    console.log("Disconnected from address: " + clientAddress);
});

// When we begin advertising, create a new service and characteristic
bleno.on('advertisingStart', function(error) {
    if (error) {
        console.log("Advertising start error:" + error);
    } else {
        console.log("Advertising start success");
        bleno.setServices([

            // Define a new service
            new bleno.PrimaryService({
                uuid: edison.service,
                characteristics: [
                    controllerCharacteristic
                ]
            })
        ]);
    }
});

// Call the periodicActivity function
periodicActivity();

// This function is called forever (due to the setTimeout() function)
function periodicActivity() {

    // If a button is pushed, notify over BLE
    if (upPin.read() == 0) {
        controllerCharacteristic.sendNotification(new Buffer([0]));
    }
    if (downPin.read() == 0) {
        controllerCharacteristic.sendNotification(new Buffer([1]));
    }
    if (leftPin.read() == 0) {
        controllerCharacteristic.sendNotification(new Buffer([2]));
    }
    if (rightPin.read() == 0) {
        controllerCharacteristic.sendNotification(new Buffer([3]));
    }

    // Wait for 20 ms and call this function again
    setTimeout(periodicActivity, 20);
}

Phone App

As in the previous experiment, create a blank HTML5 + Cordova app under HTML5 Companion Hybrid Mobile or Web App.

In the project settings, add the plugin cordova-plugin-ble-central.

Adding BLE Cordova plugin to the XDK

Once again, we need to include jQuery. Download the latest, uncompressed version of jQuery from http://jquery.com/download/. Create two new directories in your project so that you have /www/lib/jquery. Copy the .js file into the jquery directory.

Go back to the Develop tab. In www/index.html, copy in the following:

language:html<!DOCTYPE html><!--
SparkFun Inventor's Kit for Edison
Experiment 12: Phone BLE Ball
This sketch was written by SparkFun Electronics
November 23, 2015
https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments

Runs as BLE central on smartphone. Accepts BLE connection from Edison and
moves ball around screen based on BLE notifications from the Edison.

Released under the MIT License(http://opensource.org/licenses/MIT)
--><html><head><title>BLE Ball</title><meta http-equiv="Content-type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=no"><style>
        @-ms-viewport { width: 100vw ; min-zoom: 100% ; zoom: 100% ; }  @viewport { width: 100vw ; min-zoom: 100% zoom: 100% ; }
        @-ms-viewport { user-zoom: fixed ; min-zoom: 100% ; }           @viewport { user-zoom: fixed ; min-zoom: 100% ; }</style></head><body><!-- IP address and port inputs --><h3 style="text-align:center;">BLE Controller Demo</h3><div id="connection" style="margin:auto; width:240px; padding:5px;"><input id="ble_name" type="text" placeholder="Name of device"
               style="width:60%;"><button id="connect_ble" style="width:35%;">Connect</button></div><!-- Canvas for drawing our game --><div style="margin:auto; width:260px; height:260px;"><canvas id="ball_canvas" width="240" height="240"
                style="background:#E5E5E5;
                       margin-left:auto;
                       margin-right:auto;
                       display:block;"></canvas></div><!-- Debugging --><div id="debug_box" style="margin:auto;
                               width:280px;
                               height:140px;
                               padding:1px;
                               overflow:auto;
                               background:#0d0d0d;"><ul id="debug" style="color:#00BB00;"></ul></div><!-- Load the various JavaScript files --><script type="text/javascript" src="cordova.js"></script><script type="text/javascript" src="lib/jquery/jquery-2.1.4.js"></script><script type="text/javascript" src="js/app.js"></script></body></html>

In www/js/app.js, copy in the following:

language:javascript
/*jslint unparam: true */
/*jshint strict: true, -W097, unused:false,  undef:true, devel:true */
/*global window, document, d3, $, io, navigator, setTimeout */
/*global ble*/

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 12: Phone BLE Ball
 * This sketch was written by SparkFun Electronics
 * November 23, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Runs as BLE central on smartphone. Accepts BLE connection from Edison and
 * moves ball around screen based on BLE notifications from the Edison.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Put in strict mode to restrict some JavaScript "features""use strict" ;

// BLE service and characteristic information
window.edison = {
    name: null,
    deviceId: null,
    service: "12ab",
    characteristic: "34cd"
};

/******************************************************************************
 * Game Class
 *****************************************************************************/

// Game constructor
function Game(canvas) {

    // Assign the canvas to our properties
    this._canvas = canvas;
    this._ctx = this._canvas.getContext("2d");

    // Initialize the rest of the properties
    this._gameThread = null;
    this._ball = {
        x: this._canvas.width / 2,
        y: this._canvas.height / 2,
        radius: 10,
        visible: false
    };
}

// Call this to update the ball's position
Game.prototype.updateBallPos = function(dx, dy) {

    // Increment the ball's position
    this._ball.x += dx;
    this._ball.y += dy;

    // Make the ball stick to the edges
    if (this._ball.x > this._canvas.width - this._ball.radius) {
        this._ball.x = this._canvas.width - this._ball.radius;
    }
    if (this._ball.x < this._ball.radius) {
        this._ball.x = this._ball.radius;
    }
    if (this._ball.y > this._canvas.height - this._ball.radius) {
        this._ball.y = this._canvas.height - this._ball.radius;
    }
    if (this._ball.y < this._ball.radius) {
        this._ball.y = this._ball.radius;
    }
};

// Draws the ball on the canvas
Game.prototype.drawBall = function() {
    this._ctx.beginPath();
    this._ctx.arc(this._ball.x,
                  this._ball.y,
                  this._ball.radius,
                  0,
                  Math.PI * 2);
    this._ctx.fillStyle = "#BB0000";
    this._ctx.fill();
    this._ctx.closePath();
};

// This gets called by the main thread to repeatedly clear and draw the canvas
Game.prototype.draw = function() {
    if (typeof this._ctx != 'undefined') {
        this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
        if (this._ball.visible) {
            this.drawBall();
        }
    }
};

// Call this to start the main game thread
Game.prototype.start = function() {
    var that = this;
    this._ball.visible = true;
    this._gameThread = window.setInterval(function() {
        that.draw();
    }, 50);
};

// Call this to stop the main game thread
Game.prototype.stop = function() {
    this.ball.visible = false;
    this.draw();
    window.clearInterval(this.gameThread);
};

/******************************************************************************
 * Main App
 *****************************************************************************/

// Global app object we can use to create BLE callbacks
window.app = {

    // Game object
    game: null,

    // Call this first!
    initialize: function() {

        // Create a new instance of the game and assign it to the app
        this.game = new Game($('#ball_canvas')[0]);

        // Connect events to page elements
        this.bindEvents();
    },

    // Connect events to elements on the page
    bindEvents: function() {
        var that = this;
        $('#connect_ble').on('click', this.connect);
    },

    // Scan for a BLE device with the name provided and connect to it
    connect: function() {
        var that = this;
        window.edison.name = $('#ble_name').val();
        debug("Looking for " + window.edison.name);
        ble.scan([],
                 5,
                 window.app.onDiscoverDevice,
                 window.app.onError);
    },

    // When we find a BLE device, if it has the name we want, connect to it
    onDiscoverDevice: function(device) {
        var that;
        debug("Found " + device.name + " at " + device.id);
        if (device.name == window.edison.name) {
            window.edison.deviceId = device.id;
            debug("Attempting to connect to " + device.id);
            ble.connect(window.edison.deviceId,
                        window.app.onConnect,
                        window.app.onError);
        }
    },

    //  On BLE connection, subscribe to the characteristic, and start the game
    onConnect: function() {
        window.app.game.start();
        debug("Connected to " + window.edison.name + " at " +
              window.edison.deviceId);
        ble.startNotification(window.edison.deviceId,
                              window.edison.service,
                              window.edison.characteristic,
                              window.app.onNotify,
                              window.app.onError);
    },

    // Move the ball based on the direction of the notification
    onNotify: function(data) {
        var dir = new Uint8Array(data);
        debug("Dir: " + dir[0]);
        switch(dir[0]) {
            case 0:
                window.app.game.updateBallPos(0, -1);
                break;
            case 1:
                window.app.game.updateBallPos(0, 1);
                break;
            case 2:
                window.app.game.updateBallPos(-1, 0);
                break;
            case 3:
                window.app.game.updateBallPos(1, 0);
                break;
            default:
                debug("Message error");
        }
    },

    // Alert the user if there is an error and stop the game
    onError: function(err) {
        window.app.game.stop();
        debug("Error: " + err);
        alert("Error: " + err);
    }
};

/******************************************************************************
 * Execution starts here after page has loaded
 *****************************************************************************/

// Short for jQuery(document).ready() method, which is called after the page
// has loaded. We can use this to assign callbacks to elements on the page.
$(function() {

    // Initialize the app and assign callbacks
    window.app.initialize();
});

// Create a pseudo-debugging console
// NOTE: Real apps can also use alert(), but list messages can be useful when
// you are debugging the program
function debug(msg) {
    $('#debug').append($('<li>').text(msg));
}

Refer to the previous example on how to build the phone app for your smartphone.

What You Should See

Make sure that you have enabled Bluetooth on the Edison and that it is running the controller program. Run the phone app, and you should be presented with an input, a blank game canvas, and a debugging console (much like in the last experiment). Enter Edison into the input field and tap Connect.

Enter Edison into the field to connect to it over BLE

Once your phone connects to the Edison, a small, red ball should appear in the middle of the canvas (you should also see a “Connected to” message in the debugging console). Push the buttons connected to the Edison to move the ball around!

Our Edison Bluetooth controller in action

Code to Note

The Game Object

As introduced in the Concepts section, we create a class named Game along with some members and methods. The window.app.game object (an instance of the Game class) is responsible for remembering the ball’s X and Y coordinates (stored as variables within the this._ball member) as well as drawing the ball on the canvas, which is accomplished using an HTML Canvas element.

Once a BLE connection has been made, the program starts the game loop by calling window.app.game.start(). This function sets up an interval timer that calls the .draw() function every 50 ms. In .draw(), the canvas is cleared, and the ball is drawn every interval.

In window.app.onNotify, which is called on a received BLE notification, the BLE’s data (the first and only byte) is parsed to determine which way the ball should move. A received ‘0’ means “move the ball up”, ‘1’ means “down”, ‘2’ means “left”, and ‘3’ means “right”. Updating the ball’s position is accomplished by calling window.app.game.updateBallPos(dx, dy).

BLE by Name

In the previous experiment, we needed to hardcode the Edison’s Bluetooth MAC address into the program. This time, we take a different approach. When the user presses the Connect button, the program retrieves the value of the input (ideally, “Edison”) and stores it in the global window.edison object (as window.edison.name).

The program then scans for all available BLE peripherals, noting their names (device.name in the onDiscoverDevice callback). If one is found to be equal to window.edison.name (ideally, “Edison” once again), the program attempts to connect to that device. No need to set the MAC address anywhere!

In the Edison code, we assign the BLE name “Edison” in the global edison object. If we change that name, we will need to enter the same name into the input field of the phone app.

BLE Notifications

In the Edison code, we define a BLE characteristic called controllerCharacteristic. Unlike the previous example where we only allowed writing to the characteristic, we allow notifications to this characteristic.

A BLE notification sends out an update to all devices that have subscribed whenever that characteristic has changed. To accomplish this in the Edison, we create a member variable of the controllerCharacteristic named _updateValueCallback. This variable is assigned the function updateValueCallback whenever a device subscribes to the characteristic. We create the external function controllerCharacteristic.sendNotification(buf) so that other parts of the code may send data as a notification over BLE.

‘sendNotification(buf)calls the functionupdateValueCallback()with the data it received from the caller (buf`). The causes the bleno module to send a notification for that particular characteristic over BLE.

On the phone side, cordova-plugin-ble-central is configured to subscribe to the characteristic with ble.startNotification(...). Notifications to that characteristic call the function onNotify(), which then parses the received data to determine how to move the ball.

This and That (Dummy Functions)

As mentioned previously, the keyword this refers to the calling object. Sometimes, we have to create a wrapper around a callback function so that we can pass the object to the function.

For example, in the phone code app.js, the method Game.prototype.start uses the built-in function setInterval() to call the draw method repeatedly. As it is, setInterval() is a method of the global window object. If we were to write

language:javascript
Game.prototype.start = function() {
    this._ball.visible = true;
    this._gameThread = window.setInterval(this.draw, 50);
};

the keyword this (only within setInterval) would refer to window, not the Game object! And, as you might guess, window has no draw() function. This piece of code would throw an error (unless you made a window.draw() function).

To get around this, we first assign this to a placeholder variable, which we will (humorously) call that. Then, we can create a dummy function as the callback for setInterval, which calls that.draw(), referring to the draw() method in the Game object.

language:javascript
Game.prototype.start = function() {
    var that = this;
    this._ball.visible = true;
    this._gameThread = window.setInterval(function() {
        that.draw();
    }, 50);
};

Troubleshooting

  • Bluetooth is not connecting– If you restarted the Edison since the last experiment, make sure you enter the three commands rfkill unblock bluetooth, killall bluetoothd, and hciconfig hci0 up into an Edison terminal (SSH or serial) before running the Edison code.
  • The ball does not move– If you see the ball on the screen, then Bluetooth is connected. A visible ball that does not move could be caused by several issues:
    • The Edison might not be detecting button pushes. Insert console.log() statements into the Edison code to determine the state of each of the buttons.
    • The Edison might not be sending notifications over BLE. Use another BLE phone app (e.g. BLE Scanner) to see if the characteristic is being updated.
    • The phone app might not be receiving notifications. Place debug() statements in onNotify to see if it is being called.
    • The phone app might not be updating the ball postion. Place debug() statements in Game.prototype.updateBallPos to see if it is being called.

Going Further

Challenges

  1. Make the ball’s radius grow by 1 every time it touches a wall.
  2. Make the ball move faster (this can be accomplished in several ways).
  3. Make a real game! For example, you could make a Breakout clone that uses the Edison controller to move the paddle. See this tutorial to help you get started.

Digging Deeper

Finale: Next Steps

Where do you go from here? The purpose of the kit was to provide an overview of the many different things you can do with the Edison (and all this with only JavaScript!). By this point, you’ve hopefully gained some confidence in programming the Edison with the XDK, creating simple web pages, and making wireless connections over WiFi and Bluetooth Low Energy. Along the way, perhaps you were inspired to create a project of your own imagination.

Beyond JavaScript

As you probably noticed, the experiments in this guide focused primarily on JavaScript and the so-called “web languages” (at least some of the popular ones). If you followed along with the experiments to create web pages and web apps, you can apply the knowledge to create your own web pages or simple smartphone apps.

There is nothing wrong, of course, with using strictly JavaScript. Some people might want to try different languages. Because the Edison is a full computer, it is capable of compiling and running many more languages. Out of the box, the Edison has Node (for running JavaScript), Python, and a C/C++ compiler (gcc).

  • See here for getting started with Python on the command line
  • Check out this tutorial for using Eclipse to program C/C++ for the Edison

In reality, you can likely compile or run almost any programming language on the Edison. For those of you who enjoy esoteric interests, you can even find a Malbolge interpreter.

Online Resources

Books

Discussion

Have ideas, comments, or suggestions? Feel free to post them and ask questions about the Edison SIK in the Comments section.

Project Ideas

If you are still looking for inspiration for projects, perhaps some of these can help:

Appendix A: Troubleshooting

Help! I bricked my Edison!

This is very much a possibility when loading new firmware. If you find that you have put the Edison in an unrecoverable state, it should be possible to recover (unbrick) it.

Connect a USB cable from your computer to Console port on the Base Block. Open a serial terminal to the Edison. If you see the Edison begin to POST to your serial terminal, look for the line (it will count down to 0):

Hit any key to stop autoboot: 0

Press ‘enter’ and enter the command:

run do_flash

This will put the Edison into DFU mode. You can now run the flashall.bat or flashall.sh script from your host computer to re-image the Edison.

Many thanks to user ddewaele for finding this solution. You can see an example of his error (bricked Edison) and his solution as a gist on GitHub.

The Phone Flash Tool Lite Shows the Edison as “Disconnected”

If the Phone Flash Tool refuses to show the Edison as Connected, make sure that you have enabled USB networking (Appendix C). Flashing the Edison also requires a very specific order with the Phone Flash Tool:

  1. Ensure the Edison is disconnected from the computer
  2. Start the Phone Flash Tool Lite
  3. Browse to the FlashEdison.json file (in the unzipped Yocto firmare image directory)
  4. Click Start to flash
  5. Connect a USB cable from the computer to the OTG port on the Base Block

dfu-util or libusb not found (Windows)

If you see an error message such as “The program can’t start because libusb-1.0.dll is missing from your computer” or a message about dfu-util not being found, you will need to add a .dll library and .exe program to the Yocto image directory.

Download and install 7-zip from the 7-zip.org page. You will probably want the .msi version.

Download dfu-util for Windows (this executable came from the particle.io community).

Go to Start → All Programs → 7-Zip → 7-Zip File Manager. Within the file manager, navigate to your downloads folder. Select “dfu-util-0.8-binaries.tar.zx” and select “Extract.”

Unzipping dfu-util in Windows

Click “OK” when prompted on where to extract the files to accept the defaults. “dfu-util-0.8.binaries.tar” will appear in the 7-Zip File Manager. Double-click on it to enter the folder. Select “dfu-util-0.8-binaries.tar” and click “Extract” to extract dfu-util one more time.

Untarring dfu-util in Windows

Open up a File Explorer window and navigate to <YOUR DOWNLOADS FOLDER>\dfu-util-0.8-binaries.tar\dfu-util-0.8-binaries\dfu-util-0.8-binaries\win32-mingw32. Copy both dfu-util.exe and libusb-1.0.dll.

Copy dfu-util and libusb

Paste them into <YOUR DOWNLOADS FOLDER>\edison-iotdk-image-… (the place where you unzipped the Yocto image).

Paste dfu-util and libusb

dfu-util not found (Linux)

If you get an error like “dfu-util: command not found” when trying to update to the latest Yocto image then you need to install dfu-util. Run the command:

sudo apt-get install dfu-util

The Edison won’t connect

If you are trying to connect to the Edison and you don’t see it listed as an IoT Device in the XDK, then a few things might be wrong.

No Edison in the XDK

  • The Edison is not powered. Make sure you the blue LED on the Base Block is lit up.
  • The Bonjour service is not installed or not working. You can still connect manually if you do not want to use Bonjour. You will need the IP address of the Edison (see Connecting to WiFi).
  • Make sure your computer is on the same WiFi network as the Edison. Alternatively, you could use a USB network instead.

If you get an error when trying to connect, such as “Error on ssh connection: Error: All configuration authentication methods failed,” then you need to try reconnecting and entering the root password you set during the Connecting to WiFi step.

Wrong password

Bluetooth Low Energy

BLE is not on by default in the Edison. Additionally, you must unblock the bluetooth radio and stop the bluetoothd daemon before running any JavaScript that relies on the bleno module. To do that, every time you boot the edison, you must log in (SSH or serial) and enter the following commands:

rfkill unblock bluetooth
killall bluetoothd
hciconfig hci0 up

Android is also known to have some issues with BLE, especially bleno. If your phone does not connect to the Edison, and the Edison shows up as “Dual Mode” in 3rd party applications (e.g. BLE Scanner), then try turning Bluetooth off and on again in Android. Additionally, resetting the phone (turn power off and on again) also seems to help.

It’s Still Not Working!

If it is a problem with the hardware (things are not getting power, the temperature sensor doesn’t work, etc.), we have an awesome tech support staff to help you out. Please see our tech support page to find out how to contact them.

If you have a question, concern, or suggestion for the documentation, feel free to post that in the Comments section of this guide.

Appendix B: Programming Without the XDK

The Intel® XDK offers some really useful features when programming, such code completion, automatic installation of libraries, and formatting new projects (e.g. templates). However, we totally understand if you don’t want to use the XDK. The good news is that the Edison is a full computer, which means it is more than capable of installing libraries and running code on its own!

Writing Code

There are several ways to write code. Finding a good editor can be a challenge. If you fancy yourself an old-school Unix guru, you might be comfortable with vi. All you need to do is log in to the Edison through SSH or serial and enter the command

vi

You will be greeted with the perhaps familiar vi interface.

vi on the Edison

If you dislike vi but still want to edit code on the Edison directly, you could install another editor. For example, nano has been added to the Edison’s package repositories. See here to install nano.

XDK offers the benefit of editing code on your computer (desktop or laptop) and the ability to send that code directly to the Edison. You can use any number of editors on your personal computer for editing code. For example, Notepad++ for Windows, TextWrangler for Mac, or Emacs for Linux.

Once you are done writing the code, you can send it to the Edison through a number of ways:

  • Copy and paste the code into vi on the Edison and save it
  • Use scp (Linux/Mac) or WinSCP (Windows) to transfer the file(s) from your computer to the Edison
  • Upload the code as part of a GitHub repository and download it on the Edison

Running Node.js

By default, the Edison comes pre-loaded with Node.js, which is the runtime environment used to run JavaScript. To run a Node program written in JavaScript, we just need to enter the command

node <name_of_program>.js

into the SSH or serial terminal of the Edison.

For example, let’s make a simple JavaScript program:

langauge:javascript
for (var i = 0; i < 3; i++) {
  console.log("Hi " + i);
}

Save it as test.js in the home directory on the Edison (/home/root). Log into the Edison and make sure we are in the home directory.

cd /home/root

Then, run the program.

node test.js

You should see a few messages printed to the console.

Testing Node.js in the Edison

Installing Node Modules

You can include JavaScript libraries (Node.js modules) in your program by installing them directly on the Edison. From the console, you just need to call

npm install <module name>@<version number>

For example, to install the version of Socket.IO as required by Experiment 5, Part 2, enter the following command into the Edison console:

npm install socket.io@1.3.7

Note that this requires the Edison to be connected to the Internet, as it will attempt to find and install Socket.IO v1.3.7 from the npm package repository.

You do not need to create a package.json file (like we did with the XDK) to accompany your code. The npm install command installs the package directly on the Edison. As long as your code as the necessary require('socket.io') line, you will be able to use Socket.IO.

A list of available modules can be found on npmjs.com.

Appendix C: Using a USB Network

If you are trying to update the Edison’s firmware via the Phone Flash Tool Lite program or want to upload code from the XDK without using WiFi, you can enable USB Ethernet networking. For Windows, this relies on the RNDIS driver. OS X needs to use HoRNDIS, and Linux users will need to use USB CDC.

For all operating systems, start by connecting a USB cable from the OTG port of the Edison Base Block to an available USB port on your computer.

Edison Base Block USB OTG port

NOTE: By default, the IP address of the Edison on the USB network is 192.168.2.15. Additionally, you can program the Edison from the XDK by connecting over the USB network!

Windows

Go to Start → Control Panel → Network and Internet → Network and Sharing Center → Change Adapter Settings

Adapter Settings in Windows

Right-click on the Local Area Connection that says Intel Edison USB RNDIS Device and select Properties. This will bring up a new window.

Local Area Connection Properties

Select Internet Protocol Version 4 (TCP/IPv4) and click Properties. This will, once again, bring up a new window.

Entering static IPv4 address

Select Use the following IP address: and enter 192.168.2.2 for the IP Address. Click anywhere in the Subnet mask fields and it should auto-populate. Click OK on this window and OK on the Local Area Connection window.

Your computer and Edison should now be networked together over USB. To check this, go to Start → Accessories → Command Prompt. Enter ping 192.168.2.15 and you should see several replies from the Edison (192.168.2.15).

Pinging the Edison from Windows

OS X

WARNING: At this time, the HoRNDIS driver does not work on OS X 10.11 (El Capitan). If you are using 10.11, keep watching the HoRNDIS site for updates.

Modern versions of OS X do not come with USB networking drivers. As a result, we will need to install a custom driver. Download the latest release (in .pkg form) for HoRNDIS:

Download HoRNDIS Driver

Open the .pkg file and follow the instructions to install the driver. Restart your Mac just to be sure. Once it has booted back up, open up System Preferences and go to Network, and you should see the Edison listed. Change Configure IPv4 to Manually, set IP Address to 192.168.2.2, and Subnet Mask to 255.255.255.0.

Configure networking for the USB network on OS X

Click Apply and you should be able to connect to the Edison over the USB network. Open a console and enter the command ping 192.168.2.15. You should see some ping replies. Press ‘Ctrl+C’ to stop pinging.

Ping the Edison from OS X

OS X also come packaged with an SSH client. In a console, enter:

ssh root@192.168.2.15

Type yes if prompted to accept the RSA key, and enter your Edison’s root password.

Linux

Many modern distributions contain USB network drivers by default. With a USB cable connected between your computer and the OTG port on the Base Block, open up a console and enter the command:

ifconfig

You should see an entry labeled usb0, which refers to a USB network. That should be the Edison, assuming you have no other USB Ethernet devices plugged in.

USB network device plugged in

Enter the commands:

sudo ip address add 192.168.2.15/24 dev usb0
sudo ip link set dev usb0 up

If your system does not support the sudo command, use su to become root before entering the commands (without sudo).

You can check to make sure that the IP address was set with ifconfig. You should see an IP address assigned to usb0.

IP address assigned to usb0 on Linux

To test that you have a connection to the Edison, you can ping it:

ping 192.168.2.15

That should give you a few replies, showing that the Edison is indeed at 192.168.2.15. Press ‘Ctrl+C’ to stop pinging.

Ping the Edison from Linux

Many versions of Linux also come packaged with an SSH client. If so, you won’t need any special programs to connect to the Edison over the USB network. Just enter:

ssh root@192.168.2.15

Type yes if prompted to accept the RSA key, and enter your Edison’s root password.

Appendix D: Manually Updating the Firmware

If the Phone Flash Tool was not working properly or you did not want to use the Phone Flash Tool, you can try to flash the Edison manually.

NOTE: These steps are more involved and requires some familiarity with the command line. If you run into issues, check in Appendix A: Troubleshooting first before posting a question in the Comments section.

Find your operating system below and follow the directions. Note that you will need to use the USB OTG port of the Edison.

Edison Base Block USB OTG port

Windows

Navigate to the unzipped directory of the downloaded Yocto image. Look for the file flashall.bat.

Edison Yocto image flashall scripts

Double-click flashall.bat. That should bring up a window asking you to plug in your Edison.

Flashall asking to plug in the Edison

Plug the USB micro cable into the OTG Port of the Edison, and plug the other end into an open USB port of your computer. Wait a few moments, and the script will begin flashing the Edison.

Wait while the Edison is flashed

You will either get a notice that the flashing process is complete or the window will close. Wait at least 2 more minutes after the update to allow the Edison to finish configuring. Do not unplug the Edison during that time!

OS X

Open a terminal (Finder → Applications → Utilities → Terminal).

OS X Terminal

We need to install a few utilities in order to flash the Edison from OS X.

Install Homebrew:

ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”

Press RETURN and enter your password when asked to continue the installation process.

Homebrew might need to clean or check things before we use it. Run:

brew doctor

Once Homebrew has been installed and cleaned, use it to install a few other utilities:

brew install coreutils gnu-getopt dfu-util

Change to the Edison Yocto image directory in your Downloads. The directory name will be different depending on the version of the image you downloaded earlier.

cd ~/Downloads/edison-iotdk-image-...

Run the install script.

sudo ./flashall.sh

You will see a message like “Now waiting for dfu device.” At that, plug the USB micro cable into the OTG Port of the Edison, and plug the other end into an open USB port of your computer. You should see the script start to flash the Edison in the terminal. Wait while that finishes (it could take a few minutes).

Flashing the Edison from OS X

You will should get a notice that the flashing process is complete. Wait at least 2 more minutes after the update to allow the Edison to finish configuring. Do not unplug the Edison during that time!

Linux

Navigate to the Yocto image that you unzipped. Open a terminal and enter:

cd Downloads/edison-iotdk-image-...

Where the directory is the unzipped Yocto image (e.g. edison-iotdk-image-280915). Run the install script:

sudo ./flashall.sh

You will see a message like “Now waiting for dfu device.” At that, plug the USB micro cable into the OTG Port of the Edison, and plug the other end into an open USB port of your computer. You should see the script start to flash the Edison in the terminal. Wait while that finishes (it could take a few minutes).

Flashing Yocto with Linux

You will should get a notice that the flashing process is complete. Wait at least 2 more minutes after the update to allow the Edison to finish configuring. Do not unplug the Edison during that time!

Appendix E: MRAA Pin Table

MRAA pin map table based on Intel’s IOT Dev Kit Repository

Rows highlighted in yellow are available on the GPIO Block.
Edison Pin (Linux)MRAA NumberArduino BreakoutMini BreakoutPinmode0Pinmode1Pinmode2
GP12203J18-7 GPIO-12PWM0
GP13145J18-1 GPIO-13PWM1
GP1436A4J19-9 GPIO-14
GP1548J20-7 GPIO-15
GP1919J18-6 GPIO-19I2C-1-SCL
GP207J17-8 GPIO-20I2C-1-SDA
GP276J17-7 GPIO-27I2C-6-SCL
GP288J17-9 GPIO-28I2C-6-SDA
GP403713J19-10 GPIO-40SSP2_CLK
GP415110J20-10 GPIO-41SSP2_FS
GP425012J20-9 GPIO-42SSP2_RXD
GP433811J19-11 GPIO-43SSP2_TXD
GP4431A0J19-4 GPIO-44
GP4545A1J20-4 GPIO-45
GP4632A2J19-5 GPIO-46
GP4746A3J20-5 GPIO-47
GP48337J19-6 GPIO-48
GP49478J20-6 GPIO-49
GP7739J19-12 GPIO-77SD
GP7852J20-11 GPIO-78SD
GP7953J20-12 GPIO-79SD
GP8054J20-13 GPIO-80SD
GP8155J20-14 GPIO-81SD
GP8240J19-13 GPIO-82SD
GP8341J19-14 GPIO-83SD
GP8449J20-8 GPIO-84SD
GP10910J17-11 GPIO-109SPI-5-SCK
GP11023J18-10 GPIO-110SPI-5-CS0
GP1119J17-10 GPIO-111SPI-5-CS1
GP11424J18-11 GPIO-114SPI-5-MISO
GP11511J17-12 GPIO-115SPI-5-MOSI
GP128132J17-14 GPIO-128UART-1-CTS
GP129254J18-12 GPIO-129UART-1-RTS
GP130260J18-13 GPIO-130UART-1-RX
GP131351J19-8 GPIO-131UART-1-TX
GP13444J20-3
GP1354J17-5 GPIO-135UART
GP16515A5J18-2 GPIO-165
GP18206J17-1 GPIO-182PWM2
GP183219J18-8 GPIO-183PWM3

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

Sound Reactive EL Wire Costume

$
0
0

Sound Reactive EL Wire Costume a learn.sparkfun.com tutorial

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

Introduction

Bring science fiction to life with a personalized light-up outfit! EL wire is a delightfully futuristic-looking luminescent wire that has the added benefit of staying cool, making it ideal for wearable projects. Combining sensors and a microcontroller with EL wire allow for a wide range of feedback and control options.

This project uses the SparkFun Sound Detector and the EL Sequencer to flash the EL wire to the rhythm of ambient sound, including music, clapping, and talking. You could accomplish the same with the EL Escudo DOS Arduino Shield.

alt text

Materials

Electronics

alt text

Costume

alt text

  • Article(s) of clothing
    • For a Tron-esque look, go for stretchy black material. Yoga pants and other athletic gear works great!
  • Belt
  • Old jacket with large pocket, preferably zippered or otherwise sealable.
    • The pocket will house the electronics. If you intend to wear the costume outdoors in potentially wet weather, choose a pocket that is waterproof (i.e. cut a pocket from a waterproof jacket).
  • Piece of packing foam or styrofoam (to insulate the sound detector)

Tools

alt text

  • Safety goggles
  • Soldering Iron
  • Wire Cutter/Stripper
  • Epoxy (waterproof)
  • Scissors
  • Needle + thread OR fabric adhesive

Recommended Reading

Build It!

CAUTION: Although it is low current, EL wire runs on high voltage AC (100 VAC). There are exposed connections on the EL Sequencer board so BE CAREFUL when handling the board. Always double (and triple) check that the power switch is OFF before touching any part of the board. For final projects, it is recommended to coat all exposed connections in epoxy, hot glue, electrical tape, or other insulating material.

  1. Test EL Sequencer with EL Wire.

    alt text

    Connect the inverter, battery, and at least one strand of EL wire to the EL Sequencer. (Note that the two black wires of the inverter correspond to the AC side.)

    Be sure that the EL Wire lights up and blinks when you power the EL Sequencer on battery mode.

  2. Solder header pins onto 5V FTDI pinholes on the EL Sequencer and onto the VCC, Ground, and A2 input pins.

    alt text
  3. Solder header pins to the sound detector.

    alt text
  4. Connect sound detector to EL Sequencer via female-to-female jumper wires (you can also skip the header installation, and solder wire directly to the header pins).

    alt text

    Connect the sound detector VCC and Ground pins to the VCC and Ground pins on the EL Sequencer. Connect the sound detector Gate output to the A2 input pin on the EL Sequencer. If you are using the envelope and/or audio output signals, connect these to pins A3 and A4 on the EL Sequencer (more on this in the Program It! section below).

  5. Make a protective casing for the sound detector using packing foam or styrofoam to prevent jostling or other physical vibrations (aka collisions) from triggering it.

    alt text

    alt text

    Place sound detector on top of foam, outline the board with a pen, and cut out a hole in the foam for the detector to fit snugly inside. It is also recommended that you epoxy the wires onto the foam (but not the sound detector board).

  6. Cut out a pocket from the jacket, and sew onto the belt.

    alt text

    alt text
  7. Put belt on, connect EL Wire to EL Sequencer, and place EL Sequencer in pocket pouch. Determine approximate placement of each EL wire strand based on location of electronics.

    alt text
  8. Mark and/or adhere the base of the EL wire JST connector onto clothing, allowing the full length of the connector to flex. Be sure that the JST connector can easily reach the EL Sequencer.

    alt text
  9. Starting at the base of the JST connector, attach EL wire strands to your chosen article of clothing.

    alt text

    Sew EL wire onto clothing using strong thread or dental floss, or use an appropriate fabric adhesive.

    alt text

    Prior to adhering the EL wire, it is recommended to use safety pins to determine placement of the EL wire on each article of clothing while you are wearing it. EL wire is flexible but not so stretchy, so give yourself some wiggle room.

    It is also recommended to use separate EL wire strands on different articles of clothing to facilitate the process of taking it on/off.

Program It!

  1. Connect EL Sequencer to computer via 5V FTDI Breakout Board or cable.

  2. Program the EL Sequencer using the Arduino platform; the EL Sequencer runs an ATmega328p at 8 MHz and 3.3V.

  3. Determine how you want to use the sound detector output(s) to control the EL wire. The sample program below utilizes the gate channel output to turn on the EL wire if there is a sound detected.

For a simple example sketch, you can copy the code below or you can visit the following link.

language:c
// Sound Activated EL Wire Costume
// Blink EL Wire to music and other ambient sound.
//JenFoxBot
void setup() {
  Serial.begin(9600);
  // The EL channels are on pins 2 through 9
  // Initialize the pins as outputs
  pinMode(2, OUTPUT);  // channel A
  pinMode(3, OUTPUT);  // channel B
  pinMode(4, OUTPUT);  // channel C
  pinMode(5, OUTPUT);  // channel D
  pinMode(6, OUTPUT);  // channel E
  pinMode(7, OUTPUT);  // channel F
  pinMode(8, OUTPUT);  // channel G
  pinMode(9, OUTPUT);  // channel H
//Initialize input pins on EL Sequencer
  pinMode(A2, INPUT);
}
void loop()
{
  int amp = digitalRead(A2);

  //If Gate output detects sound, turn EL Wire on
  if(amp == HIGH){

    digitalWrite(2, HIGH); //turn EL channel on
    digitalWrite(3, HIGH);
    digitalWrite(4, HIGH);
    delay(100);
  }

    digitalWrite(2, LOW); //turn EL channel off
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);

}

This program is just one example of what is possible with the SparkFun Sound Detector. Depending on your needs, different responses can be achieved by using the “envelope” and “audio” outputs of the sound detector. The EL Sequencer can individually control up to 8 different EL wire strands using the three sound detector output signals, so there are tons of possibilities to customize your sound-activated outfit!

More information about the sound detector output signals:

The gate channel output is a digital signal that is high when a sound is detected and low when it is quiet. The envelope channel output traces the amplitude of the sound, and the audio output is the voltage directly from the microphone. Check out the plot below for the actual output voltage of the sound detector.

alt text

In the photo above, the red trace corresponds to the gate signal output, the light green trace corresponds to the envelope signal output, and the dark green trace corresponds to the audio signal output. More info can be found in the Sound Detector Hookup Guide.

Test, Secure, and Show Off!

  1. Connect all components to the EL Sequencer (inverter, battery, sound detector), and place in belt pouch. Turn the system on, make some noise (e.g. clapping, snapping, or music), and check that the EL wire flashes when there is a sound.

  2. If the outfit works as expected, secure all connections by coating them in a (thin) layer of epoxy. Let dry for at least 24 hours.

    Epoxy is a very permanent adhesive, so if you want to reuse any of the components, try other adhesives like hot glue or electrical tape (less secure, but adjustable and removable).

    You can reduce the overall strain on individual connections by ensuring that wires are securely fastened to the belt and/or pouch approximately one inch (1") from all connections. The goal is to allow the EL wire to flex while keeping electrical connections rigid, as the connections are the most likely point of breakage.

  3. Wear your one-of-a-kind, high-tech outfit and go show it off to the world!

alt text

You can also see the costume in action in the videos below.

Resources and Going Further

  • There are tons of fabulous, and practical, uses for EL wire. Check out this EL Wire Light-Up Dog Harness to add matching lights to your favorite furry friend!
  • Explore different sensors to trigger EL wire with the EL Sequencer!

You can find more of Jen FoxBot’s projects on her blog and YouTube channel.


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

Button Pad Hookup Guide

$
0
0

Button Pad Hookup Guide a learn.sparkfun.com tutorial

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

Introduction

This tutorial introduces matrix-scanning tecnniques, using the SparkFun 4x4 Button Pad to build an illuminated keypad.

alt text

4x4 Button Pad with Arduino Mega 2560

More importantly, we’ll introduce the concepts underlying the design and implementation of matrix scanning, so the reader can adapt and extend the techniques for their own projects.

Covered in this Tutorial

This tutorial is structured as a series of progressive exercises. First, we’ll explore the underlying concepts and underpinnings of the design. Then we’ll apply what we’ve learned, assembling the PCB, and working through several applications, starting simply, then adding features and complexity.

  1. We’ll start by assembling the the keypad.
  2. Next, we’ll introduce matrix scanning by getting a single color of LED to light.
  3. From there, we’ll add the buttons as an input device.
  4. Finally, we’ll enable to other colors of the LEDs in the matrix.

Along the way, we’ll explore some of the design decisions that contribute to the keypad, and look at some of the coding techniques that are used to control the hardware.

Suggested Reading

  • We’re going to be doing some low-level programming in this tutorial. This assumes that you’re familiar with Binary numbers and converting them to and from hexadecimal and decimal representations.
  • In particular, we’re going to be using bitwise operators to perform the matrix scan.
  • You’ll need to be comfortable with Through-hole soldering. Assembling the button pad involves some more sophisticated soldering techniques than most of our other soldering projects.
  • The matrix scanning will take advantage of internal Pull-up Resistors
  • The matrix scanning also uses diodes to isolate the switches from each other.

Background

Even if you’re just getting into the world of microcontrollers and embedded programming, you’ve probably hooked some buttons and LEDs up to your system, and written programs that let you turn the LEDs on and off using the buttons. It’s fun to make an LED light up, and even more fun to have a switch that turns it on and off.

Exercises #3, #4, and #5 in the SIK Experiment Guide are versions of exactly that. In those experiments, a variety of LEDs and buttons are attached to a RedBoard, usually with one pin attached to a single button or LED.

alt text

If a couple switches and LEDs are fun, then heaps of LEDs and buttons are even better, right?

It naturally leads to questions about the limits of button and LED attachment. If a RedBoard allows 20 pins for digital I/O (digital pins 0-13, and repurposing A0 through A5 as digital), that allows a mix of buttons and LEDs totaling 20 units to be connected. This device-directly-to-pin connection strategy also assumes that we don’t need to use pins for other purposes, such as serial communication.

That’s a pretty serious constraint for many applications.

A Classic Example

Let’s look at a classic microcontroller system with a stylish “buttons & LEDs” user interface, the Roland TR-808 drum machine.

alt text

Across the lower edge of the control panel are 16 pushbutton switches, each with a captive red LED. The machine uses the LEDs to indicate its current status, and pressing a button causes the associated LED to toggle on and off.

The 808 was introduced in 1980. The NEC μPD650C microprocessor inside was state of the art for its day, running at 500 KHz (a screaming half megahertz!). It had nine 4-bit wide ports for I/O, but a number of those ports were consumed by the external memory bus (accessing the four KB of external RAM), leaving 20 pins for I/O.

But, the designers of the TR-808 connected all 32 of those components using only twelve I/O pins.

How did they do it? Let’s look at that section of the schematic.

alt text

TR-808 keys and LEDs (Courtesy Archive.org)

Here you see the LEDs near the top, the buttons below that, and the microcontroller along the left. The LEDs and buttons are in a scan matrix arrangement.

An Introduction To Matrix Scanning.

Matrix scanning is a common technique used to expand the number of inputs or outputs beyond the number of available pins. Matrix scanning requires some cleverness on both the hardware and software sides of the system – there are some subtle factors at play.

To create a scan matrix, instead of using n pins directly as input or outputs, we allocate them as the axes of a Cartesian coordinate system – think of them like lines of latitude and longitude. Matrices are usually described using the terms row for an X-axis group, and column for a Y-axis group. Any intersection in the matrix can be described using its X,Y or row, column coordinates.

alt text

If you're having trouble keeping them straight, remember that Doric and Ionic columns are vertical structures in classical architecture.

Also keep in mind that the physical layout of a matrix circuit may not correspond to the conceptual axes used in the design. We could lay LEDs out in a circle, but still use X,Y based scanning to address each of them.

The scan matrix circuit places electronic components at the row, column intersections. By selecting a single row and column at a time, each component can be addressed uniquely.

A Simple Example

Let’s explore a simple example. Using four pins, we’ll use two of them as row selectors, and the other two as column selectors. At each intersection in the matrix, we’ll install a pushbutton switch that shorts the row to the column.

alt text

  • The row pins are configured as inputs, with pull-up resistors. We’ll refer to them as 1 and 2.
  • The column pins are configured as outputs. We’ll call them A and B.
  • At the intersection of each pair of pins, we’ll place a momentary-contact switch that bridges the row to the column when it is pressed.

To use this matrix, we drive a single output at a time to select a column. While it’s driven, we read the inputs. If we see the drive signal coming back on the input pins, we know that the switch at that X,Y position is closed.

Practical scan matrices often invert the voltages on the pins for a couple of clever reasons. Using inverted logic is called an active low system.

Many microcontrollers have input pins that can be configured with an internal pull-up resistor. If nothing is driving a pulled-up pin, it will read as a logic high. It's uncommon for port pins to have an internal pull-down.

To take advantage of those internal pull-up resistors, scan matrices often use inverted logic. The selected row is set to a low level, and the others are set high. Reading the columns, we look for a logic low to indicate that a button is closed, allowing the selection signal through. This is also why we'll use the relative terms "selected" or "driven," rather than the absolute terms "high" and "low."

The scan consists of walking a logic low around the output pins, and looking for that low on the input pins.

alt text

Above, the button at B1 is held. As the scan progresses, it does the following:

  1. Nothing is selected. Outputs A and B are both high, and we don’t worry about inputs 1 and 2.
  2. Column A is selected with a logical low.
    • The system reads inputs 1 and 2. Both are open, so the pull-up resistors cause the inputs to be pulled high. Since this is an active low matrix, the high inputs indicate nothing is pressed.
  3. The system deselects column A by driving it high and selects column B is by driving it low.
    • The system reads inputs 1 and 2. Since switch B1 is held, the low level from the column selection shows up at input 1.
    • By pairing the column output (B) with the detected switch (1), the system knows that switch B1 is pressed.
  4. Finally, everything is deselected by driving both outputs high.

The Problem With Simple

The process described above works well when a single button is held, but it can be problematic when more than one button is held at a time. Let’s look at what happens when we press buttons A1 and B1 together.

alt text

When the scanning sets column output A low, button A1 puts that low voltage onto row 1. Because A2 is also held, the low selection voltage from A is put onto column B, even though B is not selected, and putting a high level on the output pin.

This is a problem!

We have inadvertently connected two outputs together, and driven them to different logic levels. It’s hard to predict what the voltage read by input 1 will be. Outputs A and B are contending, and the results depend on the specific architecture of the input and output pins.

  • In a perfect universe, the two outputs would balance each other, and the row would sit halfway between the voltages (IE: at 2.5V on a 5V system).
  • The universe isn’t usually so perfect. It’s more likely that one pin can drive harder than the other, and row 1 will be either high or low.
  • Sometimes the universe is downright malevolent. By shorting two outputs together, it’s possible that the circuitry inside one or both pins could be damaged, and possibly burned out.

Regardless of the actual result, connecting port pins together like this is considered poor practice. Ultimately, the circuit is too simple to be very useful.

A Step Above Simple

To fix the above situation, diodes are put in series with each button, as shown below. The diodes isolate the scan columns from each other, even when multiple buttons are held simultaneously.

alt text

With the diodes in place, and we hold A1 and B1 at the same time, the diode on B1 won’t conduct the row voltage back to column B. The short circuit no longer exists, and we can individually detect that A1 and B1 are pressed at the same time.

This circuit is commonly found in MIDI keyboards, where the microcontroller needs to be able to correctly detect that multiple keys are held simultaneously, in order to play chords.

This is also the sort of circuit used in high-quality PC keyboards. Being able to correctly detect arbitrary key combinations is known as N-Key Rollover. While it’s not especially useful for everyday touch-typing, it can be very important for gaming, and alternate typing systems, such as braille, and chord typing.

Turning Things Around

We’ve seen how to scan a 2x2 key matrix for registering input. Now let’s turn things around, and use a 2x2 LED matrix for output. The matrix places LEDs at the junctions of the matrix.

alt text

The LED matrix takes advantage of what we discussed in the switch matrix analysis, above – diodes (or, more specifically, Light Emitting Diodes) only conduct in one direction, when the anode is at a higher voltage than the cathode. If both ends are at the same voltage (both high, or both low), or the diode is reverse biased (anode lower than cathode), then current doesn’t flow, and the LED doesn’t light up.

Differing from the button examples above, the driving pins are all configured as outputs. By carefully steering voltage onto the columns and rows, we control the voltage across the LEDs, allowing us to address each LED individually.

Let’s look at how an active low scan would proceed if we want to light up B1, while leaving the other diodes dark.

alt text

  1. At the start of the scan, all pins are high.
  2. The first column is selected by driving pin A low. We don’t want the LEDs in column A to light, so we also drive pins 1 and 2 low. There is no voltage across the LEDs, which are therefore dark.
  3. Column A is deselected be driving it high, and Column B is selected by driving it low. To get LED B1 to light, we also drive row 1 high. B1 is forward biased, and illuminates.
  4. At the end of the scan, column B is deselected, and rows 1 and 2 are also driven high.

The LED is only illuminated while column B is being scanned. This takes advantage of how our eyes perceive the world around us – when an LED flashes on and off quickly enough, we see it as being solidly illuminated (although it may appear to be less bright than a continuously lit LED.). This is one example of the phenomenon of persistence of vision.

Growing larger

To address more buttons or LEDs, we simply add columns and rows. For instance, if we wanted 16 buttons , we could add two rows and two columns, making a 4x4 matrix.

A 4x4 matrix almost brings us full circle, back to the Roland TR-808, with its 16 buttons and 16 LEDs. By including both buttons and LEDs, the 808 hits one last design optimization: the scan outputs for the switches are shared with the LEDs.

alt text

If we look a little more closely at the schematic, we see (from top to bottom)

  • Port G pins 0 through 3 are the LED row select inputs.
  • Port B pins 0 through 3 are the switch row inputs.
  • Port H pins 0 through 3 are the column outputs, common to both the switches and LEDs.

The output pins in ports G and H are buffered using discrete transistors, since the port pins of the μPD650C aren’t capable of sourcing or sinking the current required to get the LEDs to light up.

Port B has discrete pull-down resistors, an indication that this is an active-high scan matrix. The μPD650C doesn’t have internal pull-ups, so there’s no reason to invert the scan just to take advantage of them.

You’ll also notice that instead of a diode per button, the column select lines each have a single diode – this isolates the column selection outputs, but doesn’t prevent misleading behavior if multiple switches are held simultaneously (although such presses can be detected and ignored in software).

A Few More Details

We mentioned above that the scan matrix requires cleverness in both the hardware and software. Our discussion above has covered some of the clever hardware design issues, such as installing diodes to prevent contention, using active-low logic to take advantage of the internal pull-ups on port pins, and sharing select lines between the button and LED matrices.

There are a handful of other issues that a scanned matrix need to take into account, often handled by the associated software.

  • The rate at which the scan progresses is a key parameter. When the scan is too slow, the LEDs will visibly flicker, and the buttons will seem unresponsive.
  • A faster scan smooths out the LEDs, but becomes susceptible to detecting small glitches in the button actuation. We’ll explore software techniques for removing button glitches when we hook up the buttons.

With the basic concepts of matrix scanning covered, lets look at how they’re implemented in the 4x4 RGB Button Pad!

The 4x4 RGB Button Pad

With the basics of matrix scanning established, let’s look at how they work out in the SparkFun 4x4 RGB Button Pad.

alt text

Button Pad Schematic

From what we explored in the previous section, we recognize the columns and rows. Each junction in the matrix consists of a pushbutton switch and RGB LED. The LEDs are a single envelope containing separate red, green and blue LEDs, which share a common cathode. The LEDs are set up as three overlapping 4x4 matrices, one for each color.

Errata

The Button pad PCB design dates from around 2008, relatively early in SFE history. As such, it’s not completely up to our modern standards for labeling marking and labeling. Let’s clarify a few points.

  • First, the RGB LED that the PCB was designed for is no longer available. We stock a nearly-equivalent one, but there’s one catch – the Green and Blue pins have traded places.
  • The PCB silkscreen has component designators for the LEDs printed on top, but they are marked as C1 to C4. The C (usually used for capacitors) should actually be a D (for diode).
  • The row signals are combined into busses (the horizontal dark blue lines). This is a schematic shorthand that results in a simpler schematic, but can make it harder to follow individual wires around the page. In this case, four signals enter the bus on the left and are pulled out at each junction in the matrix.
  • The connections at the bottom are marked “ground”. These would more accurately be labeled “column”.
    • For the buttons, they could be marked column select.
    • For the LEDs, they are the LED cathodes.
  • Rows and columns are both labeled numerically (1 through 4), while it might be easier to understand if one axis were alphabetical, A through D.

Let’s assemble our keypad, and start working with it.

Materials

The following exercises use the items on the following wishlist.

Wishlist for 4x4 Button Pad Components


Tools

You’ll also need to following tools.


Before we assemble the button pad, let’s take a closer look at some of the parts.

The PCB

The PCB is designed with geometric features that interface with the button pad. The most obvious are the circular traces printed on top, with interlocking fingers that are bridged by the rings in the keypad, completing the button circuit.

alt text

Button Contacts

Inside each set of circles is the footprint for a common-cathode RGB LED.

The Button Pad

alt text

4x4 Rubber Keypad

The 4x4 Rubber Keypad is molded from Dow Corning Silastictm Silicone rubber. It’s similar to the keypads used by television remote controls.

If we flip it over, we’ll see a some particular details molded into the rubber.

alt text

Back of Keypad

There are several features on the back of the button pad worth noting.

  1. Contact rings– The most important feature is probably the conductive ring molded into the back of each button. It makes contact with fingers on the printed circuit board.
  2. Recesses– Each button also has a hollow cavity in it, leaving room for a 3mm or 5mm PTH LED.
  3. Vents– There are little troughs in the rubber that allow air to escape when the button is pressed. This make it easier to press the buttons, and prevents them from suctioning onto the PCB.
  4. Bosses– These are little pegs that interface with holes in the PCB, to keep the keypad from sliding around.

The Bezels

When the keypad is placed on the PCB, it is held in place by a set of brackets known as the “bezel.”

alt text

Sandwich

There are actually four bezels in the wish list, two marked “bottom,” and two marked “top.” These designators indicate the positions the the bezels get installed in. The bottom bezels have tabs that stick out, and the top bezels have recesses those tabs fit into.

alt text

Bottom and Top Bezels

Assembly

As we saw in the last section, the rubber button pad needs to sit on the PCB to work properly. If anything sticks up too far, the pad won’t sit properly, and the buttons will be hard to press.

To keep the components appropriately short, we’ll take a little extra care as we install them.

Diodes

The 1n4148 diodes are installed on the back of the PCB, and would usually be soldered on the back of the board. However, since the resulting solder fillets would stick up too far, we’ll actually trim them short, and then solder them from the back side of the PCB. It’s a bit more work, but the end result is worth the effort.

There are 16 diodes. The diode locations on the PCB are simply marked with a rectangular outline, with a extra stripe at the cathode end.

To install the diodes, first, bend the leads of the diode to fit the holes in the PCB.

alt text

Push the diode down until the body touches the PCB, but don’t solder it in. Instead, flip the board over and trim the leads flush.

alt text

Then remove the trimmed diode, and snip a tiny bit more off the leads. We want to have enough lead left to fit into the hole on the PCB, but not so much that it protrudes.

alt text

Finally, put the diode back in the footprint, taking care to keep the cathode stripe pointed the correct direction, matching the silkscreen. Solder it in by tacking the remaining lead, adjacent to the diode body.

alt text

Before moving on, double-check that solder hasn’t flowed through the hole, making a bump on the top of the PCB. If it has, you can cut it away with your flush cutters, or remove the bump with a bit of solder wick.

LEDs

Each RGB LED has four leads. The anode of each color has its own pin, and they share a common cathode. The cathode is the longest pin of the bunch.

alt text

The LEDs are polarized. The body has a small flat edge at the base, that corresponds to the flat on the PCB silkscreen

alt text

To put the LED on the PCB, insert the diode into the footprint. The longest lead is the second hole in from the flat, the other leads are each a bit shorter. With practice, you can insert the LED by “walking” it from side to side, and each lead will fall into place.

We need to cinch the LED up close to the PCB, to ensure that it will fit inside the recess in the button. If you’re unsure about how tall it can be, you can test the fit with the keypad over the LED.

alt text

Before soldering, doublecheck the alignment of the flat side of the LED. When you’re sure it’s the right way around, solder it down, and snip the leads.

Wires

For the following exercises, we’ll simply be using solid-core wire to connect the keypad to the Arduino Mega. If you’ve got a different application in mind, removable connectors or snappable headers might be more suitable. However you chose to connect the button pad, the goal should be to keep the connectors from protruding through the PCB, interfering with the rubber buttons

A fully populated 4x4 RGB button pad requires 24 wires to connect it to the microcontroller. We’ll install the wires incrementally in the following sections, but each one will be installed using the same basic method. Like the 1N4148 diodes, we’ll be soldering them from the back of the PCB, so they don’t protrude and create bumps under the keypad.

The exercises in this guide were done on a workbench, with the button pad sitting adjacent to the Mega. For that application, each wire was about 6" (15 cm) long.

alt text

The PCB end of the wire was stripped to reveal about 0.1" of copper.

alt text

That end was bent into a gentle curve, and soldered to the PCB. Like the diodes, it was soldered from the back, and anything protruding on the button-side on the board was trimmed flush.

alt text

The other end was stripped about 0.25", so it could be inserted into the headers on the Mega.

alt text

Final Assembly

The last assembly step is to place the buttonpad over the PCB…

alt text

…and secure it with the plastic bezels. Start with the “bottom” bezels (the ones with the protruding tabs), on opposite corners.

alt text

Then add the “top” bezels on the remaining corners.

alt text

Finally, insert the Philips screws, and thread them into the standoffs.

alt text

Take care to not overtighten the screws. We want to hold the button pad in place, but not tighten it so much that it gets damaged.

Exercise #1: Monochrome LEDs

Our first exercise is to get the red LED scan working.

Wiring

To start out, we need to wire up the parts of the matrix that hit the red LEDs – the LED columns and the red LED row pins.

To make it easier to think about, set the button pad so that the button side is facing you, and connectors are on the left and bottom edges.

alt text

This keeps the rows and columns in a fairly sensible order and orientation. The columns are the connections across the bottom, and the rows are the connections up the left edge.

For 16 LEDs in a 4x4 matrix, that makes 4 rows + 4 columns = 8 connections total. These 8 connections are detailed in the following table.

FunctionColorButton Pad
Connection
Mega
Connection
Red LED Row 1RedRed122
Red LED Row 2RedRed230
Red LED Row 3RedRed333
Red LED Row 4RedRed436
LED Column AGreenLED-GND-442
LED Column BYellowLED-GND-343
LED Column CBlueLED-GND-244
LED Column DWhiteLED-GND-145

You’ll notice that the column selects are on adjacent pins, but the red LED rows are spaced apart – this leaves the interceding pins for the corresponding green and blue connections.

With the wires attached to the PCB, it will look like this:

alt text

Each wire was prepared and soldered as described in the assembly section, and the end was stuck into the header on the Mega.

alt text

4x4 Button Pad with Arduino Mega

Code

The following sketch illuminates a single red LED at a time. The illuminated LED walks around the matrix.

language:c

/******************************************************************************
red-only.ino
Byron Jacquot @ SparkFun Electronics
1/6/2015

Example to drive the red LEDs in the RGB button pad.

Exercise 1 in a series of 3.
https://learn.sparkfun.com/tutorials/button-pad-hookup-guide/exercise-1-monochrome-leds

Development environment specifics:
Developed in Arduino 1.6.5
For an Arduino Mega 2560

This code is released under the [MIT License](http://opensource.org/licenses/MIT).

Distributed as-is; no warranty is given.
******************************************************************************/
//config variables
#define NUM_LED_COLUMNS (4)
#define NUM_LED_ROWS (4)
#define NUM_COLORS (1)

// Global variables
static bool LED_buffer[NUM_LED_COLUMNS][NUM_LED_ROWS];
static int32_t next_advance;
static uint8_t led_index;

static const uint8_t ledcolumnpins[NUM_LED_COLUMNS]   = {42,43,44,45};
static const uint8_t colorpins[NUM_LED_ROWS] = {22,30,33,36};

static void setuppins()
{
  uint8_t i;

  // initialize all of the output pins

  // LED column lines
  for(i = 0; i < NUM_LED_COLUMNS; i++)
  {
    pinMode(ledcolumnpins[i], OUTPUT);

    // with nothing selected by default
    digitalWrite(ledcolumnpins[i], HIGH);
  }

  // LED row lines
  for(i = 0; i < NUM_LED_ROWS; i++)
  {
    pinMode(colorpins[i], OUTPUT);

    // with nothing driven by default
    digitalWrite(colorpins[i], LOW);
  }

}

static void scan()
{
  static uint8_t current = 0;
  uint8_t val;
  uint8_t i, j;

  // Select a column
  digitalWrite(ledcolumnpins[current], LOW);

  // write the row pins
  for(i = 0; i < NUM_LED_ROWS; i++)
  {
    if(LED_buffer[current][i])
    {
      digitalWrite(colorpins[i], HIGH);
    }
  }

  delay(1);

  digitalWrite(ledcolumnpins[current], HIGH);

  for(i = 0; i < NUM_LED_ROWS; i++)
  {
    digitalWrite(colorpins[i], LOW);
  }

  // Move on to the next column
  current++;
  if (current >= NUM_LED_COLUMNS)
  {
    current = 0;
  }

}

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.print("Starting Setup...");

  // setup hardware
  setuppins();

  // init global variables
  next_advance = millis() + 1000;
  led_index = 0;

  // Initialize the LED display array
  for(uint8_t i = 0; i < NUM_LED_COLUMNS; i++)
  {
    for(uint8_t j = 0; j < NUM_LED_ROWS; j++)
    {
      LED_buffer[i][j] = false;
    }
  }
  // Set the first LED in the buffer on
  LED_buffer[0][0] = true;

  Serial.println("Setup Complete.");

}

void loop()
{
  // put your main code here, to run repeatedly:

  scan();

  if(millis() >= next_advance)
  {
    next_advance = millis()+1000;

    LED_buffer[led_index/NUM_LED_COLUMNS][led_index%NUM_LED_COLUMNS] = false;
    led_index++;
    led_index %= (NUM_LED_COLUMNS * NUM_LED_ROWS);
    LED_buffer[led_index/NUM_LED_COLUMNS][led_index%NUM_LED_COLUMNS] = true;
  }
}

The code is an implementation if what we described in the background section. A column is selected, and the corresponding row pins are driven to get the LEDs to light.

Let’s look at a few of the finer points in the code.

  • In an effort to make the code more portable and configurable, the basic parameters are defined in a set of definitions at the top of the sketch.
  • The image displayed by the LEDs is declared as a two-dimensional array of bool. The array dimensions match the rows and columns.
  • The pins themselves are defined as constant one-dimensional arrays. This makes it easy to:
    • Reassign the pins, by simply editing the array initialization values.
    • Walk from pin to pin, by incrementally indexing the array.
  • The matrix scan is performed by the scan() function.
    • On each invocation, the scan selects the next column, then writes the corresponding row pins with the values from the LED array.
    • It pauses for a millisecond, which allows the LED to glow for a moment.
      • If you’re curious, remove this delay(1), and you’ll find that the LEDs get significantly dimmer.
    • Then it deselects the column and stops driving the rows.
  • loop() calls the scan function every time it is invoked. Because it contains the delay(1) mentioned above, the scan updates at most once every millisecond.
  • Every second (or 1000 millis()), the loop walks the illuminated LED to the next position.

The next exercise is to add button inputs to this, allowing you to turn each LED on or off by pressing the corresponding button.

Exercise #2: Monochrome plus Buttons

Our Second exercise is to add the buttons to the scan matrix. We’ll use them as inputs, to toggle the corresponding LEDs on and off.

We’re going to assume that you’re following this guide in order, and have just completed exercise #1. This exercise will describe the additions needed to add the button matrix, building incrementally on top of exercise #1.

Wiring

We’re going to add another 8 wires to interface the button matrix. This breaks down as four button columns and four button rows, and described in the following table.

FunctionWire
Color
Button Pad
Connection
Mega
Connection
Button Row 1BlackSwitch146
Button Row 2YellowSwitch247
Button Row 3GreenSwitch348
Button Row 4BlueSwitch449
Button Column AGreenSWT-GND-450
Button Column BYellowSWT-GND-351
Button Column CBlueSWT-GND-252
Button Column DWhiteSWT-GND-153

Again, the wires are prepared and soldered as described in the assembly section, and the other end is stuck into the header on the Mega. With these wires, we’re adding column and row connections for the buttons. When they’re in place, the connections to the PCB look like this.

alt text

Red LED and Button Connections

Code

The following sketch adds button support to the previous sketch.

language:c
/******************************************************************************
red-plus-buttons.ino
Byron Jacquot @ SparkFun Electronics
1/6/2015

Example to drive the red LEDs and scan the buttons of the RGB button pad.

Exercise 2 in a series of 3.
https://learn.sparkfun.com/tutorials/button-pad-hookup-guide/exercise-2-monochrome-plus-buttons

Development environment specifics:
Developed in Arduino 1.6.5
For an Arduino Mega 2560

This code is released under the [MIT License](http://opensource.org/licenses/MIT).

Distributed as-is; no warranty is given.
******************************************************************************/
//config variables
#define NUM_LED_COLUMNS (4)
#define NUM_LED_ROWS (4)
#define NUM_BTN_COLUMNS (4)
#define NUM_BTN_ROWS (4)
#define NUM_COLORS (1)

#define MAX_DEBOUNCE (3)

// Global variables
static bool LED_buffer[NUM_LED_COLUMNS][NUM_LED_ROWS];

static const uint8_t btncolumnpins[NUM_BTN_COLUMNS] = {50, 51, 52, 53};
static const uint8_t btnrowpins[NUM_BTN_ROWS]       = {46, 47, 48, 49};
static const uint8_t ledcolumnpins[NUM_LED_COLUMNS] = {42, 43, 44, 45};
static const uint8_t colorpins[NUM_LED_ROWS]        = {22, 30, 33, 36};

static int8_t debounce_count[NUM_BTN_COLUMNS][NUM_BTN_ROWS];

static void setuppins()
{
  uint8_t i;

  // initialize
  // select lines
  // LED columns
  for (i = 0; i < NUM_LED_COLUMNS; i++)
  {
    pinMode(ledcolumnpins[i], OUTPUT);

    // with nothing selected by default
    digitalWrite(ledcolumnpins[i], HIGH);
  }

  // button columns
  for (i = 0; i < NUM_BTN_COLUMNS; i++)
  {
    pinMode(btncolumnpins[i], OUTPUT);

    // with nothing selected by default
    digitalWrite(btncolumnpins[i], HIGH);
  }

  // button row input lines
  for (i = 0; i < NUM_BTN_ROWS; i++)
  {
    pinMode(btnrowpins[i], INPUT_PULLUP);
  }

  // LED drive lines
  for (i = 0; i < NUM_LED_ROWS; i++)
  {
    pinMode(colorpins[i], OUTPUT);
    digitalWrite(colorpins[i], LOW);
  }

  // Initialize the debounce counter array
  for (uint8_t i = 0; i < NUM_BTN_COLUMNS; i++)
  {
    for (uint8_t j = 0; j < NUM_BTN_ROWS; j++)
    {
      debounce_count[i][j] = 0;
    }
  }
}

static void scan()
{
  static uint8_t current = 0;
  uint8_t val;
  uint8_t i, j;

  // Select current columns
  digitalWrite(btncolumnpins[current], LOW);
  digitalWrite(ledcolumnpins[current], LOW);

  // output LED row values
  for (i = 0; i < NUM_LED_ROWS; i++)
  {
    if (LED_buffer[current][i])
    {
      digitalWrite(colorpins[i], HIGH);
    }
  }

  // pause a moment
  delay(1);

  // Read the button inputs
  for ( j = 0; j < NUM_BTN_ROWS; j++)
  {
    val = digitalRead(btnrowpins[j]);

    if (val == LOW)
    {
      // active low: val is low when btn is pressed
      if ( debounce_count[current][j] < MAX_DEBOUNCE)
      {
        debounce_count[current][j]++;
        if ( debounce_count[current][j] == MAX_DEBOUNCE )
        {
          Serial.print("Key Down ");
          Serial.println((current * NUM_BTN_ROWS) + j);

          // Do whatever you want to with the button press here:
          // toggle the current LED state
          LED_buffer[current][j] = !LED_buffer[current][j];
        }
      }
    }
    else
    {
      // otherwise, button is released
      if ( debounce_count[current][j] > 0)
      {
        debounce_count[current][j]--;
        if ( debounce_count[current][j] == 0 )
        {
          Serial.print("Key Up ");
          Serial.println((current * NUM_BTN_ROWS) + j);

          // If you want to do something when a key is released, do it here:

        }
      }
    }
  }// for j = 0 to 3;

  delay(1);

  digitalWrite(btncolumnpins[current], HIGH);
  digitalWrite(ledcolumnpins[current], HIGH);

  for (i = 0; i < NUM_LED_ROWS; i++)
  {
    digitalWrite(colorpins[i], LOW);
  }

  current++;
  if (current >= NUM_LED_COLUMNS)
  {
    current = 0;
  }

}

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);

  Serial.print("Starting Setup...");

  // setup hardware
  setuppins();

  // init global variables
  for (uint8_t i = 0; i < NUM_LED_COLUMNS; i++)
  {
    for (uint8_t j = 0; j < NUM_LED_ROWS; j++)
    {
      LED_buffer[i][j] = 0;
    }
  }

  Serial.println("Setup Complete.");

}

void loop() {
  // put your main code here, to run repeatedly:

  scan();

}

Once the code is loadeed, the keypad doesn’t do anything on its own, but when you press a button, the corresponding LED toggles on and off.

alt text

Button matrix in command of LED matrix

The button scan is added in parallel to the LED scan. A column is selected, and a row is read. Some new definitions have been added to dimension the button matrix, plus some new data tables to define the pins for those functions.

The most complex part of this code is the button press detection, which involves a little extra work. When the buttons open or close, sometimes the change isn’t especially clean – the contacts might chatter or bounce when they close. The waveforms below show a couple of different switch actuations, captures from this button pad.

alt text

Captured switch closures

The nice closure on the left was the result of pressing the button quickly and decisively, straight down. The closure on the right is the result of pushing the button slowly, at an oblique angle. The ring inside twisted down onto the fingers of the PCB contacts. In this instance it takes roughly 20 milliseconds for the button to close solidly.

The glitchiness can cause the scanning system to misinterpret the chatter as multiple keypresses, when in fact the button was only actuated once.

To prevent this, the software uses some logic to perform debouncing. The scan system has to find a switch closed for several scans in a row before it decides that the switch is actually closed. It uses the two-dimensional array debounce_count to keep track of the number of successive scans. When a switch is found closed, the counter is incremented. When the counter reaches the constant MAX_DEBOUNCE, it decides that the switch has been solidly and cleanly closed, and acts on the keypress.

When a key is released, the counter counts back down to zero. This example prints a message when it detects a release. Some applications don’t take any action on key releases (like the keypad on an ATM), but it’s necessary in others (such as MIDI keyboards).

For the rubber button pad, a MAX_DEBOUNCE of 2 or 3 seems to work fairly well. Other types of buttons might require different debounce values.


With the red LEDs and buttons working, the final step is to get the green and blue LEDs working.

Exercise #3: RGB LEDs and Buttons

Wiring

Hang in there, only 8 more wires to go!

With the red LEDs and buttons working, let’s finish up by adding the blue and green LEDs to the mix.

FunctionWire
Color
Button Pad
Connection
Mega
Connection
Green Row 1GreenBlue1*24
Blue Row 1BlueGreen1*26
Green Row 2GreenBlue2*31
Blue Row 2BlueGreen2*32
Green Row 3GreenBlue3*34
Blue Row 3BlueGreen3*35
Green Row 4GreenBlue4*37
Blue Row 4BlueGreen4*38

* Keep in mind that the LEDs we’ve used have their green and blue legs transposed when referencing the PCB markings. Yes, we are intentionally swapping green and blue in the wiring!

alt text

With all of these wires, it’s starting to look like a bird’s nest!

alt text

Code

The final sketch builds on the previous two.

language:c

/******************************************************************************
rgb-plus-buttons.ino
Byron Jacquot @ SparkFun Electronics
1/6/2015

Example to drive the RGB LEDs and scan the buttons of the RGB button pad.

Exercise 3 in a series of 3.
https://learn.sparkfun.com/tutorials/button-pad-hookup-guide/exercise-3-rgb-leds-and-buttons

Development environment specifics:
Developed in Arduino 1.6.5
For an Arduino Mega 2560

This code is released under the [MIT License](http://opensource.org/licenses/MIT).

Distributed as-is; no warranty is given.
******************************************************************************/
//config variables
#define NUM_LED_COLUMNS (4)
#define NUM_LED_ROWS (4)
#define NUM_BTN_COLUMNS (4)
#define NUM_BTN_ROWS (4)
#define NUM_COLORS (3)

#define MAX_DEBOUNCE (3)

// Global variables
static uint8_t LED_outputs[NUM_LED_COLUMNS][NUM_LED_ROWS];
static int32_t next_scan;

static const uint8_t btnselpins[4]   = {50,51,52,53};
static const uint8_t btnreadpins[4] = {46,47,48,49};
static const uint8_t ledselpins[4]   = {42,43,44,45};

// RGB pins for each of 4 rows
static const uint8_t colorpins[4][3] = {{22,24,26}, {30,31,32},{33,34,35},{36,37,38}};


static int8_t debounce_count[NUM_BTN_COLUMNS][NUM_BTN_ROWS];

static void setuppins()
{
    uint8_t i;

    // initialize
    // select lines
    for(i = 0; i < NUM_LED_COLUMNS; i++)
    {
        pinMode(ledselpins[i], OUTPUT);

        // with nothing selected by default
        digitalWrite(ledselpins[i], HIGH);
    }

    for(i = 0; i < NUM_BTN_COLUMNS; i++)
    {
        pinMode(btnselpins[i], OUTPUT);

        // with nothing selected by default
        digitalWrite(btnselpins[i], HIGH);
    }

    // key return lines
    for(i = 0; i < 4; i++)
    {
        pinMode(btnreadpins[i], INPUT_PULLUP);
    }

    // LED drive lines
    for(i = 0; i < NUM_LED_ROWS; i++)
    {
        for(uint8_t j = 0; j < NUM_COLORS; j++)
        {
            pinMode(colorpins[i][j], OUTPUT);
            digitalWrite(colorpins[i][j], LOW);
        }
    }

    for(uint8_t i = 0; i < NUM_BTN_COLUMNS; i++)
    {
        for(uint8_t j = 0; j < NUM_BTN_ROWS; j++)
        {
            debounce_count[i][j] = 0;
        }
    }
}

static void scan()
{
  static uint8_t current = 0;
  uint8_t val;
  uint8_t i, j;

    //run
    digitalWrite(btnselpins[current], LOW);
    digitalWrite(ledselpins[current], LOW);

    for(i = 0; i < NUM_LED_ROWS; i++)
    {
        uint8_t val = (LED_outputs[current][i] & 0x03);

        if(val)
        {
            digitalWrite(colorpins[i][val-1], HIGH);
        }
  }


  delay(1);

  for( j = 0; j < NUM_BTN_ROWS; j++)
  {
    val = digitalRead(btnreadpins[j]);

    if(val == LOW)
    {
      // active low: val is low when btn is pressed
      if( debounce_count[current][j] < MAX_DEBOUNCE)
      {
        debounce_count[current][j]++;
        if( debounce_count[current][j] == MAX_DEBOUNCE )
        {
          Serial.print("Key Down ");
          Serial.println((current * NUM_BTN_ROWS) + j);

          LED_outputs[current][j]++;
        }
      }
    }
    else
    {
      // otherwise, button is released
      if( debounce_count[current][j] > 0)
      {
        debounce_count[current][j]--;
        if( debounce_count[current][j] == 0 )
        {
          Serial.print("Key Up ");
          Serial.println((current * NUM_BTN_ROWS) + j);
        }
      }
    }
  }// for j = 0 to 3;

  delay(1);

  digitalWrite(btnselpins[current], HIGH);
  digitalWrite(ledselpins[current], HIGH);

  for(i = 0; i < NUM_LED_ROWS; i++)
  {
    for(j = 0; j < NUM_COLORS; j++)
    {
      digitalWrite(colorpins[i][j], LOW);
    }
  }

  current++;
  if (current >= NUM_BTN_COLUMNS)
  {
    current = 0;
  }
}

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);

  Serial.print("Starting Setup...");

  // setup hardware
  setuppins();

  // init global variables
  next_scan = millis() + 1;

  for(uint8_t i = 0; i < NUM_LED_ROWS; i++)
  {
    for(uint8_t j = 0; j < NUM_LED_COLUMNS; j++)
    {
      LED_outputs[i][j] = 0;
    }
  }

  Serial.println("Setup Complete.");
}

void loop() {
  // put your main code here, to run repeatedly:

  if(millis() >= next_scan)
  {
    next_scan = millis()+1;
    scan();
  }
}

Now, instead of toggling the red LEDs between on and off, pressing a button cycles between the different colors. The cycle is off, then red, then green, then blue, then off again.

If you’ve been following the code changes between each exercise, you can probably anticipate what has been added.

  • The array that defines the color output pins has been expanded to be two-dimensional. The second dimension adds pins for the green and blue LEDs.
  • When the button scan detects a button press, it increments the corresponding value in the LED_outputs array.
  • When the LED scan sets the LED outputs, it uses some bitwise operations to convert the button counter into a color bit, and apply it to the LED row outputs.
  • This version doesn’t allow for color mixing – we’ll explore why below.

The Limits of I/O Pins

If you've worked with modern microcontrollers, you're probably used to hanging LEDs off digital output pins, as we've been doing in these examples.

We're actually being a little sloppy by doing this - we're taking advantage of the fact that the Atmel ATMega2560 microcontroller has very robust digital inputs and outputs. They are specified to an absolute maximum of 40 mA, and they behave reasonably well when this limit is exceeded, limiting the current.

Similarly, the overall maximum rated current for the entire processor is 200 mA.

The reason that this example constrains each LED to only red, green or blue is to stay safely within these limits. If we were to light an entire column of LEDs (that's twelve LEDs total, each at roughly 20 mA), they'd add up to 240 mA!

Older microcontrollers allowed much less current per port pin, often in the range of 1 mA. If that range was exceeded, the pin could be fatally damaged. Designing with such controllers meant considering the current consumption per pin more carefully - refer back to the TR-808 schematic, and you'll notice that the pins that drive the LEDs use discrete transistors to increase the current drive capabilities.

For added safety, we should put a resistor inline with each LED scan line. The appropriate values can be calculated using the formula in our resistor applications tutorial.

Extra Credit

Through this guide, we’ve intentionally kept things simple, to demonstrate the matrix scanning concepts. We’ve only scratched the surface of the permutations of matrix scanning.

There are a lot of other variations on these ideas to consider, but we’re leaving them as exercises for the reader.

More Colors

As we discussed in the previous section, we’re only lighting the red, green or blue section of each LED individually, to keep current consumption low. When the author was developing exercise #4, the initial implementation allowed for the RGB LEDs to be on in any combination. The end result was that if too many LEDs were lit simultaneously, they got dim, and the processor heated up. Ultimately, the exercise was revised to only use single colors.

If we want to light more than one section at a time, we can mix them to create other colors, but to do that, we’ll need to source and sink additional current. One solution is to add current limiting resistors in series with each LED Anode, and buffer the signal with high-current line drivers.

If you’re really clever, you can use pulse-width modulation to vary the LED brightness, for an even wider range of colors.

Code Optimizations

The sketches in the exercises were written to be portable. They use the Arduino pin definitions, and digitalRead, and digitalWrite functions, which makes them easy to move to other systems. For instance, you could move this code to a Teensy 3.2 by adjusting the pin numbers in the row and column arrays. But this means handling those individual bits one at a time.

Most microcontrollers define the port pins as adjacent bits in byte or word wide registers. If you’re working with those registers, you can arrange the matrix to gang the digital I/O using byte and word reads and writes. It’s just not as easy to move to a different microcontroller!

As an even more optimized keypad scan can take advantage of external pin interrputs. The scanning is idle until a key is pressed. The key triggers an interrupt, which performs a single scan to determine which key is pressed. When all keys are released, the system idles again.

Bigger and Better

We can combine multiple keypads into a larger matrix by joining the adjacent rows and columns.

Offload The Keypad Scanning

There are peripheral chips that can do the button and LED scanning. The SX1509 I/O expander has a mode that allows it to scan an 8x8 key matrix, and interrupt the host when a key press is detected.

The 2x2 button Pad

The 4x4 button pad has a little brother, the 2X2 button pad, that pairs with a matching PCB. If you’re building a 2x2 button pad, you’ll need a single top bezel to hold it together.

The circuit of the 2x2 button pad is actually set up like a single row of the 4x4 pad, and could be added to the same scan matrix.

Resources and Going Further

Resources

  • The complete Roland TR-808 service notes can be found at archive.org.

Going Further

  • Our Serial LED Matrix uses matrix scanning techniques to address an 8x8 matrix of RGB LEDs.
  • Charlieplexing is a more advanced scanning technique for driving many LEDs with very few pins.
  • Matrix scanning is only one way to interface a bunch of switches. This article compares and contrasts a number of different methods.

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


MP3 Trigger Hookup Guide V24

$
0
0

MP3 Trigger Hookup Guide V24 a learn.sparkfun.com tutorial

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

Introduction

The MP3 Trigger is a versatile, low-cost, low-power embedded audio unit that plays MP3 tracks directly from a FAT32 or FAT16 formatted microSD flash card to a stereo 1/8” (3.5mm) headphone output jack, supporting up to 192kbps stereo playback. The board has 18 external input pins that when pulled to ground, trigger pre-selected MP3 tracks, and a full-duplex serial control port that provides real-time volume control as well remote triggering for up to 255 tracks. There is also an on-board navigation switch for local access and playback of all MP3 tracks on the flash card.

MP3 Trigger

WIG-13720
$49.95

The heart of the MP3 Trigger board is the Cypress PSoC CY8C29466-24SXI microcontroller which serves up MP3 data to a VLSI VS1063 audio codec IC. This version also supports an optional initialization file that can be used to set the serial port baud rate as well as to reprogram any of the 18 trigger inputs to alternate functions, including random and sequential track selection, transport controls and even volume up/down. Each conventional trigger can be set to either allow immediate restarts, or to lock out restarts if audio is playing. Also, a new trigger filename convention provides greater flexibility in naming your MP3 tracks and makes file management easier.

This version of the MP3 Trigger includes firmware that supports the use of an initialization file on the microSD card that can be used to change the serial baud rate, as well as to repurpose any of the 18 trigger inputs to alternate functions, such as random and sequential triggers, navigation controls and even volume controls. In addition, a restart lockout option can be used to prevent any trigger from starting a track if audio is already playing. Using these features, custom applications can often be implemented without the use of a separate microcontroller.

Suggested Materials

To get started with your MP3 Trigger, you’ll need a few items not included. To begin, you’ll need an microSD card on which to store your .mp3 files. A simple way to power the MP3 Trigger while you’re familiarizing yourself with it is to use a 9V wall adapter. If you intend on using your MP3 Trigger with another serial device, you need an FTDI Basic or other serial connection. Last, you will need something though which to play audio. You may use headphones, a 3.5mm-to-3.5mm audio cable to connect to an external audio source, or one of our 3.5mm Audio pigtails to wire your MP3 Trigger to the output you desire.

SparkFun FTDI Basic Breakout - 5V

DEV-09716
$14.95
60
Wall Adapter Power Supply - 9VDC 650mA

TOL-00298
$5.95
3
MicroSD Card with Adapter - 8GB

COM-11609
$13.95
2
Audio Cable TRRS - 18" (pigtail)

CAB-11580
$1.95

The MP3 Trigger supports both SDSC (up to 2GB) and SDHC (up to 32GB) type microSD cards.

Suggested Reading

Before you begin working with the MP3 Trigger, you may find the following tutorials useful:

  • How to Solder - Soldering will be necessary to attach buttons and switches to the trigger inputs.
  • Working with Wire - You’ll likely need to use some wire to attach those buttons and switches.
  • Switch Basics - Learn about the numerous buttons and switches you can use to trigger your audio files.

  • If you plan on using your MP3 Trigger with an Arduino or other microcontroller, you should have a good understanding of Serial Communication, Hexadecimal, ASCII, and Serial Terminals.

Board Overview

Here is a brief overview of the MP3 Trigger’s specifications:

Specifications

  • Input Voltage Range: 4.5V to 12.0V DC, or regulated 3.3V (jumper selectable)
  • Current Consumption: Approximately 45mA idle, 85mA playing
  • Media: SDSC and SDHC microSD cards
  • File system: FAT32 and FAT16
  • Audio output: Headphone stereo (1/8” stereo jack)
  • Trigger inputs: Logic level 3.3V–5.0V, active low inputs, w/ internal pull-ups (connector provides individual grounds, allowing switches or jumpers to be connected directly to each trigger input)
  • Serial: Full duplex, 8-bit, 38.4Kbaud (default, other baud rates supported via initialization file)

The following will highlight the various hardware sections found on the MP3 Trigger.

Power

The MP3 Trigger is designed to be powered a few different ways.

External Power

The fist and most obvious power scheme is to apply external power to the barrel jack connector (5.5x2.1mm center positive). As the silkscreen next to the connector reads, you may power the MP3 Trigger through this jack with 4.5-12V DC.

The solder jumper next to the barrel jack comes set to VBUS by default. Ensure that this jumper is always set to VBUS so long as you’re powering the MP3 Trigger through that connector.

While power is applied to the barrel jack, you may use the USB/EXT switch as an ON/OFF switch to control the power to the MP3 Trigger. It should be powered while in the EXT position.

power option 1

You can also solder power wires directly to the through-holes located on the backside of the board.

back holes

Power is indicated by the red Power LED located in the upper-right corner.

power LED

USB Power/Regulated 3.3V Power Source

If you would like you integrate the MP3 Trigger into an existing system that already has regulated power, you can power the MP3 Trigger through the FTDI Header.

FTDI Port

Heads up! You will need to clear the solder jumper and resolder it so that the 3.3V pad and center pad are connected before you can power the board through the FTDI header.

alt text

You can apply the regulated power source directly to the VCC and GND pins, or you can solder some right-angle headers to the FTDI port and power with the appropriate FTDI Basic Breakout.

alt text

Right-angle headers soldered on to the FTDI Port

power with ftdi

If you intend on using the MP3 Trigger in conjunction with an Arduino or other microcontroller to communicate over the UART, you will do so through this port as well.

Why a 5V FTDI and not a 3.3V FTDI?

The MP3 Trigger has a 5V FTDI label despite it seeming logical that you could use a 3.3V FTDI as well. The reasoning behind this is that our current version of the 3.3V FTDI Basic uses the FTDI IC to regulate 5V down to 3.3V, and if you are using this device to power the MP3 Trigger, you may exceed the current limitation of the 3.3V FTDI, leading to a potential brown-out on your device. Thus, we recommend using a 5V FTDI Basic.

Note: SparkFun will be releasing a High-Current 3.3V FTDI Basic very soon. This page will be updated upon its release.

Trigger Pins

The Trigger pins are what make the MP3 Trigger so easy to use. Each of the 18 triggers is broken out to a 0.1" through-hole. Next to each trigger pin is a Ground pin. By shorting a trigger pin to ground, you are activating that trigger and thus playing the audio file associated with that particular trigger.

triggers

More information can be found in the Using the Trigger Inputs section.

1/8" Stereo Headphone Jack and Audio Solder Jumpers

The MP3 Trigger has a 1/8" (3.5mm) audio jack to connect your project to an amplifier and speakers or to headphones.

Audio Jack

Audio jumpers configured for Line out

You will only be able to have your MP3 Trigger configured to play audio as a line out or as headphones, but not both at the same time. By default, the MP3 Trigger comes configured to play over a line out to an external audio system. If you wish to use your MP3 Trigger with headphone instead, you’ll need to clear the solder from all three audio solder jumpers and solder the center pads to the opposite pads.

A solder jumper cheat sheet is conveniently printed in the silkscreen on the back of the MP3 Trigger to help you in altering the audio configuration.

jumper chart

Once configured for headphones, the jumpers should look like this:

alt text

Navigation Switch

The navigation switch allows you to cycle through and play/stop all the tracks located on your microSD card.

Nav Switch

More information on its operation can be found in the Basic Operation Section.

MicroSD Socket

The microSD socket is a simple push-to-insert/push-to-remove mechanism.

micro SD Socket

The MP3 Trigger supports both SDSC (up to 2GB) and SDHC (up to 32GB) type microSD cards.

More information on how the microSD card initializes can be found in the Basic Operation Section.

Basic Operation

Simply drag and drop the desired MP3 files into the root directory of a FAT32 or FAT16 formatted microSD flash card using a PC.

The MP3 Trigger does not support hot-swapping of the microSD Card. While this won’t damage anything, the microSD media is only initialized during power up. So whenever the card is changed or updated, be sure to power cycle the MP3 Trigger after installing the card.

When power is applied to the MP3 Trigger, the on-board (green) status LED indicates the state of the installed media as follows:

  • 1 long blink - No formatted microSD media found.
  • 1 long blink, followed by 1 short blink - microSD media found, no MP3 files located.
  • Constant short blinks - Hardware problem with MP3 Decoder.
  • 3 short blinks - microSD media found, at least 1 MP3 file located.

status LED

Status LED

As soon as the MP3 Trigger powers up with 3 short blinks, the on-board navigation switch can be used to play all of the tracks on the card, regardless of the filenames.

  • Left - Plays the previous MP3 file in the directory
  • Right -Plays the next MP3 file in the directory
  • Center - Starts/Stops the current MP3 file

Using the Trigger Inputs

The MP3 Trigger provides 18 input pins (TRIG01 –TRIG18) that can be used to trigger specific MP3 tracks on the microSD card. MP3 tracks are associated with triggers by placing a 3-digit number (using leading 0s) at the beginning of the filename; 001 for TRIG01, 002 for TRIG02 and so on. The rest of the filename can be anything. For example, the following are both valid names for TRIG14:

  • “014TRACK.MP3”
  • “014 Breaking Glass.mp3”

The trigger inputs are active low and pulled high internally. Therefore, they can be activated either by digital outputs from another microcontroller (such as an Arduino) or by a simple contact closure (switch) to ground. The inputs support voltage levels of either 5V or 3.3V.

The trigger inputs are made available on the even-numbered pins of a dual row connector, and all the opposing (odd-numbered) pins are ground, making it easy to wire individual switches or contact closures directly to the MP3 Trigger board.

Installing a 36-pin dual-row header allows shunt jumpers to be installed on the trigger inputs to automatically sequence and loop tracks on power-up as follows.

When a triggered track reaches the end, the MP3 Trigger looks to see if any trigger inputs are active, and will automatically start another track if so. If only the same trigger is active, then that track will restart (loop). If other triggers are active, the MP3 Trigger will always start the next higher trigger track, wrapping back to 1 after 18.

This, combined with the fact that the MP3 Trigger will automatically start the lowest numbered active trigger on power up, means that by installing shunt jumpers on the trigger inputs, the MP3 Trigger can be set to automatically sequence and loop from 1 to 18 tracks on power up with no externally programming or control required. (Beginning with firmware version 2.40, installing a shunt jumper on a single sequential trigger will do the same thing.)

For example, if you wanted track 9 to play on startup, you’d jumper trigger 9. If you wanted tracks 1 through 9 to play on startup, you have to have a jumper on all nine triggers.

Using the initialization file describe later in this document, triggers can be reprogrammed to start sequential or random tracks. For example, if a trigger is reprogrammed to be a random trigger, and that one trigger is shunted closed, then the MP3 Trigger will power up and continuously play tracks in a (pseudo) random order.

Quiet Mode

The MP3 Trigger can be placed into Quiet Mode using the serial control port. In this mode, the trigger inputs will not start tracks but instead will cause serial messages to be sent upon activation. (See “MP3 Trigger Outgoing Message Summary” below.) This allows the trigger inputs to be decoupled from specific tracks, so that a PC or microcontroller can monitor the trigger inputs and then start any track or sequence of tracks via the serial control port.

Quiet Mode is off by default and is not preserved through a power cycle

Serial Control Protocol

The MP3 Trigger comes with a full duplex 3.3-5V serial TTL interface that allows for control of all the MP3 tracks (up to 256) on the microSD card as well as volume, and for monitoring input trigger activity. You can use an FTDI Basic or connect to any serial interface that uses the format: 8-bits, 1-start, 1-stop, no parity, flow control = none. The serial port baud rate defaults to 38.4kbps, but can be changed using the initialization file. All commands to the MP3 Trigger are 1 or 2 bytes in length.

1-byte commands are upper case ASCII characters. 2-byte commands start with an ASCII character. Those starting with an upper case character use an ASCII value (‘0’–‘9’) as the second byte. (These commands can be typed on a keyboard.) 2-byte commands starting with a lower case character require a binary value (0 – 255) as the second byte.

Bytes sent to the MP3 Trigger are not echoed. If echoing is required, set your terminal program to echo locally.

Command Summery

Command: Navigation – Start/Stop
Number of bytes: 1
Command byte: ‘O’
Data byte: none
Comments: This command performs the same function as pushing the on-board nav switch center position. If the current track is playing, it stops. If the current track is stopped, it will restart from the beginning.

Command: Navigation – Forward
Number of bytes: 1
Command byte: ‘F’
Data byte: none
Comments: This command performs the same function as pushing the on-board nav switch right position. The next MP3 track in the directory will be started.

Command: Navigation – Reverse
Number of bytes: 1
Command byte: ‘R’
Data byte: none
Comments: This command performs the same function as pushing the on-board nav switch left position. The previous MP3 track in the directory will be started.

Command: Trigger (ASCII)
Number of bytes: 2
Command byte: ‘T’
Data byte: N = ASCII ‘1’ through ‘9’
Comments: If it exists, the track with the filename “00Nxxxx.MP3” will be started, where N is the data byte. xxxx can be any valid filename characters of any length.

Command: Trigger (binary)
Number of bytes: 2
Command byte: ‘t’
Data byte: n = 1 to 255
Comments: If it exists, the track with the filename “NNNxxxx.MP3” will be started, where NNN is the ASCII equivalent of the data byte 'n' with leading 0s. xxxx can be any valid filename characters of any length.

Command: Play (binary)
Number of bytes: 2
Command byte: ‘p’
Data byte: n = 0 to 255
Comments: If it exists, the nth track in the directory will be played. The total number of available tracks in the directory can be retrieved using Status Request command below.

Command: Set Volume (binary)
Number of bytes: 2
Command byte: ‘v’
Data byte: n = 0 to 255
Comments: The VS1053 volume will be set to the value n. Per the VS1053 datasheet, maximum volume is 0x00, and values much above 0x40 are too low to be audible.

Command: Status Request (ASCII)
Number of bytes: 2
Command byte: ‘S’
Data byte: N = ASCII ‘0’ through ‘1’
Comments: If N = ‘0’, the MP3 Trigger will respond with a version string. If N = ‘1’, the MP3 Trigger will respond with the total number of tracks on the installed microSD card, in ASCII. Both responses will be preceded by the ‘=’ character.

Command: Quiet Mode (ASCII)
Number of bytes: 2
Command byte: ‘Q’
Data byte: N = ASCII ‘0’ or ‘1’
Comments: If N=’1’, Quiet mode is turned on. If N=’0’, Quiet mode is turned off. Default state is off.

MP3 Trigger Outgoing Message Summary

The MP3 Trigger sends the following ASCII messages:

  • ‘X’: When the currently playing track finishes.
  • ‘x’: When the currently playing track is cancelled by a new command.
  • ‘E’: When a requested track doesn’t exist (error).

In response to a Status Request Command, data byte = ‘0’, the MP3 Trigger sends an 18-byte version string: e.g. “=MP3 Trigger v2.50”. In response to a Status Request Command, data byte = ‘1’, the MP3 Trigger sends the number of MP3 tracks on the currently installed microSD card: e.g. “=14”.

In Quiet Mode only, when one or more trigger inputs are activated, the MP3 Trigger sends ‘M’ followed by a 3-byte bit mask indicating which triggers were activated:

  • Data byte 0: TRIG01 through TRIG08
  • Data byte 1: TRIG09 through TRIG16
  • Data byte 2: TRIG17 and TRIG18

A value of 1 in a bit position indicates that the corresponding trigger input was activated.

Initialization File

Version 2.40 firmware (and above) supports the use of an initialization file to change some of the operation parameters of the MP3 Trigger upon power up. This file is ASCII text only, and can be created and edited with any text editor such as Notepad. The initialization file must be named “MP3TRIGR.INI” and must, like all the mp3 files, be in the root directory. The file is optional. If it does not exist, then the MP3 Trigger defaults to normal operation at 38.4K baud and all triggers starting their respective tracks. Initialization file commands must begin with the “#” character and be followed by a space. The initialization file example on the following two pages is self-documented and describes the commands currently supported:

Sample Initialization File

#BAUD 38400
#RAND 2
#TRIG 01, 0, 0
#TRIG 02, 0, 0
#TRIG 03, 0, 0
#TRIG 04, 0, 0
#TRIG 05, 0, 0
#TRIG 06, 0, 0
#TRIG 07, 0, 0
#TRIG 08, 0, 0
#TRIG 09, 0, 0
#TRIG 10, 0, 0
#TRIG 11, 0, 0
#TRIG 12, 0, 0
#TRIG 13, 0, 0
#TRIG 14, 0, 0
#TRIG 15, 0, 0
#TRIG 16, 0, 0
#TRIG 17, 0, 0
#TRIG 18, 0, 0
******************** ALL INIT COMMANDS ABOVE THIS LINE *********************
This is a sample init file for the MP3 Trigger v2, firmware version 2.40.

The init file is optional. If not present, the default parameters will be
in effect: 38.4Kbaud, and all triggers will start their corresponding
tracks with restart lockout disabled. If it is present, it must be named
MP3TRIGR.INI and be located in the root directory.

Only the first 512 bytes of the file are examined for commands, and the first
occurrence of the '*' character is treated as the end of file by the parser.
Comments are not allowed in the command section, but there is no restriction
on the length of the comments that follow the first '*'.

All commands must begin with the '#' character and be followed by a space,
then the command parameters separated by commas. White space is ignored. All
parameters are decimal numbers. Leading zeros are acceptable. See the above
examples - which are redundant since they are all default values.

The following commands are supported in firmware version 2.40:

#BAUD N

    where N is one of the following: 2400, 9600, 19200, 31250 or 38400

#RAND N

    where N is from 1 to 255

    The default behavior of the random trigger function is to play a random
    track from all the MP3 files on the flash card. The #RAND function will
    exclude the first N tracks (in the directory) from the random trigger
    function. So if there are 18 MP3 files on the card and N=4, then the
    first 4 MP3 files will be excluded from the random trigger function.

#TRIG N, F, L

    where: N is the trigger number (1-18)
    F is the trigger function type (see below)
    L is the restart lockout enable

    The defined trigger function types (F) are as follows:

    F = 0: Normal operation
    F = 1: Next (same as the forward Nav switch)
    F = 2: Random
    F = 3: Previous (same as the back Nav switch)
    F = 4: Start (restarts the current track)
    F = 5: Stop
    F = 6: Volume Up
    F = 7: Volume Down

    The restart lockout feature, if enabled, will prevent that trigger
    from working if audio is currently playing. Use this if you want
    to prevent restarts before the track has reached the end. This
    feature does not apply to function types 5-7.

    L = 0: Restart lockout disabled (default)
    L = 1: Restart lockout enabled

You only need to include entries for triggers that are to be non-default.
As an example, I use the following single-line init file to make trigger
18 be a "Next" function, then hard-wire the trigger so that my MP3 Trigger
powers up and loops continuously through all the tracks on the card.

#TRIG 18, 1, 0

Bootloader

The MP3 Trigger has a resident bootloader that allows updating the firmware directly from the microSD card, alleviating the need for a hardware programmer. Because this bootloader is in located in protected sectors of the PSoC’s flash memory, it cannot overwrite itself. The bootloader can always be run on power up, thus making it possible to recover from a bad firmware load.

IMPORTANT NOTE: Use of a hardware programmer, such as the Cypress MiniProg, to program the MP3 Trigger with anything other than the bootloader image will erase the bootloader. Don’t do it!

Using the Bootloader

To update the MP3 Trigger firmware, copy the new firmware hex file to a FAT16 or FAT32 formatted micro-SD card and rename the file to “MP3TRIGR.HEX”. It doesn’t matter if it’s the only file on the microSD card or not - the bootloader will find it as long as it has this exact filename. Insert the microSD card into the MP3 Trigger with the power off. Hold down the center nav switch while turning on the power. Wait for the status LED to go solid, then power cycle the MP3 Trigger to run the new firmware.

Bootloader Detailed Explanation

The bootloader is always entered whenever the board powers up. The first thing it does is look to see if the center nav switch is being held down. If not, it immediately vectors to the start of the firmware. Note that if you have previously loaded bad firmware, the board will simply halt or do whatever your bad code tells it to do – possibly with no activity other than the power LED. This is normal if there’s no good firmware loaded.

If the center nav switch is being held on power up, the bootloader searches the microSD card directory for a file named “MP3TRIGR.HEX”. If there’s no card installed, or the file doesn’t exist on the card, it will blink the status LED very rapidly forever. If it finds and is able to open the file, it begins to program the PSoC Flash with the contents of the firmware file. The status LED will illuminate for each hex record programmed. If it successfully programs the entire file, the status LED will turn solid upon completion. You can then power cycle the MP3 Trigger and you will be running the new firmware (don’t hold the nav switch down again or you will simply re-enter the bootloader.

If there’s a flash memory programming error (or you pull the microSD card out before it finishes, for example) the status LED will indicate a bad programming cycle by blinking briefly at about 1 Hz (This looks very different than the blinking for programming records). You need to cycle the power again holding the nav switch to re-enter the bootloader.

The key is that the bootloader cannot over-write any p art of itself, no matter what’s in the firmware image file. The worst thing that can happen is you load bad firmware and the board won’t run. But you can always hold the nav switch down on power up and get into the bootloader to load new firmware.

Resources and Going Further

Thanks for reading! Here are some additional resource and tutorials for you to explore.

My Drunk Kitchen Apron

A fun project that uses the LilyPad MP3 trigger. This apron will dispense helpful kitchen advice and humor from the host of My Drunk Kitchen, Hannah Harto!

SparkPunk Sequencer Theory and Applications Guide

Examine the inner workings of the SparkPunk Sequencer, then explore some modifications and alternate applications.

Bare Conductive Musical Painting

Learn how to make a musical painting using the Bare Conductive Touch Board and Conductive Paint.
New!

MP3 Trigger Hookup Guide V24

Incorporate sound into your next project easily with the MP3 Trigger.

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

Electronic E-craft Terrarium

$
0
0

Electronic E-craft Terrarium a learn.sparkfun.com tutorial

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

Introduction

Introduction

People put plants (both plastic and real) in terrariums to create small, concentrated natural environments. What makes these terrariums interesting to me is that the glass enclosure isolates the ordinary objects from the real world and frames the objects for people to take a closer look. For this project, I included electronic components into a terrarium for people to appreciate the aesthetic aspects of technology. Also, I also wanted to express that technology is alive in another way.

In this tutorial, I will be creating an interactive, electronic terrarium. When the edge of the terrarium is touched, the lights start to breathe, and a leaf appears in the sand. To see the terrarium in action, check out the video below.

Electronic Terrarium from Kehui Liu on Vimeo.

Materials Required

You will need the following materials to follow along with this project.

You will need one of the following to program the ATtiny.

SparkFun RedBoard - Programmed with Arduino

DEV-12757
$19.95
76
Tiny AVR Programmer

PGM-11801
$19.95
34

Additionally, you will need the following materials:

Suggested Reading

If you aren’t familiar with the following concepts, we recommend reading over them before proceeding.

Arduino Code

Before we begin building this project, we need to first program the ATtiny, because we will be soldering directly to its legs, making it much more difficult to reprogram afterwards. If you would like to not solder directly to your ATtiny so as to be able to reprogram it or to reuse it in a later project, you can use a DIP Socket as well, soldering all the parts to it and then inserting the ATtiny into it.

Program the code onto the ATtiny using the Arduino or ISP Programmer shown above. If you have never programmed an ATtiny using the Arduino IDE before, have a look at this tutorial about how to work with ATtiny. Alternatively, if you are using the TinyAVR Programmer, take a look at this tutorial.

You will also need to add the Capacitive Sensor library to your Arduino IDE in order to compile the sketch. This can be added using the Library Manger.

Capacitive Sensor Library

Load the following sketch onto the ATtiny. You can use the Codebender plugin below. Be sure to select the correct ATtiny board from the drop down menu.

If you would prefer to use the Arduino IDE, you can copy and paste the code from below.

language:c

/*Electronic Terrarium
Code by Kehui Liu
December 2015
From the Performative Sculpture class of Parsons DT
Project tutorial available here: https://learn.sparkfun.com/tutorials/electronic-terrarium
Released under the MIT License (https://opensource.org/licenses/MIT)
*/

#include <CapacitiveSensor.h>

CapacitiveSensor cs_3_4=CapacitiveSensor(3, 4);
int heat = 0;
int led = 1;
long total;
void setup(){
    cs_3_4.set_CS_AutocaL_Millis(0xFFFFFFFF);
    pinMode(heat, OUTPUT);
    pinMode(led, OUTPUT);
}

void loop(){
    long start = millis();
    total = cs_3_4.capacitiveSensor(30);
    if(total>200){
        digitalWrite(heat, 255);
        for(int i = 0; i<255;i++){
        delay(10);
        }
        for(int i = 0; i<255;i++){
            analogWrite(led,255-i);
            delay(10);
        }
    }else{
        analogWrite(led,255);
        digitalWrite(heat, 0);
    }
    delay(300);
}

Assembly

Dye the Sand

Sand Coloring Materials

Mix thermochromic pigment with regular paint. Add the mixture to the sand and let dry. The color of thermochromic dye will fade when heated.

Coated Sand

Thermochromatically covered sand.

Mixing and matching paints and thermochromatic pigment will result in different colors of the sand in a neutral state. Remember that the color will fade the base paint color when heated.

Sew the Flexinol

Draw a shape of your choice on a piece of fabric that you’d like to display once heated. Sew the Flexinol onto the fabric. Seal the two end with crimp beads.

Flexinol leaf

To test the result, cover the shape in a small amount of sand. Using a 9v battery, hook one end of the Flexinol to the positive (+) terminal and the other end to the negative (-) terminal. You should see the sand change color on top of the Flexinol shape.

Tape the Vase

Use copper tape to outline your desired touching point. You will also need a spot on the copper tape to solder to your ATtiny.

Vase with copper tape

Solder Everything Together

Connect your circuit together. Use the image below as a guide.

Connected Circuit

Please note that pin 1 of the ATtiny is the upper-left pin in the image.

Put Everything Into the Vase

Arrange the parts as you like. Gluing some components to the side of the enclosure may be necessary. Last, add the sand, and leave a thin layer on the heating part.

Parts in Vase

Connect the Batteries and Done!

Insert the CR2032 battery into the holder. Make sure the positive (+) side of the battery is facing out.

CR2032 Battery Inserted

Finally, connect your 9V battery to the system.

9V Battery Inserted

Now, when the edge is touched, you should see the image light up in the sand!

Resources and Going Further

You should now have a functioning Electronic Terrarium! If you have any feedback, please visit the comments or contact our technical support team at TechSupport@sparkfun.com.

For additional inspiration, take a look at the following projects tutorials.

Let It Glow Holiday Cards

Craft a glowing card for friends and family this holiday season with paper circuits - no soldering required!

Humidity-sensing LED Flower

How about that humidity? This tutorial shows how to add sensing capability to the 21st Century Fashion Kit's RGB flower project.

21st Century Fashion Kit: Electrochromatic Circuits

Diana Eng walks you through a magically appearing design made with an thermochromatic pigment.

LED Robot Pop Up Card

Craft a paper circuit pop up card with a cycling RGB LED, battery, and copper tape.

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

RedStick Hookup Guide

$
0
0

RedStick Hookup Guide a learn.sparkfun.com tutorial

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

Introduction

alt text

The RedStick

The SparkFun RedStick is a production version of the BadgerStick, which made an appearance at a trade show near you in the BadgerHack Badge. This version carries an NCP1402 boost regulator (as seen in the SparkFun 5.0v Step-Up Breakout Board, so it can run at 16MHz from a 6V down to a 2V input!

The RedStick operates as an Arduino Uno in the Arduino IDE!

Covered in This Tutorial

Suggested Reading

  • RedBoard Hookup Guide– The RedBoard and RedStick have many similarities. Learn the ins-and-outs of getting either up and running in the Arduino IDE in this tutorial.
  • BadgerHack– The original BadgerStick (promo) documentation.
  • Charlieplexed 8x7 LED Array Github– If you would like more information on how the 8x7 LED array is programmed, check out the code files.

Hardware Overview

The following lists the features of the RedStick:

  • A boost regulator providing 5V to the Atmega328p from an input range of 2 to 6 volts.
  • 16 MHz system clock (allowed because of the additional supply voltage)
  • Uno compatible in the Arduino IDE. Simply select the board “Arduino/Genuino Uno” and go!
  • USB end matches standard USB thickness and width.

What the RedStick is not:

  • A RedBoard – it doesn’t provide 3.3 volts, only 5.
  • A battery charger – The RedStick turns off the battery when plugged into a USB port.

alt text

Parts of the RedStick


The following table lists all of the pins on the RedStick and their functionality.

Pin Silk
FunctionNotes
TXSerial transmit
This is serial data coming out of the RedStick.
RXSerial Receive
This is serial data coming in
2Digital
~3Digital with PWM
4Digital
~5Digital with PWM
~6Digital with PWM
7Digital
8
Digital
9Digital
~10Digital / PWM / SS
~11
Digital / PWM / MOSI
SPI bus
12PWM / MISO
SPI bus
13Digital / SCK / LED
SPI bus
A0Digital / Analog
A1Digital / Analog
A2Digital / Analog
A3
Digital / Analog
A4
Digital / Analog / SDA
I2C bus -- some applications require pull-up
A5
Digital / Analog / SCL
I2C bus-- some applications require pull-up
A6Analog
Analog only!
A7AnalogAnalog only!
RXI
Serial Receive
Electrically tied to RX
TXISerial Transmit
Electrically tied to TX
VCC
Microprocessor Power (Boost output)
If using as input, supply regulated 5.0 v
GNDGround
+Battery Positive
Supply 2.0 to 6.0 volts
-Battery Negative
This is also GND

Powering the RedStick

The RedStick was designed to allow two sources of power.

  • Power directly from the USB port.
  • Power with 2-6 volts on the battery terminals.

alt text

A block diagram showing how the power flows in this board

Functional Description

When power is applied to the USB port, it will not flow into the battery. Alternately, if the USB voltage is lower than the battery, power will not flow into the USB host.

To use AA cells, for example in a battery holder such as a 2xAA Holder with switch, solder the wires directly into the battery terminal holes, matching red to positive.

To use a rechargeable battery, such as a 1 Ah Lithium Ion battery, solder a JST connector into the smaller, 2mm spaced holes and attach the battery. Again match red with positive.

Note on VCC: It's conceivable that power might be applied to the VCC pin instead. This is OK as long as the input voltage is regulated while the USB and battery inputs are left open.

Notes on DC-DC converters

The RedStick uses a boost circuit to convert a low voltage ( > 2.0 volts DC ) to 5 volts DC. This DC-DC conversion is fairly common in today’s world where a liner regulator is not efficient enough. This boost circuit measured around 83% efficient.

Here’s a couple concepts to think about related to DC-DC converters

DC-DC converters and power

Ideally, DC-DC converters would be 100% efficient. In the math model, this means that power out = power in. So, if the converter is delivering 200mA at 5V, by the definition of electrical power, that’s 1W (P = V * I). If we’re consuming 1W from the output, we must be supplying 1W to the input. If the input is a battery at 3V, supplying 1W, it must be supplying 330mA. That’s more than we’re getting out!

As the input voltage to a DC-DC converter drops, the current consumption increases to maintain the output load.

This also applies to LED and CCFL bulbs that aren’t dimmer compatible. As the dimmer decreases the voltage, the current increases and fries the dimmer circuit because it was designed for resistive loads (incandescents) that behave as Ohm’s law indicates.

Drawbacks of DC-DC converters

The appeal of DC-DC converters is the low cost of the completed circuit. This is because inductors are used in place of transformers. The inductors operate at a high frequency so that the size can be made small, which makes them cheap. The control circuitry is a logic system that chooses when, and how fast, to operate the inductor in order to build up the necessary voltage on the output. This switching frequency can be seen as ripple on the output side of the DC-DC converter, depending on the loading of the circuit.

This DC-DC converter produces between 30 and 170 mV ripple in the 5kHz to 250kHz range, with optimal performance between 2.5-4.5 volts (typical battery voltages).

The RedStick comes with the blink sketch loaded and running, so the LED (pin 13) will toggle every second. This section shows how to get back to this basic sketch using codebender and by using the Arduino IDE.

alt text

The RedStick running the blink application to insure basic function. In this photo, the RedStick is being powered from two AA cells.

Using codebender

With codebender, you’ll have to install the small browser Arduino plugin, if you have not done so already. Without a codebender account you can modify and run from this webpage, but you won’t be able to save or share without making a free account.

Select Arduino Uno for device and the RedStick’s COM port number. You can edit this code (try reducing the delay time in the loop() to 500) and click “Run on Arduino” to make sure everything is working. The codebender browser must be installed.

Using the Arduino IDE

To re-load the sketch, select the Arduino/Genuino Uno board from the menu, select the basic example blink, and press upload.

alt text

Selecting the Arduino Uno board. Don’t forget to select your com port too if it wasn’t auto-selected

alt text

Select the blink.ino sketch from the basic examples menu

Now compile and run! That’s all there is to it!

Example: Using the 8x7 LED Array

If you would like to use an 8x7 LED array with the RedStick as with the BadgerStick, you can! The libraries have been updated to use F_CPU to set scroll speeds for 4, 8, and 16MHz boards.

Using a promo 8x7: The original promo 8x7 LED array was designed for 3.3v operation but the RedStick operates at 5. Appling a 8x7 from a show (has badger logo on back) will have increased brightness and current consumption. For proper compatibility remove the 8 SMD resistors and replace with 82 ohms each, though it'll probably be ok if you choose not to alter it. SparkFUn will be releasing a 5V compatible version of the LED array in the near future.

Install the Arduino library

The 8x7 LED array has its own library. It is available as a github repository called SparkFun_LED_Array_8x7_Arduino_Library. It is not part of the library manager and will need to be manually installed (Drop it in your /libraries folder).

For more information, view this guide to installing Arduino libraries

Run the example sketch

Under examples, select the 8x7 library, then the example sketch “ScrollText”. This sketch displays scrolling text on the 8x7 LED array, but the library can also be used to draw individual pixels, shapes, and bitmaps.

alt text

Selecting the example sketch

Compile and run the sketch. The example text Hello. :) and Let's scroll! should scroll across the array. From this point the text can be changed, or the other features of the library can be used. Check out the BadgerHack ‘Make a Game’ section for example code that uses the 8x7 API.

alt text

The RedStick driving a modified 8x7 LED array (promo item). Here, it scrolls “:)” as part of the example

Example: Adding a Second Voltage Rail

Not all projects are LEDs and digital logic. If you want to add devices that operate at voltages other than 5.0 volts, a low-dropout regulator (LDO) can be added to solve the problem. Here, I’ve used basic components to attach a BME280 atmospheric sensor to my RedStick. Of course, you could use a breadboard power supply stick. I didn’t want the barrel jack and extra space used up, so I used discrete components.

This inexpensive wishlist gets you the regulator, plenty of caps, and plenty of proto board to get going.

Build the LDO circuit

Build the following circuit. Remember to mind polarity on the electrolytic capacitor, that the pin ordering is kind of counter-intuitive, and that the TO-220’s tab is connected to the pin 2 and not ground.

alt text

Connect the LDO circuit

To connect the LDO circuit to the RedStick,

  • connect “GND” to a spare GND pin
  • connect “Input” to VCC.

Now the “Output” is a regulated rail! In this case, 3.3 volts.

For this example, a BME280 is used. The BME280’s ground is connected to the common GND pin while 3.3V is connected to the LDO’s Output terminal. I2C serial lines are directly connected to the RedStick’s A4 (SDA) and A5 (SCL) pins. The BME280’s circuit board pulls these lines safely up to 3.3V.

Run the example

Run the BME280’s example sketches. For information on use of the BME280, see the hookup guide.

alt text

alt text

The final product. This USB stick / BME280 combo is great for determining the local weather conditions, altough it’s usually about 2 degrees Celsius hotter around my computer than in the center of a room

Resources and Going Further

Here’s a recap of the useful links from the guide and some extras that have information not covered. Remember, if you get stuck on a problem take a step back and list off what you do know, and have fun!

Resources used in this guide

Additional information and related topics




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

Simblee Breakout Board Hookup Guide

$
0
0

Simblee Breakout Board Hookup Guide a learn.sparkfun.com tutorial

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

Introduction

The SparkFun Simblee Breakout Board is a programmable board that allows you to add mobile app functionality via Bluetooth Low Energy (BLE, or Bluetooth 4.0) to your embedded projects. Unlike other BLE solutions, the Simblee requires no specialized app development skills to realize the phone-side interface; all the necessary coding is done in the Arduino environment and then uploaded to a browser app on the phone.

alt text

If you want to skip directly to writing code, we have another tutorial covering coding concepts that are common to all Simblee products. If you’re looking for a sewable solution, checkout out our Simblee LilyPad Board.

Recommended Reading

There are a few topics you may want to be sure you understand before you go any further.

  • Bluetooth Basics - While Bluetooth 4.0 is quite different to previous versions of Bluetooth, our Basics tutorial will give you some insight into the methods and goals of Bluetooth in general.
  • Serial Communication - You’ll want to make sure you understand serial communication, as that will be a major means of debugging your Simblee sketch during development.
  • Logic Levels - The Simblee runs at 3.3V. Make sure you understand the difference between 3.3V and 5V logic levels before you start connecting things to the Simblee or you may damage it!

Simblee Hardware Overview

There are two really important facts in this tutorial, highlighted here:

We recommend using the either the LilyPad FTDI Basic or the 5V FTDI Basic for programming the Simblee LilyPad. Do not use the 3.3V FTDI Basic, as it may not be able to source enough current from the 3.3V rail.
If you've used Arduino boards before, you're probably used to connecting LEDs to the pins as output signals. A normal Arduino can light up many LEDs at once, and several per pin; for the Simblee, you shouldn't try more than ONE per pin, with an additional recommendation of don't try to turn on more than three at a time across all pins. The processor inside the Simblee module cannot drive enough current to light up more LEDs than this.

Here’s a rundown of the features you’ll find on the Simblee breakout board:

Labeled board

  • RFDuino compatible pin section– The top section is compatible with the RFDuino shields and programmers.
  • User LED– We’ve provided a user controllable LED on pin D2. This allows you to get some feedback without any additional hardware at all.
  • User button– Similarly, we’ve provided a button on pin D3. Don’t forget to use INPUT_PULLUP when setting the mode for that pin in the code!
  • Programming header– While you can use the RFduino programmer, we’ve provided a standard 6-pin FTDI breakout programming header as well. This allows the profile of the board to remain low unless necessary. We recommend using the either the LilyPad FTDI Basic or the 5V FTDI Basic for programming the Simblee LilyPad. Do not use the 3.3V FTDI Basic.

Resources and Going Further

That concludes the Hardware overview for the Simblee Breakout. For more information on using the Simblee to create your own applications for embedded project, visit our Simblee Concepts tutorial.

New!

Simblee Concepts

February 4, 2016

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!

For more info on the Simblee module itself, please have a look at the Simblee User’s Manual.

Here are a few more resources for the Simblee:

For more Bluetooth fun, check out these other SparkFun tutorials.

Bluetooth Basics

An overview of the Bluetooth wireless technology.

Using the BlueSMiRF

How to get started using the BlueSMiRF and Bluetooth Mate Silvers.

Understanding the BC127 Bluetooth Module

SparkFun has two boards using the BC127; here's what you need to know to use them.

Interactive Hanging LED Array

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

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

Simblee Concepts

$
0
0

Simblee Concepts a learn.sparkfun.com tutorial

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

Introduction

Simblee LilyPad and Simblee breakout board

The Simblee module by RFDigital is intended to make embedded devices using Bluetooth Low Energy connections easier for everyone: hardware hackers, app developers, students, makers, engineers, and anyone else who wants to leverage their smartphone via BLE.

Historically, using a smartphone with an embedded project has meant learning to develop applications for smartphones, a daunting requirement. RFDigital has made this easier by moving the application development into the Arduino environment. When you write your sketch defining the behavior of the embedded portion of the Simblee, you’ll also add a couple of functions below the old familiar setup() and loop() calls that tell the Simblee app running on your mobile device what the custom front end for this particular situation should look like.

SparkFun has made two boards using the Simblee: a LilyPad board for sewable applications and a standard breakout board for general use. We also sell the official RFduino Simblee breakout, the RFduino Simblee starter kit, and a number of RFDuino shield products which are compatible with both the official Simblee breakout and our breakout.

This tutorial will introduce you to some of the generic principles involved in developing a project with the Simblee module.

Required Materials

  • Buttons– We’ll be wanting to send signals into the application from hardware, so you’ll definitely want buttons. This assortment is nice because it’s breadboard compatible and the buttons have a nice, big, color-coded surface.
  • LEDs– We’ll also be sending signals out to the outside world, and if you can light an LED, you can use that signal to do anything. This assortment includes several types of LED, including the common cathode RGB LED we’ll be using later, as well as the resistors you’ll need to limit the drive current.
  • Jumper Wires– Of course, you’ll need some jumper wires to hook everything up.
  • Breadboard– And, a breadboard. I suggest this one, since its length will make it easier to insert a Simblee board as well as build a circuit with which to interface.
  • Header pins– If you’ve bought a Sparkfun Simblee Breakout board, you’ll need to add some header pins so you can insert it into your breadboard.
  • Alligator clips– If you’re using a LilyPad Simblee Board, alligator clips are the way to attach them to the circuit you’re building up on the breadboard.

Suggested Reading

Obviously, we’re going to have to make some assumptions about prior knowledge during these lessons. If you aren’t sure you’re comfortable with any of the topics below, here’s your chance to review them before continuing on with the tutorial.

  • LEDs– Obviously, you’ll want to understand how LEDs work, since we’ll be using LED as a stand-in for other devices during our tutorials.
  • Resistors– This segment of our resistor tutorial has good coverage on using an LED to limit the current through an LED. This is more important for the Simblee than for most other boards, as the drive current capability out of the Simblee pins is lower than on most similar development boards.
  • Breadboards– We’re going to assume you’re building your circuit up on a breadboard. That’s the easiest way to do it.
  • Soldering– If you bought a Simblee Breakout Board, you’re going to have to solder some pins to it to use it in a breadboard. In addition to the general soldering tips in our main soldering tutorial, our Pi Wedge B+ Hookup Guide has some really great tips on soldering pins to a breakout board.
  • Logic levels– The Simblee board uses 3.3V signals, rather than 5V, and it’s important that you understand the distinction to avoid damaging your Simblee.

General Hardware Information

While the Simblee is, in most respects, very similar to any other Arduino-compatible breakout boards you may have used, there are a few considerations that apply specifically to Simblee-based boards that you should be aware of.

Reduced LED drive strength

This is the big one. A normal Arduino (an Uno R3, say, or a Sparkfun RedBoard) can output up to 20mA into an LED, from more than one pin at a time. Simblee based boards, however, can only drive 15mA total, across all pins. This means you may have to use larger current limiting resistors (something like a 1k-ohm resistor is appropriate) for LEDs with a low forward voltage (like red, yellow, or orange). Attempting to drive too many LEDs at too high a current may damage your Simblee board.

3.3V drive voltage

This has become more common in recent years, but the prevalence of 5V Arduino and Arduino compatible boards still makes it worth mentioning. If you’re not sure of what this means, please refer to our logic level tutorial for more information.

For the LilyPad Simblee and SparkFun Simblee Breakout, we’ve provided some onboard protection circuitry that will allow you to use the 5V FTDI Basic programming adapter (or the LilyPad version) to program them. We recommend against using the 3.3V FTDI Basic (so much that I’m not even going to link to it), as it lacks sufficient supply current to run a Simblee module at programming power levels. Both Simblee boards have onboard power regulation circuitry to convert the 5V power to the 3.3V that the Simblee needs, which brings us to…

Powering your Simblee board

As mentioned above, both Sparkfun Simblee boards have an onboard power regulator to provide the 3.3V regulated power the modules want. A single-cell LiPo battery (such as this one) makes an excellent power supply for Simblee projects; in fact, the LilyPad Simblee not only has a 2mm JST connector specifically to attach to our batteries, it also has an onboard charge circuit!

Of course, as a Bluetooth Low Energy device, we expect the Simblee to have extremely long battery life. This is, however, heavily contingent on the rest of your design. If you are constantly driving LEDs, for instance, or powering an accelerometer or other sensor, you’ll find that the low-power nature of the Simblee module won’t help you much at all. Also, you’ll need to place the Simblee module into a low power mode much of the time to realize the benefits of the BLE power consumption features. More on this later, in the examples section.

Setting Up Arduino

Adding support for the Simblee to your Arduino IDE

In the bad old days, adding support for a new architecture to the Arduino IDE meant downloading files from some random website, extracting them into some random folder, and then copying them into some obscure location on your hard drive. Those days are behind us!

Introduced in version 1.6.0 of the Arduino.cc version of the IDE, the Boards Manager allows you to download support for a new device from within the IDE itself. The good people behind the Simblee have provided a link which allows you to directly add the Simblee supporting files and tools from the Boards Manager.

Add the download address to your preferences window

Preferences window + popup

As you can see in the picture above, there’s a text field at the bottom of the preferences window for the Arduino IDE (which can be accessed from the “File” menu), labeled “Additional Board Manager URLs”. Click the little box next to the field, and paste the appropriate link from below into the first open line in the text box that opens:

https://www.simblee.com/package_simblee_index.json (for Arduino 1.6.5)
https://www.simblee.com/package_simblee166_index.json (for Arduino 1.6.7)

Click the “OK” button, then “OK” in the “Preferences” window. This adds the address of the resource to the IDE, so you can access it from within the Boards Manager. We recommend against using Arduino 1.6.6, as there have been issues observed during development.

Open the Boards Manager and download the support package

Where the boards manager is

Next, open the Boards Manager. It can be found under the “Tools” menu, at the head of the board selection submenu. Selecting it will bring up a window that looks like this:

Boards manager

Type “Simblee” into the search window, and hit enter. A description of the Simblee support package should appear in the scroll window. If the package description doesn’t appear, try restarting your IDE.

Click anywhere in that description field to select it, and a button labeled “Install” should appear. Click it, and wait for the bar across the bottom to fill in.

Once the download is complete, restart the IDE, and you should see the Simblee in your board selection menu.

Boards menu, with Simblee!

Testing the installation

Regardless of the board you’ve purchased, you’re going to select the same thing from the boards menu: “Simblee”. The module at the heart is the same, as is the upload process.

You’ll also want to select the appropriate COM port for your board; I’m going to assume you know how to figure that out but if you need help, you can check out our “Installing the Arduino IDE” tutorial.

At this point, you should have a blank sketch open, with nothing but setup() and loop() functions.

Hit the “Upload” button, and wait. After a few moments, you should see the uploading progress message in the bottom frame of the IDE window:

Upload successful

If that happens, congratulations! You’ve got the IDE properly upgraded to support Simblee.

If it fails, try restarting the IDE, check and make sure you have the right COM port selected (again, check the Installing the Arduino IDE tutorial for help), or reinstall the support package through the boards manager.

Installing the App

At this time (early Feb 2016), the Simblee app is only available for iOS. RFDigital expect to have an Android version available sometime in the first quarter of 2016. We’ll update our site when that happens.

To interact with the Simblee module from a mobile device, you’ll need to install the Simblee for Mobile app. This free download is available for iOS only, through the Apple App Store.

Simblee for Mobile Download page

The Simblee for Mobile app must be downloaded from the Apple App Store. Simply open the App Store and search for “Simblee for Mobile”, and the download page should come up automatically.

Once the install has finished, you’ll find the Simblee for Mobile app on one of your home screens.

Simblee for Mobile Icon

Opening the app will show a screen like this, where you’ll see a list of all the active Simblee devices in the area.

Simblee for Mobile app

You can then connect to the active devices by simply touching the name in the list.

General Coding Concepts

Since the Simblee introduces a new concept (a synchronized but self-contained application running on a remote device), there are a few new concepts in the way code is written for the Simblee that we should go over before we dive into the examples.

New Functions

First and foremost, you’ll notice that any sketch which uses the Simblee UI library (called “SimbleeForMobile”, hereafter abbreviated SFM) has at least two additional functions: ui() and ui_event(). Let’s explore what these are for.

ui() is basically the SFM equivalent of the setup() function. It creates the default objects that the user will see when connecting the Simblee app to a particular Simblee device and how those objects will behave. It gets called on connection to a new device (maybe– we’ll cover the circumstances under which a device can cache the interface later).

ui_event() is a callback function which gets triggered when the user “does something” in the UI. We’ll get into the specifics of what that “something” may be later, but broadly, it’s just what you’d expect: interacts with a button, moves a slider, enters a text value, etc.

SimbleeForMobile.process()

This one is simple, if extremely important. During each iteration of loop(), you need to call this function to handle processing of events from the UI. It’s important to note that, since this function is getting called during loop(), excessive busy-wait delays (like the delay() function) will impact the responsiveness of your application more than anything else will.

Here’s a blank SimbleeForMobile sketch, showing all the new features in place.

Blank SimbleeForMobile sketch

Power Management

As mentioned earlier, while the Simblee is a Bluetooth Low Energy device, there is nothing inherently low energy about it while it’s operating normally. In fact, it may be consuming more power than a regular Arduino! In order to realize the benefits of BLE, you must learn to manage the power state of the processor.

Broadly speaking, this means that you’ll want to put the device in low power mode for as much of the time as possible, waking up only when necessary and then powering down again immediately. This “sleep as much as possible protocol” brings us to the next point: host/client synchronization.

We’ll cover this in an example later; for now, I want to point it out to avoid that concept slipping through the cracks.

Host/client synchronization

One of the key problems with BLE is keeping client devices synchronized with their hosts. For a BLE device to minimize power use, it must sleep a lot of the time; this means not necessarily being available to hear a communications request from the host when it is sent. To work around this limitation, the host and client agree on a “wake-up interval”, during which the client will listen for the host and the host will attempt to contact the client. In a bidirectional system, there’s room for a lot of slop; they can repeat messages as often as needed until an acknowledgement is received.

However, some BLE devices are made to be very low power, running on batteries for months at a time or more. One of the ways this is possible is by waking up only long enough to squirt a tiny data packet out into the ether, and then going immediately back to sleep. Host devices must, therefore, be listening during these times, or they’ll miss the packet.

As we’ll see later, it’s possible to set the time gap between these data transmissions to very short times (20ms) to very long times (days). As you might imagine, this means that BLE modules must have very accurate internal real time clocks. This can be used to our advantage for other reasons, as well.

Library Reference

This page is intended to provide a reference to the various commands that are provided in the Simblee libraries. While we will try to provide examples of as many of these as possible, this list will give a strict explanation of each function.

There are ten Simblee-specific libraries: SimbleeAESCOM, SimbleeCloud, SimbleeForMobile, SimbleeGZLL, SimbleeRNG, SimbleeAES, SimbleeBLE, SimbleeCOM, SimbleeForMobileClient, and SimbleeNonBLE. In addition, there are Simblee-compatible versions of three “standard” Arduino libraries: SPI, Servo, and Wire. We won’t cover all of these; there just isn’t time. We’re going to focus on SimbleeForMobile, SimbleeForMobileClient, SimbleeBLE, and SimbleeNonBLE, as these are probably the most widely applicable.

SimbleeNonBLE

Strictly speaking, SimbleeNonBLE isn’t really a library; it’s created as a library folder to provide example code for Simblee devices that isn’t specific to using the Simblee as a BLE device. Thus, there’s no need to include “SimbleeNonBLE.h” in any of your code files (indeed, the file is empty). However, there are some functions that are likely to be useful that can be found in the examples folder in this “library”.

If anything is different to what you’d normally expect on a “standard” Arduino board, we’ll mention it here.

  • analogRead(uint32_t ulPin)– Returns a uint32_t (range 0-1023) representing the analog voltage on pin ulPin. The Simblee supports analogRead() on pins 1-6 only.

  • analogWrite(uint32_t ulPin, uint32_t ulValue)– Provides a PWM output on pin ulPin of duty cycle ulValue/255. Unlike most Arduino boards, any pin can be used for analogWrite(), but only up to four at one time.

  • getDeviceId()– Returns a uint64_t which is unique to this particular Simblee module. The upper and lower uint32_t values comprising this value can be individually accessed via getDeviceIdLow() and getDeviceIdHigh().

  • Simblee_pinWake(uint32_t ulPin, uint32_t dwWake)– Choose a pin to wake the device from sleep. dwWake can be either HIGH, LOW, or DISABLED.

  • Simblee_pinWakeCallback(uint32_t ulPin, uint32_t dWake, pin_wake_t callback)– The first two parameters are the same as for Simblee_pinWake(); the third is the name of a function returning type int and receiving one argument, uint32_t pinName. This code will be called upon a pin-based wake up from sleep mode.

  • Simblee_pinWoke(uint32_t ulPin)– Returns true if the recent wakeup was caused by the pin number passed in.

  • Simblee_resetPinWake(uint32_t ulPin)– Resets the status of that pin’s wakeup register. Must be called before returning to low power mode!

  • Simblee_ULPDelay(uint64_t ms)– Put the Simblee device into “ultra low-power” mode for ms milliseconds. Macros exist to define the parameter as MILLISECONDS(x), SECONDS(x), MINUTES(x), HOURS(x), or DAYS(x); if you pass the parameter INFINITE the Simblee won’t wake up until a predefined pin event occurs. In this mode, the Simblee consumes about 500uA of current. If no callback function is specified and the waking event was a pin input, execution resumes on the line after the Simblee_ULPDelay() function was called. If a callback function exists, all input wakeups will vector to that code rather than executing the code following the Simblee_ULPDelay() call.

  • Simblee_systemOff()– Put the system into double secret low power mode. In this mode, waking up will take longer and can’t be done on a timed basis; however, the power consumption is even further reduced over ultra low power mode, to around 1uA. On power up, execution begins with the callback function specified using the Simblee_pinWakeCallback() function; if you haven’t set a callback function, execution is immediately suspended back into low power mode.

  • Simblee_systemReset()– Software system reset call. Begins execution at the beginning of the sketch; this will cause the Simblee to drop any active connections.

SimbleeForMobile

The SimbleeForMobile library implements the functions necessary to draw objects in the Simblee for Mobile app. This code is resident on the Simblee module and is uploaded when the module connects to the mobile device; it can be cached on the device to reduce load times for future connections.

Common Functions

These four functions must be in every SimbleeForMobile sketch for it to work. The first two must be called and the second two must be defined.

  • SimbleeForMobile.begin()– Perform initial setup for the library. Typically, this is called at the end of the setup() function.

  • SimbleeForMobile.process()– Must be called once per loop to handle all the background processes necessary to the interaction between Simblee and host. Typically, the call to this function is the last thing done in the loop() function.

These two functions must be defined in your sketch for it to work; add them to the sketch below setup() and loop().

  • void ui()– Defines the UI on the host device.

  • void ui_event(event_t &event)– Called when an event occurs on the host device. The event_t object contains information about what particular type of event occurred; more on this in a later section.

Configuration Variables

Some of these variables are identical to the ones in the SimbleeBLE library; indeed, SimbleeForMobile is built on top of SimbleeBLE. Do not attempt to use both SimbleeBLE and SimbleeForMobile in the same sketch, however.

All of these configuration variables must be set before callingSimbleeForMobile.begin()

  • SimbleeForMobile.deviceName– Name displayed in the Simblee app. This string’s length plus the length of the SimbleeForMobile.advertisementData string must be less than 16 characters long.

  • SimbleeForMobile.advertisementData– Data displayed in the Simblee app. This string’s length plus the length of the SimbleeForMobile.deviceName string must be less than 16 characters long.

  • SimbleeForMobile.txPowerLevelint between -20 and +4 representing transmit power, in dBm. Default is +4; only values which a multiples of 4 are allowed.

  • SimbleeBLE.advertisementIntervalint variable declaring, in ms, the frequency with which to issue advertisement packets. Range from 20ms to 10.24s; the actual range units are in units of 0.625ms, so the actual interval will only be an approximation of this value. If the device is in nonconnectable mode, the actual interval will be a minimum of 100ms. Default is 80ms.

Callback Functions

Certain events (apart from UI events on the host device) will cause a callback function to be activated. Here’s a list of those functions; to use any of them, define them in your sketch below the four standard SimbleeForMobile functions.

  • void SimbleeForMobile_onAdvertisement(bool start)– Called when advertisement starts, or stops, and start reports which event occurred.

  • void SimbleeForMobile_onConnect()– Called when a host connects to the Simblee device.

  • void SimbleeForMobile_onDisconnect()– Called when a host disconnects from the Simblee.

  • void SimbleeForMobile_onRSSI(int rssi)– Called when new RSSI information is available. This is the signal strength at the Simblee, not the host.

UI Drawing Concepts

Now for the good part: how to draw a UI on the host! These functions may be called at any time, in any function; if you call them during the ui() function call, however, they will only be sent once, on connection, which makes the bandwidth usage lower.

A note on position: all objects are created with their upper left corner at the reference location. The upper left corner of the screen is 0,0, and the X and Y coordinate values increase as you move towards the right or bottom edges of the screen. To find the X and Y dimensions of the screen, you may reference the SimbleeForMobile.screenWidth and SimbleeForMobile.screenHeight variables.

It is possible to use the device in either portrait or landscape mode. The mode is selected when SimbleeForMobile.beginScreen() is called. More on this below.

Bookending your UI items with SimbleeForMobile.beginScreen() andSimbleeForMobile.endScreen() within the ui() function allows the Simblee app to determine what portions of the UI the user expects to remain fixed. Anything not between those two function calls will not be cached on the host device and will be reuploaded at every device reconnection.

UI Elements

A note about colors: many of these objects accept one or more parameters of type color_t. color_t variables contain red, green, blue, and alpha channel information, and are returned by the functions rgb(redVal, greenVal, blueVal) and rgba(redVal, greenVal, blueVal, alphaVal). There are also some pre-defined macros for certain colors: BLACK, RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, WHITE, GRAY, and CLEAR.

Rectangle

UI Rectangle object examples

The simplest object that can be drawn in the UI is a rectangle. Parameters are the x,y coordinates of the upper left corner, x and y dimensions, and color. If so desired, a second color parameter can be passed, and the rectangle will be colored as a gradient from top to bottom.

language:c
uint8_t drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, color_t color);
uint8_t drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
    color_t color, color_t color2);

Text Box

UI Text Box examples

Text boxes can be either numeric or alphanumeric. They are created via overloaded calls to the SimbleeForMobile.drawText() function; height is automatically calculated. Text cannot be made bold, italicized, etc, but the size and color may be altered, and alphanumeric text boxes may contain multiple lines of text (by inserting ‘\n’ characters in the string). Text boxes may only be used for user input by detecting a touch, like a button; for user text value inputs, see “Text Fields”, up next.

language:c
uint8_t drawText(uint16_t x, uint16_t y, const char* title);
uint8_t drawText(uint16_t x, uint16_t y, const char* title, color_t color);
uint8_t drawText(uint16_t x, uint16_t y, const char* title, color_t_color,
    uint8_t size);

uint8_t drawText(uint16_t x, uint16_t y, int16_t value);
uint8_t drawText(uint16_t x, uint16_t y, int16_t value, color_t color);
uint8_t drawText(uint16_t x, uint16_t y, int16_t value, color_t color,
    uint8_t size);

Text Field

UI Text field examples

A text field is intended to receive user input in the form of a string or number. Unlike text boxes, width is not automatically calculated and must be supplied to the function after x and y are specified. After width is the last mandatory field, a string which will be the default value upon launch of the script. This string can, of course, be empty, if you don’t want to display a default value. Optional parameters are placeholder text, which appears whenever the text field is empty (including when the default text string is empty),color, which is the text color, and background, which is the color of the background inside the field. For a numerical text field, instead of a default string, a default value is entered; however, this means that the placeholder text will never be visible in a numerical text field. Numerical text fields will also cause the keyboard to be brought up in a numerical mode, but the input is not constrained to numbers.

language:c
uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, const char* text);
uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, const char* text,
    const char* placeholder);
uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, const char* text,
    const char* placeholder, color_t color);
uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, const char* text,
    const char* placeholder, color_t color, color_t background);

uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, int16_t value);
uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, int16_t value,
    const char* placeholder);
uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, int16_t value,
    const char* placeholder, color_t color);
uint8_t drawTextField(uint16_t x, uint16_t y, uint16_t w, int16_t value,
    const char* placeholder, color_t color, color_t background);

Button

UI Button examples

Buttons are the simplest default interactive UI element. Unlike text boxes, they can have a specified width, and the title will be centered inside the button. The background of the button is always clear; the text can be colored. The type argument can be either BOX_TYPE or TEXT_TYPE.

language:c
uint8_t drawButton(uint16_t x, uint16_t y, uint16_t w, const char* title);
uint8_t drawButton(uint16_t x, uint16_t y, uint16_t w, const char* title,
    color_t color);
uint8_t drawButton(uint16_t x, uint16_t y, uint16_t w, const char* title,
    color_t color, uint8_t type);

Switch

Switch examples

Switches are on/off toggles; the only valid parameters are location and color. They will change to a more subdued color variation when off.

language:c
uint8_t drawSwitch(uint16_t x, uint16_t y);
uint8_t drawSwitch(uint16_t x, uint16_t y, color_t color);

Segment

Segment examples

Segment objects are a “choose one” option. Aside from the x and y location parameters, the overall width (w) of the object (not of each segment!), the name of a const array of const char\* objects, the number of desired segments (i.e., the number of objects in the array), and, optionally, the color of the object must all be provided.

language:c
// Syntax for specifying segment titles; odd names and values used to show
//  that segment text and title variable names are completely arbitrary.
const char* alice = "blue";
const char* bob = "leopard";
const char* texas = "hematite";

const char* const bullDozer[3] = {alice, bob, texas};

uint8_t drawSegment(uint16_t x, uint16_t y, uint16_t w, const char* const
    *title, uint8_t count);
uint8_t drawSegment(uint16_t x, uint16_t y, uint16_t w, const char* const
    *title, uint8_t count, color_t color);

Slider

Slider examples

For gross adjustments of value (speeds, volumes, etc.) where absolute actual values aren’t of great importance, a slider is probably the best choice. Parameters are x and y position, width of the object, minimum and maximum values, and, optionally, color.

language:c
uint8_t drawSlider(uint16_t x, uint16_t y, uint16_t w, int16_t min,
    int16_t max);
uint8_t drawSlider(uint16_t x, uint16_t y, uint16_t w, int16_t min,
    int16_t max, color_t color);

Stepper

Stepper examples

For fine adjustments, a stepper object may be more appropriate. Each press of either of the buttons of a stepper object increments or decrements a value, accordingly; the user may hold the button down to continuously increment or decrement. A textField object should be used if the current value is to be displayed, as the stepper has no means of display itself.

Note that the w parameter is unused and may be set to any value.

language:c
uint8_t drawStepper(uint16_t x, uint16_t y, uint16_t w, int16_t min,
    int16_t max);
uint8_t drawStepper(uint16_t x, uint16_t y, uint16_t w, int16_t min,
    int16_t max, color_t color);

Images

It is possible to include custom images in your Simblee UI; this is not recommended, however, as the image will be stored in the Simblee firmware as a full-size PNG bitmap image meaning that even relatively small images will take up a large chunk of the available code memory in the Simblee. We’re not going to go into the full process for doing this; it would take up too much space in this already-large tutorial.

To encode an image, you’ll need a program called “xxd”. This program will convert a PNG file to a .h file; that file must then be moved into your sketch folder.

Up to 31 images may be stored in this fashion. For an example of using this functionality, see the “Temperature” example included in the Simblee support package.

UI Element Update Functions


It’s possible to update the position, width, height, and the color(s) of an object after it is created. Most objects can be updated using one of these functions; the id parameter is the value returned by the function called to create the object.

language:c
void updateX(uint8_t id, uint16_t x);
void updateY(uint8_t id, uint16_t y);
void updateOrigin(uint8_t id, uint16_t x, uint16_t y);

void updateW(uint8_t id, uint16_t w);
void updateH(uint8_t id, uint16_t h);
void updateSize(uint8_t id, uint16_t w, uint16_t h);

void updateRect(uint8_t id, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void updateColor(uint8_t id, color_t color);
void updateColor2(uint8_t id, color_t color2);

textBox and textField have their own specialized update functions which can only be applied to them:

language:c
void updateValue(uint8_t id, int16_t value);
void updateText(uint8_t id, const char *text);

Finally, any object can be shown, or hidden, by using the setVisible() function. Passing true makes the object visible if it is hidden.

language:c
void setVisible(uint8_t id, bool visible);

Reacting to UI Events

Whenever a UI event occurs, the ui_event() function is called. You can specify what an event is using the setEvents() function.

language:c
void setEvents(uint8_t id, uint8_t events);

The events parameter is the logical OR of the constants EVENT_PRESS,EVENT_DRAG, and EVENT_RELEASE. When an object is touched (EVENT_PRESS), dragged, or released, ui_event() is called. Within ui_event(), information about the event is contained in the event object:

  • event.id– The identifier (value returned by the function which created the object) of the object generating the event.
  • event.type– The type of the event (one of EVENT_PRESS, EVENT_RELEASE, or EVENT_DRAG)
  • event.value– The current value of the object.
  • event.text– The current text of the object (only valid for non-numericTextField objects)

For image objects, there are two additional event types: EVENT_POSITION andEVENT_COLOR. These behave as the others, but indicate that the returned information is one of the following data chunks.

  • event.x, event.y– The position within the object (not relative to the absolute screen coordinates) where the event occurred.
  • event.red, event.blue, event.green, event.alpha– RGBA information about the pixel that was touched (only valid in image objects)

SimbleeBLE

This library controls the more basic elements of the BLE interface: advertisement, iBecon functionality, data transfer, and proximity, for example. You’ll need to add #include <SimbleeBLE.h> to the top of your main sketch file to use any of these functions. This is fairly low-level stuff and is not needed to use the Simblee to communicate with the Sibmlee phone app; however, you will likely need it to develop your own phone application.

General BLE Functionality

Some of these things can be useful even when interfacing with the Simblee for Mobile app.

If you wish to set any of these variables, you must do so before callingSimbleeBLE.begin().

  • SimbleeBLE.txPowerLevelint between -20 and +4 representing transmit power, in dBm. Default is +4; only values which a multiples of 4 are allowed.

  • SimbleeBLE.customUUID– this const char\* variable allows the user to change the UUID of the Simblee module. This will break compatability with the Simblee app but may be useful in situations where you are creating your own application.

  • SimbleeBLE.deviceNameconst char\* variable holding the name of the Simblee module. By default, it is “Simblee”. The combined length of the device name and advertisement data must be less than or equal to 18; any longer and the name will be truncated to one character to make room for the data.

  • SimbleeBLE.radioActive– Evaluates to true if the radio is currently transmitting data, and false otherwise. Can be used to delay timing critical code until immediately after the radio has transmitted data to reduce the chances that the radio will interrupt the timing critical code; however, the radio cannot be disabled, so it’s up to the user to make sure that the time required is shorter than the time before the next radio packet.

Advertisement

Advertisement is the means by which a peripheral BLE device communicates its existance to central devices in the area which are currently scanning for advertising devices. Advertising comes in four flavors, depending upon whether the advertisement is connectable or not, and whether it is directed or not. The simblee supports only undirected advertising (i.e., broadcast), but it can be connectable or not connectable.

Simblee modules can also only function as peripheral devices, not central. Also, you must not exceed 9600 baud during BLE mode; failure to adhere to this will actually lock up your sketch.

  • SimbleeBLE.advertisementIntervalint variable declaring, in ms, the frequency with which to issue advertisement packets. Range from 20ms to 10.24s; the actual range units are in units of 0.625ms, so the actual interval will only be an approximation of this value. If the device is in nonconnectable mode, the actual interval will be a minimum of 100ms. Default is 80ms.

  • SimbleeBLE.advertisementDataconst char\* variable pointing to a string containing some data sent out with each advertisement packet. Defaults to“sketch” and is the description that shows up in the Simblee app under the device name. Max 32 characters. The combined length of the device name and advertisement data must be less than or equal to 18; any longer and the name will be truncated to one character to make room for the data.

  • SimbleeBLE_onAdvertisement(bool start)– This function is automatically called when advertisement is started or stopped; start is true if advertising was started and false if it was stopped. It is not called when an advertising packet is sent out, however.

Connections

These functions and variables control the connection to a host device. Most of these can be ignored for interoperation with the Simblee mobile app; however, the functions called on connection and disconnection may be useful.

These variables must be set before calling SimbleeBLE.begin().

  • SimbleeBLE.connectablebool variable used to enable/disable the connectable state of the Simblee.

  • SimbleeBLE_onConnect()– Called when a new connection to the Simblee is opened.

  • SimbleeBLE_onDisconnect()– Called when a connection to the Simblee is closed.

  • SimbleeBLE_onRSSi(int RSSI)– Called when new RSSI (received signal strength indicator) data is available. This is at the Simblee, not at the host. Values range from 0dBm (best) to -127dBm, although the connection will be severed as too unreliable around -92dBm.

  • SimbleeBLE_onReceive(char \*data, int len)– Called when data has been received from the host.

Note that the above functions are not a part of the SimbleeBLE class; they are defined elsewhere. The following functions are part of the SimbleBLE class.

These functions send various data types back to the host. Again, note that this mechanism is not required when dealing with the Simblee for Mobile app.

  • SimbleeBLE.send(char data)
  • SimbleeBLE.send(const char \*data, int len)
  • SimbleeBLE.sendByte(uint8_t data)
  • SimbleeBLE.sendInt(int data)
  • SimbleeBLE.sendFloat(float data)

  • SimbleeBLE.updateConnInterval(in min_conn_interval_ms, int max_conn_interval_ms)– Request that the host change the connection interval to some number of milliseconds between the min and max values. The host may reject this or choose a value out of this range entirely, at its discretion.

  • SimbleeBLE.getConnInterval()– Return an int specifying the current connection interval in milliseconds. Minimum value is 7.5ms, max is 4s.

iBeacon functionality

iBeacon is a protocol developed by Apple for making BLE devices that can be used to transmit small data packets to nearby devices. iBeacons are one-way; the receiving devices cannot communicate back to the iBeacon devices.

As with the advertisement variables, these must be set before callingSimbleeBLE.begin().

  • SimbleeBLE.iBeaconbool which enables iBeacon mode.

SimbleeBLE.iBeaconUUID– array of 16 uint8_t values comprising the UUID to be used in iBeacon mode.

  • SimbleeBLE.iBeaconMajor and Simblee.iBeaconMinor– These two unsigned short variable values are reported by the iBeacon constantly, along with the UUID and the iBeaconMeasuredPower value. Both default to 0.

  • SimbleeBLE.iBeaconMeasuredPower– Signal strength of this module as measured at 1m, in dBm. This value is stored as an unsigned 8-bit integer; you’ll need to convert the value to hex before writing to the variable. The default value is -59dBm; that converts to 0xC5 in two’s complement expressed as hexadecimal. Apps which attempt to determine distance to the module will use this as a base value for calculating the probable distance to the module.

Control an LED

This example shows you how to control an LED on (or attached to) a Simblee board from your smart device. We’ll be using an LED connected to pin 2; this is provided for you on the SparkFun Simblee Breakout Board. If you’re using the SparkFun LilyPad Simblee Board, there is an LED attached to pin 13, so you can change the led variable in the code to reflect that. For the RFDigital Simblee Breakout, you’ll need to connect an LED to a pin of your choice and change the code accordingly.

This example shows not only how to structure the code, but also how to use the “switch” and “button” objects, and how to add an event trigger to an object that doesn’t normally have it.

Here’s the complete listing of the code; it can be downloaded from the GitHub repository directly or from Github as a zip file.

language:c
/****************************************************************************
 * LED_Control LED Control from smart phone Mike Hord @ SparkFun Electronics 26
 * Jan 2016 https://github.com/sparkfun/Simblee_Tutorials
 *
 * This example demonstrates the use of the SimbleeForMobile library to control
 * a pin on a Simblee module from a phone app. We'll show both a button and a
 * switch in this example.
 *
 * Resources: Please install the Simblee support files before attempting to use
 * this sketch; see
 * https://learn.sparkfun.com/tutorials/simblee-concepts#setting-up-arduino for
 * details.
 *
 * Development environment specifics: Arduino.cc IDE v1.6.7
 *
 * This code is beerware; if you see me (or any other SparkFun employee) at the
 * local, and you've found our code helpful, please buy us a round!
 * ****************************************************************************/

// To use the SimbleeForMobile library, you must include this file at the top
// of your sketch. **DO NOT** include the SimbleeBLE.h file, as it will cause
// the library to silently break.
#include <SimbleeForMobile.h>

const int led = 2; // The Simblee BOB (WRL-13632) has an LED on pin 2.
int ledState = LOW;

// Every draw command returns a uint8_t result which is the object id that was
// created. If you wish to change the object later, you'll need this value,
// and if you want to catch an event created by an object, you'll need it
// there, too. Make sure you create these id variables outside of any function,
// as you'll need to refer to them in many other functions.

uint8_t btnID;
uint8_t switchID;

void setup()
{
  pinMode(led, OUTPUT);
  digitalWrite(led, ledState);

  // advertisementData shows up in the app as a line under deviceName. Note
  // that the length of these two fields combined must be less than 16
  // characters!
  SimbleeForMobile.advertisementData = "Blink";
  SimbleeForMobile.deviceName = "WRL-13632";

  // txPowerLevel can be any multiple of 4 between -20 and +4, inclusive. The
  // default value is +4; at -20 range is only a few feet.
  SimbleeForMobile.txPowerLevel = -4;

  // This must be called *after* you've set up the variables above, as those
  // variables are only written during this function and changing them later
  // won't actually propagate the settings to the device.
  SimbleeForMobile.begin();
}

void loop()
{
  // This function must be called regularly to process UI events.
  SimbleeForMobile.process();
}

// ui() is a SimbleeForMobile specific function which handles the specification
// of the GUI on the mobile device the Simblee connects to.
void ui()
{
  // color_t is a special type which contains red, green, blue, and alpha
  // (transparency) information packed into a 32-bit value. The functions rgb()
  // and rgba() can be used to create a packed value.
  color_t darkgray = rgb(85,85,85);

  // These variable names are long...let's shorten them. They allow us to make
  // an interface that scales and scoots appropriately regardless of the screen
  // orientation or resolution.
  uint16_t wid = SimbleeForMobile.screenWidth;
  uint16_t hgt = SimbleeForMobile.screenHeight;

  // The beginScreen() function both sets the background color and serves as a
  // notification that the host should try to cache the UI functions which come
  // between this call and the subsequent endScreen() call.
  SimbleeForMobile.beginScreen(darkgray);

  // Create a button slightly more than halfway down the screen, 100 pixels
  // wide, in the middle of the screen. The last two parameters are optional;
  // see the tutorial for more information about choices for them. The BOX_TYPE
  // button has a bounding box which is roughly 38 pixels high by whatever the
  // third parameter defines as the width.
  btnID = SimbleeForMobile.drawButton(
                              (wid/2) - 75,          // x location
                              (hgt/2) - 22,          // y location
                              150,                   // width of button
                   "Reverse LED",         // text shown on button
                              WHITE,                 // color of button
                              BOX_TYPE);             // type of button

  // Buttons, by default, produce only EVENT_PRESS type events. We want to also
  // do something when the user releases the button, so we need to invoke the
  // setEvents() function. Note that, even though EVENT_PRESS is default, we
  // need to include it in setEvents() to avoid accidentally disabling it.
  SimbleeForMobile.setEvents(btnID, EVENT_PRESS | EVENT_RELEASE);

  // Create a switch above the button. Note the lack of a title option; if you
  // want to label a switch, you'll need to create a textBox object separately.
  // A switch's bounding box is roughly 50 by 30 pixels.
  switchID = SimbleeForMobile.drawSwitch(
                              (wid/2) - 25,          // x location
                              (hgt/2)+22,            // y location
                              BLUE);                 // color (optional)
  SimbleeForMobile.endScreen();
}

// This function is called whenever a UI event occurs. Events are fairly easy
// to predict; for instance, touching a button produces a "PRESS_EVENT" event.
// UI elements have default event generation settings that match their expected
// behavior, so you'll only rarely have to change them.
void ui_event(event_t &event)
{
  // We created the btnID and switchID variables as globals, set them in the
  // ui() function, and we'll use them here.


  if (event.id == btnID)
  {
    if (event.type == EVENT_PRESS)
    {
      if (ledState == HIGH) digitalWrite(led, LOW);
      else digitalWrite(led, HIGH);
    }
    if (event.type == EVENT_RELEASE)
    {
      if (ledState == HIGH) digitalWrite(led, HIGH);
      else digitalWrite(led, LOW);
    }
  }

  // If the event was a switch press, we want to toggle the ledState variable
  // and then write it to the pin.
  if (event.id == switchID)
  {
    if (ledState == HIGH) ledState = LOW;
    else ledState = HIGH;
    digitalWrite(led, ledState);
  }
}

Once the code is loaded, you should see this in the Simblee app:

Device name and info in the app

Touching the listing for the Simblee we just programmed will bring up the application interface we just specified by programming the module with the code above:

App on the phone

As you can see from playing with it a bit, toggling the switch on the app turns the LED on and off, and pushing the button reverses the current state of the LED until it’s released.

Reading from the Simblee

Sending data to the Simblee is only one half of the equation; we need to be able to get data back, when appropriate, as well.

This is a simple demonstration of doing just that; we listen to a button on pin 3 and then change the color of a box on the phone screen. The action shown on the phone is arbitrary; we could just as easily change a text value, for instance, or even move an object.

Here’s the complete listing of the code; it can be downloaded from the GitHub repository directly or from Github as a zip file.

language:c
/****************************************************************************
 * Read_Input Read a Simblee input from smart phone
 * Mike Hord @ SparkFun Electronics 26 Jan 2016
 * https://github.com/sparkfun/Simblee_Tutorials
 *
 * This example demonstrates the use of the SimbleeForMobile library to read
 * the state of a pin on a Simblee module from a phone app.
 *
 * Resources: Please install the Simblee support files before attempting to use
 * this sketch; see
 * https://learn.sparkfun.com/tutorials/simblee-concepts#setting-up-arduino for
 * details.
 *
 * Development environment specifics: Arduino.cc IDE v1.6.7
 *
 * This code is beerware; if you see me (or any other SparkFun employee) at the
 * local, and you've found our code helpful, please buy us a round!
 * ****************************************************************************/

// To use the SimbleeForMobile library, you must include this file at the top
// of your sketch. **DO NOT** include the SimbleeBLE.h file, as it will cause
// the library to silently break.
#include <SimbleeForMobile.h>

const int btn = 3; // The Simblee BOB (WRL-13632) has a button on pin 3.

// Every draw command returns a uint8_t result which is the object id that was
// created. If you wish to change the object later, you'll need this value, and
// if you want to catch an event created by an object, you'll need it there,
// too. Make sure you create these id variables outside of any function, as
// you'll need to refer to them in many other functions.

uint8_t boxID;

void setup()
{
  // Protip: using INPUT_PULLUP very rarely causes any problems but can solve
  // a lot of problems with input signals that aren't pulled strongly.
  pinMode(btn, INPUT_PULLUP);

  // advertisementData shows up in the app as a line under deviceName. Note
  // that the length of these two fields combined must be less than 16
  // characters!
  SimbleeForMobile.advertisementData = "Button";
  SimbleeForMobile.deviceName = "WRL-13632";

  // txPowerLevel can be any multiple of 4 between -20 and +4, inclusive. The
  // default value is +4; at -20 range is only a few feet.
  SimbleeForMobile.txPowerLevel = -4;

  // This must be called *after* you've set up the variables above, as those
  // variables are only written during this function and changing them later
  // won't actually propagate the settings to the device.
  SimbleeForMobile.begin();
}

void loop()
{
  // All we want to do is detect when the button is pressed and make the box on
  // the screen white while it's pressed.

  // This is important: before writing *any* UI element, make sure that the UI
  // is updatable!!! Failure to do so may crash your whole program.
  if (SimbleeForMobile.updatable)
  {
    // Okay, *now* we can worry about what the button is doing. The
    // updateColor() function takes the id returned when we created the box and
    // tells that object to change to the color parameter passed.
    if (digitalRead(btn) == LOW) SimbleeForMobile.updateColor(boxID, WHITE);
    else SimbleeForMobile.updateColor(boxID, BLACK);
  }
  // This function must be called regularly to process UI events.
  SimbleeForMobile.process();
}

// ui() is a SimbleeForMobile specific function which handles the specification
// of the GUI on the mobile device the Simblee connects to.
void ui()
{
  // color_t is a special type which contains red, green, blue, and alpha
  // (transparency) information packed into a 32-bit value. The functions rgb()
  // and rgba() can be used to create a packed value.
  color_t darkgray = rgb(85,85,85);

  // These variable names are long...let's shorten them. They allow us to make
  // an interface that scales and scoots appropriately regardless of the screen
  // orientation or resolution.
  uint16_t wid = SimbleeForMobile.screenWidth;
  uint16_t hgt = SimbleeForMobile.screenHeight;

  // The beginScreen() function both sets the background color and serves as a
  // notification that the host should try to cache the UI functions which come
  // between this call and the subsequent endScreen() call.
  SimbleeForMobile.beginScreen(darkgray);

  // SimbleeForMobile doesn't really have an kind of indicator- but there IS a
  // drawRect() function, and we can freely change the color of the rectangle
  // after drawing it! The x,y coordinates are of the upper left hand corner.
  // If you pass a second color parameter, you'll get a fade from top to bottom
  // and you'll need to update *both* colors to get the whole box to change.
  boxID = SimbleeForMobile.drawRect(
                          (wid/2) - 50,        // x position
                          (hgt/2) - 50,        // y positon
                          100,                 // x dimension
                          100,                 // y dimensionrectangle
                          BLACK);              // color of rectangle.

  SimbleeForMobile.endScreen();
}

// This function is called whenever a UI event occurs. Events are fairly easy
// to predict; for instance, touching a button produces a "PRESS_EVENT" event.
// UI elements have default event generation settings that match their expected
// behavior, so you'll only rarely have to change them.
void ui_event(event_t &event)
{
  // In this case, we're sending data back from the Simblee to the app, so we
  // don't really care about any events that might occur.
}

You’ll know the sketch upload worked because the Simblee will appear in the app like this:

Simblee app with name and data

Here’s what the GUI we’ve created looks like when the button is not pressed (left) and when it is pressed (right):

Sketch UI

Low Power Modes

As a Bluetooth Low Energy device, one of the main benefits of the Simblee module is a long battery life. Under normal circumstances, the module draws about 5mA. This will drain one of our [CR2032 coin cell batteries] in around two days' time.

There are two lower power modes available, however: Ultra Low Power mode, and Off. They differ in how the processor can be awakened and in how much power the processor consumes in that mode.

In ULP mode, the processor consumes about 1/10 the current it does running normally. It can be told to awaken after a specific amount of time or on an event (a rising or falling edge) on a specified pin. The improvement in battery life depends, of course, on how often the processor is awakened; wake it too often and remain awake too long and you may notice very little improvement at all.

In Off mode, the processor consumes about 1/5000 the current it normally does. In this mode, only a pin change event can wake the processor, and it can only execute code within a specially created callback function. However, with current consumption this low, the shelf life of the battery becomes a serious consideration when calculating the total battery life.

Here’s the complete listing of the code; it can be downloaded from the GitHub repository directly or from Github as a zip file.

language:c
/****************************************************************************
 * Low Power Example Sketch
 * Low_Power.ino
 * 29 Jan 2016
 * https://github.com/sparkfun/Simblee_Tutorials
 *
 * This app is a way to show how the Simblee Low Power modes can be used.
 *
 * Resources: Please install the Simblee support files before attempting to use
 * this sketch; see
 * https://learn.sparkfun.com/tutorials/simblee-concepts#setting-up-arduino for
 * details.
 *
 * Development environment specifics: Arduino.cc IDE v1.6.7
 *
 * This code is beerware; if you see me (or any other SparkFun employee) at the
 * local, and you've found our code helpful, please buy us a round!
 * ****************************************************************************/

// To use the SimbleeForMobile library, you must include this file at the top
// of your sketch. **DO NOT** include the SimbleeBLE.h file, as it will cause
// the library to silently break.
#include <SimbleeForMobile.h>

const int led = 2; // The Simblee BOB (WRL-13632) has an LED on pin 2.
int ledState = LOW;
const int button = 3;

void setup()
{
  pinMode(led, OUTPUT);
  digitalWrite(led, ledState);
  pinMode(button, INPUT_PULLUP);

  // advertisementData shows up in the app as a line under deviceName. Note
  // that the length of these two fields combined must be less than 16
  // characters!
  SimbleeForMobile.advertisementData = "LoPow";
  SimbleeForMobile.deviceName = "WRL-13632";

  // txPowerLevel can be any multiple of 4 between -20 and +4, inclusive. The
  // default value is +4; at -20 range is only a few feet.
  SimbleeForMobile.txPowerLevel = -4;


  // This must be called *after* you've set up the variables above, as those
  // variables are only written during this function and changing them later
  // won't actually propagate the settings to the device.
  SimbleeForMobile.begin();
}

void loop()
{
  // There are two low power modes: Ultra Low Power and Off. ULP consumes about
  // 1/10 of the power that a fully on Simblee consumes; in Off mode, the
  // device is using about 1/5000 of the normal power consumption!

  // The system can be brought out of ULP mode either on a timed basis (see the
  // tutorial for more information; broadly, pass a number of milliseconds to
  // the Simblee_ULPDelay() function and the processor will awaken that many
  // milliseconds later) or by a pin transition event. In Off mode, *only* a
  // pin event can wake the processor!

  // Simblee_pinWakeCallback() executes the passed function when a pin causes
  // the device to leave either sleep mode. Options for the second parameter
  // are HIGH, LOW, or NONE, and correspond to the triggering state of the pin.
  Simblee_pinWakeCallback(button, LOW, buttonCallback);

  // Simblee_pinWake() sets up the device to awaken from sleep mode, but does
  // NOT provide a callback function. In ULP mode, execution will resume on the
  // line after the function call to Simblee_ULPDelay(); in Off mode, the
  // processor will immediately revert to sleep mode unless a callback
  // function is available.
  //Simblee_pinWake(button, LOW);

  // Simblee_systemOff() puts the device in a very low power mode, where it
  // consumes less than 1uA of current (compared to about 5000uA during normal
  // operation). In this mode, *only* a pin transition can bring the device out
  // of sleep, and you *must* provide a callback function with
  // Simblee_pinWakeCallback() for any code to be executed!
  Simblee_systemOff();

  // Simblee_ULPDelay() causes the processor to sleep for some number of
  // milliseconds. There are utility macros defined for converting from larger,
  // more convenient units: DAY(x), HOURS(x), MINUTES(x), SECONDS(x) will each
  // cause the processor to wait for x of that number of units. Pass INFINITE
  // to delay until a pin event occurs.
  //Simblee_ULPDelay(INFINITE);

  // If a pin event woke the processor, you MUST call the
  // Simblee_resetPinWake() function for that pin, or the processor will
  // immediately exit sleep mode upon reentering it.
  Simblee_resetPinWake(button);

  // We're blinking the LED here a bit longer than in the callback function, so
  // we can differentiate between which section of code is executing.
  digitalWrite(led, HIGH);
  delay(1500);
  digitalWrite(led, LOW);

  // This function must be called regularly to process UI events.
  SimbleeForMobile.process();
}

// ui() is a SimbleeForMobile specific function which handles the specification
// of the GUI on the mobile device the Simblee connects to.
void ui()
{
  // Empty, for this sketch's purposes.
}

// This function is called whenever a UI event occurs. Events are fairly easy
// to predict; for instance, touching a button produces a "PRESS_EVENT" event.
// UI elements have default event generation settings that match their expected
// behavior, so you'll only rarely have to change them.
void ui_event(event_t &event)
{
  // Empty for this sketch's purposes.
}

// This function (the name of which is completely arbitrary) is executed after
// a pinWake event pulls the processor out of low power mode. Here, we just
// blink the LED on for 500ms, just as a visual check that we have pulled out
// of low power mode.
int buttonCallback(uint32_t button)
{
  Simblee_resetPinWake(button);
  digitalWrite(led, HIGH);
  delay(500);
  digitalWrite(led, LOW);
}

There are no SimbleeForMobile UI elements defined in this sketch; note that, when in low power mode, the Simblee dictates when the host device gets updated, so the host device cannot interact with the Simblee. A Simblee in low power mode cannot be found in the app, either, although if you are connected to a Simblee when it enters ULP mode, the app will remain connected. Entering Off mode will cause the device to disappear from the app, and the connection to be lost.

Resources and Going Further

Here are some additional resources for more information about the Simblee.

For more Bluetooth fun, check out these other SparkFun tutorials.

RN-52 Bluetooth Hookup Guide

A hookup guide to get you started with the RN-52 Audio Bluetooth Module Breakout Board.

MetaWatch Teardown and Arduino Hookup

Tearing down the nifty bluetooth-enabled MetaWatch. Then building an Arduino sketch to control it.

Bluetooth Basics

An overview of the Bluetooth wireless technology.
New!

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!

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

Simblee LilyPad Hookup Guide

$
0
0

Simblee LilyPad Hookup Guide a learn.sparkfun.com tutorial

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

Introduction

The Simblee LilyPad Board is a programmable board that allows you to add mobile app functionality via Bluetooth Low Energy (BLE, or Bluetooth 4.0) to your e-textile projects. Unlike other BLE solutions, the Simblee requires no specialized app development skills to realize the phone-side interface: all the necessary coding is done in the Arduino environment and then uploaded to a browser app on the phone.

Simblee LilyPad

If you want to skip directly to writing code, we have another tutorial covering coding concepts that are common to all Simblee products. If you’re looking for a non-sewable option, checkout the SparkFun Simblee Breakout Board.

Suggested Reading

The Simblee LilyPad board is not a board for beginners. We suggest that you be comfortable with the topics covered in these tutorials before trying to use the Simblee LilyPad in a project:

Simblee LilyPad Hardware Overview

There are two really important facts in this tutorial, highlighted here:

We recommend using the either the LilyPad FTDI Basic or the 5V FTDI Basic for programming the Simblee LilyPad. Do not use the 3.3V FTDI Basic, as it may not be able to source enough current from the 3.3V rail.
If you've used Arduino boards before, you're probably used to connecting LEDs to the pins as output signals. A normal Arduino can light up many LEDs at once, and several per pin; for the Simblee, you shouldn't try more than ONE per pin, with an additional recommendation of don't try to turn on more than three at a time across all pins. The processor inside the Simblee module cannot drive enough current to light up more LEDs than this.

Let’s take a quick tour of the Simblee LilyPad hardware:

Labeled hardware diagram

  • Programming Header– This is the place to connect the programming board. We recommend using the either the LilyPad FTDI Basic or the 5V FTDI Basic for programming the Simblee LilyPad. Do not use the 3.3V FTDI Basic. This header can also be used to power the board during development.
  • Charge Status LED– If a battery is connected and charging, this LED will be lit. Otherwise, it will be off.
  • Charge/Power Switch– This switch controls the power to the board. When set to “CHG”, the on-board charge circuit will charge the battery (if power is connected via the Programming Header) at 100mA, but power to the rest of the board (and anything powered from the “+” sewtap) will be disconnected. When set to “ON”, the board and any attached circuitry will be powered, and charging will continue if the board is plugged in.
  • Reset Button– Normally this shouldn’t be required, but it may on occasion be useful to start your code from scratch, without reprogramming or pulling the power.
  • User LED– This LED is connected to pin 13 and can be used in your code for a “free” indicator LED.
  • LiPo Battery Connector– This connector mates with the 2mm JST connector on our polymer lithium ion batteries. The charge current is set to 100mA, which is a safe current for any battery with a capacity of 100mAh or higher.

Resources and Going Further

That concludes the Hardware overview for the Simblee LilyPad. For more information on using the Simblee to create your own applications for embedded project, visit our Simblee Concepts tutorial.

New!

Simblee Concepts

February 4, 2016

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!

For more info on the Simblee module itself, please have a look at the Simblee User’s Manual.

Here are a few more resources for the Simblee:

For more Bluetooth fun, check out these other SparkFun tutorials.

RN-52 Bluetooth Hookup Guide

A hookup guide to get you started with the RN-52 Audio Bluetooth Module Breakout Board.

Interactive Hanging LED Array

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

BC118 BLE Mate 2 Hookup Guide

Hooking up and using the BLE Mate 2, which uses the BC118 BLE module from BlueCreations.
New!

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!

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

Using an LCD on the Edison

$
0
0

Using an LCD on the Edison a learn.sparkfun.com tutorial

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

Introduction

One of the requests we often hear for the Intel® Edison is the ability to use an LCD. While the Edison does not have a display driver, we can use the onboard SPI port to control simple LCDs.

For this particular tutorial, we will rely on a recent version of Intel’s UPM library. In it is a module capable of calling the necessary functions to control an ILI9341 driver chip, which is a popular controller for 320x240, 2"-3" LCDs.

NOTE: The UPM driver used in this tutorial is a library that works in user space. That means we can make function calls to draw simple shapes and text on the LCD. Because it is not in kernel space we cannot do things like run X on it.
ALSO NOTE: The SPI driver on the Edison is currently quite slow. A full-screen refresh takes around 20 seconds, so don't expect any video or fast cycling images. If the SPI driver is updated in a future Edison image, you can ignore this message.

Required Materials

You will need an LCD with a ILI9341 controller. These can be found from a variety of sources, such as PJRC and Adafruit. Additionally, you will need the following:

NOTE: If you are using the LCD from PJRC, you will also need a 100Ω resistor.

Suggested Readings

Before getting started, you may find some of the tutorials below helpful.

Hardware Hookup

Build the Block Stack

Using the Edison Hardware Pack, attach the Edison to the Base Block.

Attaching the Edison to the Base Block

Attach the Base Block to the Pi Block. Secure them in place using screws and standoffs.

Attach the Pi Block

Connect the LCD

We need to connect the LCD to the Edison via the Pi Block. Solder headers to the LCD (if necessary), and follow the Fritzing diagram below to connect it to the Edison.

NOTE: If you are using an LCD from PJRC, a 100Ω resistor is needed between the LED and VCC pins on the LCD.
NOTE: If you are using an LCD from Adafruit, you will need to solder the jumpers IM1, IM2, IM3 on the back of the board in order to use SPI.

Connect the LCD to the Edison

Click on the image to view a larger version

Install the ILI9341 Module

NOTE: At the time of this writing, the ILI9341 module is included in UPM but not as part of the Edison image. As a result, we will need to build UPM from source. If, in the future, it is included in the default Edison image, you can skip this section.

Flash and Configure the Edison

If this is your first time using the Edison, it is recommended that you update to the latest firmware and connect to WiFi.

Build MRAA

MRAA is Intel’s set of libraries used to control the low-level hardware. Because UPM relies on MRAA, we need to install it first.

Connect to the Edison over Serial or SSH. Once logged in, enter the following commands to download MRAA:

wget https://github.com/intel-iot-devkit/mraa/archive/master.zip
unzip master.zip
mv mraa-master mraa

Then, build MRAA with:

cd mraa
mkdir build
cd build
cmake ..
make

Install the newly built libraries, and update the pkg-config path, which is needed by UPM.

make install
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig

Build ili9341 in UPM

Next, we need to download the latest version of UPM and install the ili9341 module. Download UPM with:

cd ~
rm master.zip
wget https://github.com/intel-iot-devkit/upm/archive/master.zip
unzip master.zip
mv upm-master upm

Prepare to build:

cd upm
mkdir build
cd build
cmake ..

Build and install the ili9341 module:

make ili9341
cd src/ili9341
make install

And that’s it! We’ll use this installed library to make an example program that draws some basic shapes on the LCD. Choose whether you want to write the example program in C++, JavaScript, or Python, and skip to that section below.

NOTE: Each of the C++, JavaScript, and Python examples can be found in ~/upm/examples.

Example Program: C++

If you are used to writing C/C++, then this is the way to go. Go back to your home directory and create a C++ file:

cd ~
vi ili9341.cpp

Press ‘i’ to type text. Copy and paste the code below into vi (if you are using an SSH client like PuTTY, simply right-click in the window to paste).

language:cpp
#include <unistd.h>

#include "ili9341.h"

int main(int argc, char **argv) {

    // Pins (Edison)
    // CS_LCD   GP44 (MRAA 31)
    // CS_SD    GP43 (MRAA 38) unused
    // DC       GP12 (MRAA 20)
    // RESEST   GP13 (MRAA 14)
    upm::ILI9341 * lcd = new upm::ILI9341(31, 38, 20, 14);

    // Fill the screen with a solid color
    lcd->fillScreen(lcd->color565(0, 40, 16));

    // Draw some shapes
    lcd->drawFastVLine(10, 10, 100, ILI9341_RED);
    lcd->drawFastHLine(20, 10, 50, ILI9341_CYAN);
    lcd->drawLine(160, 30, 200, 60, ILI9341_GREEN);
    lcd->fillRect(20, 30, 75, 60, ILI9341_ORANGE);
    lcd->drawCircle(70, 50, 20, ILI9341_PURPLE);
    lcd->fillCircle(120, 50, 20, ILI9341_PURPLE);
    lcd->drawTriangle(50, 100, 10, 140, 90, 140, ILI9341_YELLOW);
    lcd->fillTriangle(150, 100, 110, 140, 190, 140, ILI9341_YELLOW);
    lcd->drawRoundRect(20, 150, 50, 30, 10, ILI9341_RED);
    lcd->drawRoundRect(130, 150, 50, 30, 10, ILI9341_RED);
    lcd->fillRoundRect(75, 150, 50, 30, 10, ILI9341_RED);

    // Write some text
    lcd->setCursor(0, 200);
    lcd->setTextColor(ILI9341_LIGHTGREY);
    lcd->setTextWrap(true);
    lcd->setTextSize(1);
    lcd->print("Text 1\n");
    lcd->setTextSize(2);
    lcd->print("Text 2\n");
    lcd->setTextSize(3);
    lcd->print("Text 3\n");
    lcd->setTextSize(4);
    lcd->print("Text 4\n");

    // Test screen rotation
    for(int r = 0; r < 4; r++) {
        lcd->setRotation(r);
        lcd->fillRect(0, 0, 5, 5, ILI9341_WHITE);
        sleep(1);
    }

    // Invert colors, wait, then revert back
    lcd->invertDisplay(true);
    sleep(2);
    lcd->invertDisplay(false);

    // Don't forget to free up that memory!
    delete lcd;

    return 0;
}

Save and exit (‘esc’, type ‘:wq’, and press ‘enter’). Append the UPM modules location to our linker PATH, and compile the program:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
g++ ili9341.cpp -o ili9341 -lupm-ili9341 -lmraa -I/usr/local/include/upm

Run the program:

./ili9341

The screen will fill with a color and draw some basic shapes!

Example Program: JavaScript

If you would like to write a Node.JS program that uses the ILI9341 module, you can do that, too!

cd ~
vi ili9341.js

Press ‘i’ to type text. Copy and paste the code below into vi (if you are using an SSH client like PuTTY, simply right-click in the window to paste).

language:javascript
var ili9341 = require('jsupm_ili9341');

// Pins (Edison)
// CS_LCD   GP44 (MRAA 31)
// CS_SD    GP43 (MRAA 38) unused
// DC       GP12 (MRAA 20)
// RESEST   GP13 (MRAA 14)
var lcd = new ili9341.ILI9341(31, 38, 20, 14);

// Fill the screen with a solid color
lcd.fillScreen(lcd.color565(0, 40, 16));

// Draw some shapes
lcd.drawFastVLine(10, 10, 100, ili9341.ILI9341_RED);
lcd.drawFastHLine(20, 10, 50, ili9341.ILI9341_CYAN);
lcd.drawLine(160, 30, 200, 60, ili9341.ILI9341_GREEN);
lcd.fillRect(20, 30, 75, 60, ili9341.ILI9341_ORANGE);
lcd.drawCircle(70, 50, 20, ili9341.ILI9341_PURPLE);
lcd.fillCircle(120, 50, 20, ili9341.ILI9341_PURPLE);
lcd.drawTriangle(50, 100, 10, 140, 90, 140, ili9341.ILI9341_YELLOW);
lcd.fillTriangle(150, 100, 110, 140, 190, 140, ili9341.ILI9341_YELLOW);
lcd.drawRoundRect(20, 150, 50, 30, 10, ili9341.ILI9341_RED);
lcd.drawRoundRect(130, 150, 50, 30, 10, ili9341.ILI9341_RED);
lcd.fillRoundRect(75, 150, 50, 30, 10, ili9341.ILI9341_RED);

// Write some text
lcd.setCursor(0, 200);
lcd.setTextColor(ili9341.ILI9341_LIGHTGREY);
lcd.setTextWrap(true);
lcd.setTextSize(1);
lcd.print("Text 1\n");
lcd.setTextSize(2);
lcd.print("Text 2\n");
lcd.setTextSize(3);
lcd.print("Text 3\n");
lcd.setTextSize(4);
lcd.print("Text 4\n");

// Test screen rotation
function rotateScreen(r) {
    lcd.setRotation(r);
    lcd.fillRect(0, 0, 5, 5, ili9341.ILI9341_WHITE);
    if (r < 4) {
        r++;
        setTimeout(function() { rotateScreen(r); }, 1000);
    }
}
rotateScreen(0);

// Invert colors, wait, then revert back
setTimeout(function() { lcd.invertDisplay(true); }, 4000);
setTimeout(function() { lcd.invertDisplay(false); }, 6000);

Save and exit (‘esc’, type ‘:wq’, and press ‘enter’). Append the UPM modules location to our Node PATH:

export NODE_PATH=$NODE_PATH:/usr/local/lib/node_modules/

Run the program:

node ili9341.js

The screen will fill with a color and draw some basic shapes!

Example Program: Python

We can also use Python to make calls to the UPM module. Create a Python script:

cd ~
vi ili9341.py

Press ‘i’ to type text. Copy and paste the code below into vi (if you are using an SSH client like PuTTY, simply right-click in the window to paste).

language:python
#!/usr/bin/python

import time
import pyupm_ili9341 as ili9341

# Pins (Edison)
# CS_LCD   GP44 (MRAA 31)
# CS_SD    GP43 (MRAA 38) unused
# DC       GP12 (MRAA 20)
# RESEST   GP13 (MRAA 14)
lcd = ili9341.ILI9341(31, 38, 20, 14)

# Fill the screen with a solid color
lcd.fillScreen(lcd.color565(0, 40, 16))

# Draw some shapes
lcd.drawFastVLine(10, 10, 100, ili9341.ILI9341_RED)
lcd.drawFastHLine(20, 10, 50, ili9341.ILI9341_CYAN)
lcd.drawLine(160, 30, 200, 60, ili9341.ILI9341_GREEN)
lcd.fillRect(20, 30, 75, 60, ili9341.ILI9341_ORANGE)
lcd.drawCircle(70, 50, 20, ili9341.ILI9341_PURPLE)
lcd.fillCircle(120, 50, 20, ili9341.ILI9341_PURPLE)
lcd.drawTriangle(50, 100, 10, 140, 90, 140, ili9341.ILI9341_YELLOW)
lcd.fillTriangle(150, 100, 110, 140, 190, 140, ili9341.ILI9341_YELLOW)
lcd.drawRoundRect(20, 150, 50, 30, 10, ili9341.ILI9341_RED)
lcd.drawRoundRect(130, 150, 50, 30, 10, ili9341.ILI9341_RED)
lcd.fillRoundRect(75, 150, 50, 30, 10, ili9341.ILI9341_RED)

# Write some text
lcd.setCursor(0, 200)
lcd.setTextColor(ili9341.ILI9341_LIGHTGREY)
lcd.setTextWrap(True)
lcd.setTextSize(1)
lcd._print("Text 1\n")
lcd.setTextSize(2)
lcd._print("Text 2\n")
lcd.setTextSize(3)
lcd._print("Text 3\n")
lcd.setTextSize(4)
lcd._print("Text 4\n")

# Test screen rotation
for r in range(0, 4):
    lcd.setRotation(r)
    lcd.fillRect(0, 0, 5, 5, ili9341.ILI9341_WHITE)
    time.sleep(1)

# Invert colors, wait, then revert back
lcd.invertDisplay(True)
time.sleep(2)
lcd.invertDisplay(False)

# Don't forget to free up that memory!
del lcd

Save and exit (‘esc’, type ‘:wq’, and press ‘enter’). Append the UPM modules location to our Python PATH:

export PYTHONPATH=$PYTHONPATH:/usr/local/lib/python2.7/site-packages/

Run the script with:

python ili9341.py

The screen will fill with a color and draw some basic shapes!

Resources and Going Further

If you successfully ran one of the example programs, your LCD should look like this:

Edison with an ILI9341 LCD

Feel free to take a closer look at the examples, as they will show you how to draw basic shapes on the LCD.

Resources

Want to make a smart mirror using the Edison and an LCD? Check out the following tutorial:

New!

Interactive Smart Mirror

February 8, 2016

Build a smart mirror that displays weather data using the Intel® Edison.

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


Interactive Smart Mirror

$
0
0

Interactive Smart Mirror a learn.sparkfun.com tutorial

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

Introduction

In a recent episode of The Fellowship of the Things, we constructed a smart mirror that displays weather data discreetly in the lower right corner. The idea is that while you performed morning tasks like brushing your teeth, putting on makeup, shaving, etc., you could glance at the weather for the day.

Interactive smart mirror with the Edison

While the idea of sticking an LCD behind a one-way mirror is nothing new, we wanted to make ours more interactive. This version of the smart mirror uses an APDS-9960 Gesture Sensor so you can simply wave your hand to change the display.

Required Materials

For this build, you will need some electronics:

Additionally, you will need the following:

Suggested Reading

Before getting started, you may find some of the tutorials below helpful.

Hardware Hookup

Prepare the APDS-9960

Solder headers to the APDS-9960 board.

Headers on the APDS-9960 board

Because we cannot keep the APDS-9960 on the inside of the shadowbox (the IR light does not pass through the window very well), we recommend painting the sensor board to match the shadowbox frame. This part is optional; you don’t have to paint the board if you don’t want to.

If you want to paint the board, first cover the sensor with a small piece of electrical or masking tape.

Masking off the APDS-9960

Carefully apply some spray paint to the board and remove the tape.

Painted APDS-9960

Make the Block Stack

Using the Edison Hardware Pack, attach the Edison to the Base Block.

Edison screwed to the Base Block

Attach the Base Block to the Pi Block. Secure them in place using screws and standoffs.

Edison stack with the Pi Block

Make the Connections

Any ILI9341-controlled LCD should work. If you use the Adafruit 2.4" LCD, you will need to solder the following jumpers on the back of the board closed: IM1, IM2, and IM3 (these allow us to communicate to the LCD via SPI).

Soldered jumpers on the LCD`

Using about 6 inches of wire, solder the LCD to the Pi Block. Cut and strip the ends off 4 female jumper wires and solder the bare ends to the Pi Block. Refer to the Fritzing diagram on where to make the connections:

alt text

You should have the female ends of the jumper wires available to plug into the APDS-9960.

Soldered wires into the Edison Block stack

Assemble the Mirror

Attach the Film

Follow the directions in the window film installation kit to carefully spray, cut, and adhere the film to the inside of the shadowbox’s window.

Applying the film to the shadowbox window

Attach the Inside Electronics

Choose in which corner you want the LCD to go (we chose bottom-right). We recommend putting a few sheets of Styrofoam, wood, etc. to push the LCD up against the window when closed. We also wrapped the Styrofoam with electrical tape to hide the white color.

Foam inside the shadowbox

You can attach the Edison Block stack and LCD using screws, nails, etc. We used pins so we could move the LCD around if we wanted (also, our shadowbox has a soft foam backing). For now, leave the APDS-9960 hanging out of the shadowbox.

Pinning the electronics to the shadowbox

Note that we will wait to attach the APDS-9960 until the Edison has been programmed.

Line the Window with Backing

Since we plan to have cables coming out of the shadowbox, we want to try and prevent as much light as possible from getting through to the window (with the exception of the LCD).

Cut a piece of cardboard (or other opaque material) to cover the shadowbox’s window. From that, cut out the section where the LCD will poke through.

Adding cardboard backing to the shadowbox window

The cardboard can be attached with tape, if you so desire.

Install UPM Modules

Flash and Configure the Edison

If this is your first time using the Edison, it is recommended that you update to the latest firmware and connect to WiFi.

Build MRAA

MRAA is Intel’s set of libraries used to control the low-level hardware. Because UPM relies on MRAA, we need to install it first.

Connect to the Edison over a Serial Terminal or SSH. Once logged in, enter the following commands to download MRAA:

wget https://github.com/intel-iot-devkit/mraa/archive/master.zip
unzip master.zip
mv mraa-master mraa

Then, build MRAA with:

cd mraa
mkdir build
cd build
cmake ..
make

Install the newly built libraries, and update the pkg-config path, which is needed by UPM.

make install
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig

Build ili9341 and apds9960 in UPM

Next, we need to download a custom version of UPM and install the ili9341 and apds9960 modules.

NOTE: The APDS-9960 module in this branch of UPM is very experimental and thus quite buggy. If I can get it to be stable, I might request it to be merged with Intel's UPM library.
cd ~
wget https://github.com/ShawnHymel/upm/archive/smartmirror.zip
unzip smartmirror.zip
mv upm-smartmirror upm

Prepare to build:

cd upm
mkdir build
cd build
cmake ..

Build and install the ili9341 module:

make ili9341
cd src/ili9341
make install

Build and install the apds9960 module:

cd ../..
make apds9960
cd src/apds9960
make install

Other Dependencies

With the UPM modules installed, we can work on writing the actual code. That does mean we need to install a few more dependencies, though.

Other Node Libraries

We need one more library for our code. Luckily, we can install it through npm:

cd ~
npm install xml2js

NTP

We will want our Edison system time to be up-to-date. To do that, we will rely on an NTP service to regularly poll an Internet-connected server for the most accurate time.

Open the package manager file with:

vi /etc/opkg/base-feeds.conf

Press ‘i’ to start typing, and enter the following:

src/gz all http://repo.opkg.net/edison/repo/all
src/gz edison http://repo.opkg.net/edison/repo/edison
src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32

Press ‘esc’, and enter ‘:wq’ to save and exit. Update the package manager, and install the NTP client:

opkg update
opkg install ntp

Configure the NTP client:

vi /etc/ntp.conf

Find the line that says “server 127.127.1.0” and change it to (press ‘i’ to edit):

server pool.ntp.org

Your file should look like this:

Configure NTP client

Save and exit (‘esc’ and ‘:wq’). Next, we want to adjust our system’s local time to our timezone. Since I am in Mountain Standard Time, I’m going to use MST. We do this by creating a symbolic link /etc/localtime that points to the timezone we want in /usr/share/zoneinfo/ (note that I’m using MST for my timezone).

rm /etc/localtime
ln -s /usr/share/zoneinfo/MST /etc/localtime

When we’re done, reboot:

reboot

You can check your timezone by entering the command:

date

This should print out the date, time, and timezone.

Checking timezone in Linux

Configure OpenWeatherMap

We will be using OpenWeatherMap for our weather data, as it offers good hourly forecast data. In your browser, navigate to OpenWeatherMap’s sign up page. Enter your credentials to make an account. Once you have logged in, scroll down on your profile page, and copy down your API key.

OpenWeatherMap API key

Find Your Location

We also need to find our location so we can pass that to OpenWeatherMap. Open up Google Maps, and place a marker at the location where you want to get weather data (left-click on the map). A pop-up note will appear with the latitude and longitude data.

Using Google Maps to get latitude and longitude

Copy down those two numbers as well. We’ll need them.

The Code

Download the smart mirror code and unzip it:

rm master.zip
wget https://github.com/sparkfun/IoT_SmartMirror/archive/master.zip
unzip master.zip
mv IoT_SmartMirror-master IoT_SmartMirror

Edit the smartmirror.js file:

cd IoT_SmartMirror
vi smartmirror.js

Find the OPENWEATHER_API_KEY and change it to your API key. Additionally, change the LATITUDE and LONGITUDE variables to reflect your location (don’t forget to press ‘i’ to edit text).

Updating smartmirror.js

When you are finished, press ‘esc’ and enter ‘:wq’ to save and exit. Now, we can run the smart mirror code!

export NODE_PATH=$NODE_PATH:/usr/local/lib/node_modules/
node smartmirror.js

This should cause the mirror to (slowly) refresh and begin displaying weather data (make sure nothing is blocking the APDS-9960’s sensor when you run the program). Press ‘ctrl+c’ to stop the code. Now that we know it works, it’s time to configure the Edison so that our program starts on boot.

Run at Boot

Since we want to plug in the smart mirror and have it automatically start running our script, we need to create a service that starts the script on boot. Luckily, the IoT_SmartMirror project we downloaded already has a service already written for us!

Copy the smartmirror.service file to /lib/systemd/system/:

cd ~/IoT_SmartMirror-master
cp smartmirror.service /lib/systemd/system/
systemctl daemon-reload
systemctl enable smartmirror.service

Now, you can shutdown the Edison:

shutdown

Next time you boot it up, it should start displaying weather data!

Button It Up

Attach the Power Source

Since we don’t want to keep the Edison plugged into the computer, we will use the wall adapter instead. Unplug the USB cable from the Base Block and plug the USB wall adapter into the Pi Block’s USB port (this will provide 5V to the LCD, making it brighter).

Powering the smart mirror

Before you close the shadowbox, now is a good time to make sure the Smart Mirror is working. Wait for the Edison to boot up, and the screen should refresh black (again, make sure nothing is blocking the APDS-9960 sensor). In a moment, the Edison should gather weather data and display it on the screen.

Checking the LCD

Close the Box and Attach the Gesture Sensor

Carefully close the shadowbox, and make sure the APDS-9960 is on the outside. Attach the APDS-9960 to the shadowbox’s frame with screws or foam tape.

Mounting the APDS-9960

Mount the Smart Mirror

Find a place you want to hang or hold your new smart mirror, preferably near an outlet. Plug it in, and wait for the weather update.

Smart mirror resting on a table

Once the current weather data has appeared on screen, slowly swipe your hand left or right across the sensor to change the information to the hourly forecast.

Interacting with the smart mirror

Resources and Going Further

You now have your very own interactive smart mirror! Feel free to modify the code to display other information. Can you get news headlines to show up?

Resources

Check out some of our other Edison tutorials:

Programming the Intel® Edison: Beyond the Arduino IDE

Intel's Edison module goes beyond being just another Arduino clone. Check this tutorial for advice on how to get the most out of your Edison by writing code in C++!

Loading Debian (Ubilinux) on the Edison

How to load a Debian distribution (specifically Ubilinux) onto the Edison.

SparkFun Inventor's Kit for Edison Experiment Guide

Learn how to harness the power of the Intel® Edison using JavaScript to post data to the cloud, control electronics from smartphones, and host web pages that interact with circuits.

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

GPS Logger Shield Hookup Guide

$
0
0

GPS Logger Shield Hookup Guide a learn.sparkfun.com tutorial

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

Introduction

The SparkFun GPS Logger Shield equips your Arduino with access to a GPS module, µSD memory card socket, and all of the other peripherals you’ll need to turn your Arduino into a position-tracking, speed-monitoring, altitude-observing wonder logger.

GPS Logger Shield

The shield is based around a GP3906-TLP GPS Module– a 66-channel GPS receiver featuring a MediaTek MT3339 architecture and an up to 10Hz update rate. The GPS module will stream constant position updates over a simple serial UART, which you can then log to a µSD card and/or use for other position or time-tracking purposes.

Everything on the shield is highly configurable: A switch allows you to select the GPS module’s UART interface between either hardware or software ports, the µSD card operates over a hardware SPI port, which should be compatible with most Arduino layouts, and extra prototyping space should allow you to add those last, few components you need to complete your project.

Covered In This Tutorial

This tutorial aims to document all things GPS Logger Shield related, including both the hardware and software required to get it up-and-running. It’s split into the following sections:

  • Hardware Overview– An overview of the schematic, layout, and features of the SparkFun GPS Logger Shield.
  • Hardware Setup– Tip for assembling the GPS Logger Shield to best match your project needs.
  • Example Arduino Sketches
    • GPS Serial Passthrough– A simple sketch you can use to verify functionality of your GPS Logger Shield, and get an idea of what kind of data the GP3906 GPS module produces.
    • TinyGPS++ Serial Streaming– Using the TinyGPS++ Arduino library to parse the GPS module’s NMEA strings into latitude, longitude, altitude, speed, and more.
    • µSD Card GPS Loging– Finally, we’ll plug the parsed GPS data into a CSV file and save it to a µSD card.

Suggested Materials

There are a few extra components you’ll need to get the GPS Logger Shield fully up-and-running:

Most importantly, you’ll need an Arduino or Arduino-compatible development board. The GPS’s serial and µSD SPI ports should be compatible with almost all Arduino-sized development boards. That includes classics, like the Arduino Uno and SparkFun RedBoard, and newer models, like the Arduino Leonardo, Genuino 101, and SparkFun SAMD21 Dev Breakout.

Arduino Uno - R3

DEV-11021
$24.95
60
SparkFun RedBoard - Programmed with Arduino

DEV-12757
$19.95
77
SparkFun SAMD21 Dev Breakout

DEV-13672
$24.95
Arduino Leonardo with Headers

DEV-11286
$24.95
6

We also highly recommend a 12mm Coin Cell Battery, which fits into the GPS Shield’s battery holder. The GP3906 GPS module requires some sort of voltage on its battery supply input. If you don’t have a battery, make sure you read the VBAT section of the hardware overview carefully.

Coin Cell Battery - 12mm (CR1225)

PRT-00337
$1.95
1

You’ll also need to solder some headers into the shield, to create a solid mechanical and electrical connection between it and the Arduino. We recommend the Arduino R3 Stackable Header Pack, but a set of male headers may also suit your needs.

Break Away Headers - Straight

PRT-00116
$1.5
19
Arduino Stackable Header Kit - R3

PRT-11417
$1.5
10
Female Headers

PRT-00115
$1.5
5
MicroSD Card with Adapter - 8GB

COM-11609
$13.95
2

Finally, if you intend on logging the GPS data to a µSD card, you may want to grab a µSD Card and SD Adapter. The Arduino SD library should support most µSD cards formatted with FAT16 or FAT32 file systems.

Suggested Reading

This is a beginner-level tutorial – and the GPS Logger Shield is a beginner-friendly product – but there are a few concepts you should be comfortable with before continuing on. If any of these subjects sound unfamiliar, considering reading those tutorials before continuing on.

  • GPS Basics– This tutorial is a great primer on the wonders of GPS. Learn how we get find our position on the globe by listening to (at least) four satellites send a timestamp and aerial position.
  • Serial Communication– The GP3906 communicates via a simple, serial UART. This tutorial will familiarize you with serial-related concepts like RX, TX, and baud rate.
  • How to Solder: Through-Hole Soldering– If you’ve never soldered before, now’s a great time to start, and this is a great tutorial to learn from.
  • Installing an Arduino Library– We’ll use a pair of fantastic Arduino libraries to log GPS data to an SD card.

How to Solder - Through-hole Soldering

New to electronics and soldering? Have you soldered before but need a refresher? This tutorial with cover everything you need to know about through-hole soldering.

Serial Communication

Asynchronous serial communication concepts: packets, signal levels, baud rates, UARTs and more!

GPS Basics

The Global Positioning System (GPS) is an engineering marvel that we all have access to for a relatively low cost and no subscription fee. With the correct hardware and minimal effort, you can determine your position and time almost anywhere on the globe.

Installing an Arduino Library

How do I install a custom Arduino library? It's easy!

Hardware Overview

For a quick overview of the components and features of the GPS Logger Shield, refer to the image below:

Annotated GPS Shield image

The rest of this section will dive into some of the more critical components of the shield, including power supply requirements and UART and SPI interface configurations.

Powering the GPS Logger Shield

The GPS Logger Shield’s main voltage supply is taken from the Arduino 5V header pin. This voltage is regulated down to 3.3V, which is supplied to both the GPS module and the µSD card.

These two components should consume around 30mA on average, but they may very occasionally spike to upwards of 100mA.

Logic-Level Shifting

The shield includes a TXB0108 8-Channel Level Shifter, which shifts voltage levels between the Arduino and 3.3V GPS UART and µSD SPI signals. Regardless of whether your Arduino runs at 5V or 3.3V, you shouldn’t have to concern yourself with shifting voltages between either component.

The Arduino-side logic-level voltage is set by the IOREF pin, which most Arduino development boards connect to either 5V or 3.3V.

⚡ If your Arduino board doesn't have an IOREF pin, or if no voltage is supplied on that pin, you will need to set the IOREF voltage manually. The shield includes a jumper on the back-side of the board, labeled IOREF-SEL, which you can use to set the IOREF voltage to either 3.3V or 5V.

If your Arduino board doesn't have an IOREF pin, set this jumper to match your desired logic level.

GP3906 Battery Supply (VBAT)

The GP3906 is a great, little module, but it has one, big quirk: A supply voltage between 2.0-4.3V is required on the VBAT pin. If you have a 12mm coin cell battery, supplying that voltage is as easy as pushing it into the battery socket. When you insert the battery, make sure you slot it in + side facing up.

Plugging battery into the GPS Shield

If you don’t have a battery handy, there are a few workarounds. You can grab a soldering iron, and short the 3V3-Batt jumper, next to the battery socket.

Batt/3V3 jumper closed

If you don’t have a 12mm battery, shorting the 3V3/Batt jumper will at least keep your GPS module functional.

Or you can wire the broken out VBAT pin to any voltage supply between 2.0-4.3V.

⚡ VBAT Supply Required: The GP3906 requires some form of voltage supply on its VBAT pin, whether that be an actual battery, or simply the 3.3V regulator output. If your the GPS LED isn't at least blinking (or illuminated) when the shield is powered up, that may indicate lack of supply to the VBAT port (or a dead battery).

Supplying the GP3906 with a backup battery supply ensures that its real-time clock (RTC) will continue to tick, even when the rest of the board is powered off. That allows the module to get faster GPS fixes when it initially powers up. It doesn’t consume a lot of power – we’ve measured around 5-6µA, – so a 12mm coin cell battery could keep the board “running” (in sleep mode) for about a year.

GPS Pin Breakout’s

Most of the GPS input, output, and power pins are connected to something on the GPS Logger Shield, but they’re all also broken out to this 8-pin header.

GPS Pin breakout's highlighted

Here’s a quick overview of each pin and its function:

Pin LabelIn/OutBoard ConnectionPin Description
GNDInGroundGPS module ground (0V reference)
PPSOut1 pulse-per-second time reference
ENInActive-high chip-enable – pull low to reset or turn off
RXInArduino TX/D9Serial data input
TXOutArduino RX/D8Serial data output
FIXOutGPS Fix LEDGPS fix indicator – blinks before a fix, HIGH once a fix is valid
VBATIn12mm coin cell socketBackup power – keeps the RTC running (2.0-4.3V input range)
3V3InOn-board 3.3V regulator3.3V power supply input

The PPS and EN pins are left unconnected. You’re free to wire them up to any Arduino pin should you need either a pulse-per-second signal, or extra control of the GPS module’s operation.

Selecting the Serial Port

The GPS module communicates via a simple, UART (serial) interface. The UART-select switch allows you to switch that interface between either the Arduino’s hardware UART – on pins D0 and D1 – or a SoftwareSerial port on pins D8 and D9.

UART-select switch

Should you need a reference, this table shows the map between GPS module and Arduino UART(s):

GPS PinArduino Software UART PinArduino Hardware UART Pin
RX91 (TX)
TX80 (RX)

If you’re using an Arduino Uno or any development board with one, pre-occupied hardware UART, you may be forced to use the software serial port. Fortunately, the GPS module’s baud rate defaults to a slow, steady 9600 bps, which SoftwareSerial shouldn’t have a problem handling.

If you need to move the software serial port pins, they can be custom-routed to any other pin by cutting the solder jumpers between pins GPS-RX and D8 and/or GPS-TX and D9.

Software UART-select jumpers

Once those jumpers are cut, you can wire the GPS-RX and GPS-TX pins to any other pins you’d like.

Selecting the µSD SPI Pins

On older Arduino boards, finding the SPI port was pretty simple – it’d be on pins 10-13, mapping out to CS, MOSI, MISO, and SCLK respectively. On more recent Arduino board releases, however, these pins are just as likely to be found on only the 6-pin, 2x3 SPI header. The GPS Logger Shield maps the µSD SPI pins to both of these headers, in order to support as many development boards as possible.

A trio of three-way solder jumpers can be used to modify which Arduino pins are routed to the µSD card’s SPI I/O’s.

SPI-select jumpers

The middle pad of these jumpers carries the signal to/from the µSD card. The pads toward the inside of the board carry signals to the SPI header, and the pads toward the outside carry signals to pins 10-13.

Boards that map SPI to pins 10-13 include the Arduino Uno, RedBoard, Arduino Pro's, and most ATmega328P-based boards. If you're using any of these boards, it should be safe to leave the jumper's untouched (as they're also, likely, shorted together on the Arduino).

Boards that only map SPI to the 2x3 SPI header include the Arduino Leonardo (and other most ATmega32U4-based boards), Arduino Due, and the Arduino Zero (and most ATSAMD21-based boards). On these boards, you'll need to cut the solder jumpers connecting the middle pad to the D11-, D10-, and D13-side pads.

Power and GPS Fix Status LEDs

This pair of LEDs on the corner of the shield are a handy tool for initial troubleshooting. The red PWR LED is attached to the output of the shield’s on-board 3.3V regulator. If the shield is getting power, this LED should be on.

The blue GPS FIX LED is connected the GP3906’s “3D_FIX” pin. It can be used to identify whether the GPS module has a proper fix or not. When you initially power the shield up, the LED should blink – indicating it’s trying to find a fix. Once the LED turns solidly on, you can rest assured that your GPS module has a good fix on your location.

3D Fix pin operation

The GP3906’s 3D_Fix pin operation. The LED will be on when the GPS fix is valid, and blinking at ½ Hz otherwise.

Both of these LEDs have solder jumpers underneath, should you find the need to disable either of them. A quick slice between the pads is all it takes to remove them from the circuit. This might be useful if you’re using the GPS Logger Shield in a low-power application, where even the handful of milliamps consumed by the LEDs means months off a project’s battery lifetime.

Hardware Setup

Assembly of the GPS Logger Shield mostly comes down to soldering something to all of the 6, 8, and 10-pin Arduino headers. We usually recommend Arduino R3 Stackable Headers for this job, but male headers can work – as long as this is the top board in a shield stack.

Stackable headers soldered into the shield

If your application requires use of the 6-pin, 2x3 SPI header, you may also want to solder female headers to those pins (make sure they’re pointing down, and slot easily into your Arduino’s male SPI pins).

If you’ve never soldered an Arduino shield before, check out our Arduino Shield Assembly tutorial for some tips.

Pre-Flight Checklist

Before you get the go-ahead for GPS Shield'ing, make sure you double-check these common pitfalls one last time:

Battery (VBAT) Power Supply

Make sure you have a reliable power source supplying the GPS module’s VBAT pin. If you have a shiny, new 12mm coin cell battery plugged in, that’s perfect. Otherwise, make sure you’ve either shorted the 3.3V/VBAT jumper, or are supplying something to the GPS module’s VBAT breakout.

Battery plugged in

UART Selected

Make sure you have the UART-select switch pointing towards your preferred UART. If you’re using an Uno, Redboard, or any other ATmega328P-based Arduino, you’ll most likely need to have the switch pointing towards SW-UART, assuming the hardware UART is used for programming and serial debugging.

If you're using an ATmega328-based Arduino, no matter what your sketch ends up doing, the switch must be in the SW-UART position during any programming upload.

If you’re using a Leonardo (ATmega32U4-based boards), Zero (ATSAMD21-based boards), or any other Arduino that has a dedicated and free hardware UART on pins 0/1, we recommend leaving the switch in the HW-UART position.

µSD SPI Jumpers

Planning on logging data to a µSD card? Make sure the SPI jumpers are set accordingly. If you’re using an Uno, Redboard, or any other ATmega328P-based Arduino, you can probably leave the jumpers untouched. SPI should be broken out to both pins 10-13 and the SPI header anyway.

If you’re using a Leonardo (ATmega32U4-based boards), Zero (ATSAMD21-based boards), or any other Arduino that doesn’t break the SPI signals to pins 10-13, you’ll want to cut the three SPI-select jumpers between the middle pad and the D11-D13 pins. That will free up those pins for other purposes in your project.

SPI jumpers cut for Leonardo

Looking closely, you’ll see traces cut on all three SPI lines between the middle pad and D11, D12, and D13. That disconnects the µSD lines from those pins – leaving them connected to the SPI header.

If you’re relying on the SPI port from the 2x3-pin ICSP header, don’t forget to solder headers to the SPI port!

Example Sketch: GPS Serial Passthrough

Now that your hardware is all set up, we have three pieces of example code to give you a taste of the GPS Logger Shield’s functionality. This first example isn’t all that useful, but it will, at least, make sure everything’s working. Plus it’ll show you the raw ugliness of NMEA GPS strings and make you appreciate great libraries like TinyGPS even more.

This example doesn’t require any additional libraries. Simply plug the shield into your Arduino and upload the example code. We’ve got a couple examples, depending on which Arduino and/or serial port you’re using.

Codebender Examples: 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.

If the codebender embeds don't work for you, we'll also provide a download link to the example code.

SoftwareSerial Port Example

If you’re using an Arduino Mega, Arduino Uno, Redboard, any other ATmega328P-based Arduino, and have the UART-select switch in the SW-UART position, upload this piece of example code to your Arduino:

If the codebender embed doesn’t load for you, you can download the example code from our GitHub repository.

This example uses the SoftwareSerial library to communicate with the GPS module, and leaves the hardware serial port for debugging with the serial monitor.

Hardware Serial Port Example

If you’re using an Arduino Leonardo, Arduino Due, Arduino Zero, or any other Arduino with a free UART on pins 0/1, set the UART-select switch to HW-UART, and upload this example:

If the codebender embed doesn’t load for you, you can download the example code from our GitHub repository.

You may have to alter either or both of the serial port #defines at the top of the code. Refer to your development board’s datasheet or product info page for more information on which serial port is which.

Using the Serial Passthrough Sketch

Once you’ve uploaded the sketch, open up your serial monitor and set the baud rate to 9600. You should immediately begin to see GPS NMEA data begin to flow by at a rate of 1Hz.

For example, one set of strings may look like:

$GPRMC,235316.000,A,4003.9040,N,10512.5792,W,0.09,144.75,141112,,*19
$GPGGA,235317.000,4003.9039,N,10512.5793,W,1,08,1.6,1577.9,M,-20.7,M,,0000*5F
$GPGSA,A,3,22,18,21,06,03,09,24,15,,,,,2.5,1.6,1.9*3E

If you don’t see anything in the serial monitor, make sure the UART-select switch is in the correct position. Also double check that the blue “GPS Fix” LED is at least blinking. If it’s not, the module may not be receiving power. Don’t forget to supply VBAT!

If you’re still not having any luck, get in touch with our technical support team.


NMEA strings are the standard message format produced by almost all GPS receivers. They can relay all sorts of information including the time, latitude, longitude, altitude, and number of satellites visible, but unless you’re an incredibly fast parser, these sentences will mostly mean nothing. Fortunately, the Arduino can read those strings, parse them for you, and give you more human-readable pieces of data.

Example Sketch: TinyGPS Serial Streaming

A couple of our favorite GPS-parsing Arduino libraries are TinyGPS and TinyGPS++. These libraries simplify the task of parsing the excessive NMEA strings, leaving us with just the few bits of data we care about.

The TinyGPS libraries are built into codebender, which we’ll continue to use. If you’d like to install the libraries on your own Arduino development machine, visit the links above to download them. Reference our Installing an Arduino Library tutorial for any additional library-installing help you may need.

TinyGPS++ Example

Here’s a quick example, which uses the TinyGPS++ library to parse NMEA strings for position, altitude, time, and date. The code is also available in our GPS Shield GitHub repository, if the embed doesn’t work for you.

You may need to adjust the gpsPort and SerialMonitor defines near the top of the sketch. As it is, the sketch is set up to use the SoftwareSerial port.

After uploading the code, open up your serial monitor to watch the parsed GPS data stream by:

If your module doesn’t have a good GPS fix, you’ll probably see a lot of 0’s stream by; the time should be incrementing, although it’ll be incorrect (unless you plugged your Arduino in at exactly midnight!).

If you can find a way to take your computer and Arduino setup outside, that’ll be your best bet for getting a fix. Otherwise, try to take it near an open window. The better view it has of the sky, the better chance it’ll have to find the four satellites it needs.

A successful, fixed GPS stream will look something like this:

Lat: 40.090422
Long: -105.184534
Alt: 5243.77
Course: 295.56
Speed: 0.01
Date: 26/1/2016
Time: 20:19:34
Sats: 6

For more information on using the TinyGPS++ Library, check out the project homepage.

Example Sketch: µSD Card GPS Logging

Now that we have good GPS data, the final step is to start logging it to a µSD card.

Like the last example, this sketch uses TinyGPS++, it also uses Arduino’s built-in SD library.

The code is hosted on codebender and embedded below. If the embed below doesn’t load for you, check out the example code in our GitHub repository.

You may need to edit the gpsPort and SerialMonitor objects, toward the top of the code to get the example to work correctly on your Arduino. The sketch defaults to using SoftwareSerial for the GPS, which should work for most boards – as long as the UART-Select switch is shifted towards SW-UART.

Before uploading the code, plug a µSD card into your GPS Logger Shield. Push it in gently until you hear a click. Then release, and let it latch into place.

uSD card plugged into the shield

Once that’s in place, upload and run! You can check the serial monitor for debugging data, or just trust that the logger is logging.

Once the GPS module gets a good fix, the Arduino will start logging longitude, latitude, altitude, speed, course, date, time, and the number of visible satellites into a CSV file. The data is set to log once every five seconds, but that’s easily tunable if you need more or less data.

After letting it log for a bit, turn off your Arduino, load the SD card into your computer, and check for a GPSLOG###.CSV file. Open it up in a spreadsheet program, or just use a text editor to see what your Arduino logged.

CSV example screenshot

Now really test the logger! Power your Arduino up with a battery (our 9V to Barrel Jack Adapter is handy for that)…

Battery-powered Arduino/GPS Shield

…and take your Arduino for a walk.

Resources & Going Further

Now that you’ve got your GPS Logger Shield up-and-running, what kind of position-tracking Arduino project are you going to make. Need a little more guidance, here are a few links you may find handy:

If you need a little project inspiration, here’s a SparkFun Live, where you can watch the full build of a GPS Speedometer:

Or check out some of these related SparkFun tutorials:

Copernicus II Hookup Guide

A guide for how to get started with the Copernicus II GPS module.

Weather Shield Hookup Guide

Read humidity, pressure and luminosity quickly and easily. Add wind speed, direction and rain gauge for full weather station capabilities.

Alphanumeric GPS Wall Clock

This is a GPS controlled clock - a clock you truly never have to set! Using GPS and some formulas, we figure out what day of the week and if we are in or out of daylight savings time.

CAN-Bus Shield Hookup Guide

A basic introduction to working with the CAN-Bus shield.

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

BadgerHack: Gaming Add-On Kit

$
0
0

BadgerHack: Gaming Add-On Kit a learn.sparkfun.com tutorial

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

Introduction

The BadgerStick that you received by visiting a SparkFun booth at one of the various events we’ve attended can be hacked to perform a wide variety of tasks. The display may be small (don’t get your hopes up of running Doom on an 8x7 monochrome display). However, we can use it to display information and even play some basic games.

BadgerHack

This tutorial will guide you through turning your BadgerStick into a micro gaming system. Remember the game Breakout? Let’s make a Breakout clone on our BadgerStick by adding a joystick and some buttons!

Breakout on the Badger

NOTE: The BadgerStick and RedStick are two different products. The BadgerStick (aka BadgerHack) originated as an event-only platform to aid SparkFun in teaching soldering and programming at events like Maker local Faires and SXSW. The RedStick evolved from that concept and is the retail version of the BadgerStick, available for sale on SparkFun.com. All of the BadgerStick tutorials and expansion kits are compatible with both the BadgerStick and the RedStick, unless otherwise stated.

Required Materials

We will need a few other components to make a simple controller for the BadgerStick.


Heads up! At the time of this writing, the LED Matrix is only available at events where SparkFun is hosting workshops. For those who wish to follow along with their ReStick, a compatible version of the LED matrix will be available for sale on the SparkFun website in the near future.

Suggested Reading

Before starting this tutorial, we highly recommend you work through the main BadgerHack guide first.

BadgerHack

September 23, 2015

This tutorial shows users how to solder their SparkFun interactive badges as well as put them to use in other projects.

Additionally, if you are new to soldering or electronics, we recommend you check out the following:

When you are ready to start hacking your badge, we definitely recommend reading:

Hardware Hookup

To begin, snap off 15 pins from the break-away headers, and solder them to the through-holes on the side opposite the LED array of the BadgerStick.

Solder pins to the BadgerStick

Solder the Thumb Joystick to the Thumb Joystick Breakout board.

Solder joystick to breakout board

Snap off 5 pins from the break-away headers, and solder them to the through-holes on the Joystick Breakout Board.

Solder pins to joystick breakout board

Connections

Place the BadgerStick in the breadboard with pin 10 in position i13 and pin 5V in position i27.

Connect the rest of the components as follows:

ComponentBreadboard
Thumb Joystick Breakout*i7 (VCC)i6 (VERT)i5 (HOR)i3 (GND)
Pushbuttonc20c22f20f22
Pushbuttonc28c30f28f30
Jumper Wire( - )g30
Jumper Wire( - )g25
Jumper Wire( - )g22
Jumper Wire( - )j3
Jumper Wirej7g23
Jumper Wirej6g18
Jumper Wirej5g17
Jumper Wireg21g28

* Pins not listed are not used.


Gaming Badger Fritzing diagram

Wire colors correspond to the colors of the table above.

IMPORTANT: You can leave the battery pack soldered into the BadgerStick if you desire. If you remove the battery pack, you will need to supply power through another means, such as a USB port or a USB extension cable.

You should now have a makeshift game controller with a tiny LED screen!

Gaming badger with batteries

The Code

Plug the USB side of your BadgerStick into your computer. Make sure “BadgerStick” and the associated COM port are selected in the window below. Click “Run on Arduino.”

Play

Once the sketch has been uploaded, prepare to play!

Use the joystick to move the paddle back and forth to bounce the ball. You win when you “break” all the lights on the top part of the screen. You lose if you let the ball go past your paddle.

Let's play Breakout!

Resources and Going Further

You might notice that we do not use the 2 buttons in the game. Breakout only requires a joystick. However, you now have a basic platform that is perfect for creating games!

What other games would you want to make? Here are some ideas:

If you make something cool with your Badger, share it with #BadgerHack, or create a tutorial on hackster.io.

Resources

Other BadgerHack Projects

Check out some of the other things you can make with the Badger:

New!

BadgerHack: Sensor Add-On Kit

February 16, 2016

Turn your Badger or Redstick into a temperature and soil moisture sensing display with the BadgerHack Sensor Add-On Kit


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

BadgerHack: Sensor Add-On Kit

$
0
0

BadgerHack: Sensor Add-On Kit a learn.sparkfun.com tutorial

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

Introduction

The BadgerStick that you received by visiting a SparkFun booth at one of the various events we’ve attended can be hacked to perform a wide variety of tasks. The BadgerStick is a fully capable microcontroller that can sense the environment around it.

BadgerHack

This tutorial will guide you through turning your BadgerStick into an environment sensing station. We’ll do so by adding a temperature sensor and a soil moisture sensor.

SparkFun BadgerStick and Sensor add-on kit with plant

Plant not included

NOTE: The BadgerStick and RedStick are two different products. The BadgerStick (aka BadgerHack) originated as an event-only platform to aid SparkFun in teaching soldering and programming at events like Maker local Faires and SXSW. The RedStick evolved from that concept and is the retail version of the BadgerStick, available for sale on SparkFun.com. All of the BadgerStick tutorials and expansion kits are compatible with both the BadgerStick and the RedStick, unless otherwise stated.

Required Materials

On top of your Badgerstick/Redstick and LED array display you will need a few more parts for this project:


Heads up! At the time of this writing, the LED Matrix is only available at events where SparkFun is hosting workshops. For those who wish to follow along with their ReStick, a compatible version of the LED matrix will be available for sale on the SparkFun website in the near future.

Suggested Reading

Before starting this tutorial, we highly recommend you work through the main BadgerHack guide first.

BadgerHack

September 23, 2015

This tutorial shows users how to solder their SparkFun interactive badges as well as put them to use in other projects.

Additionally, if you are new to soldering or electronics, we recommend you check out the following:

When you are ready to start hacking your badge, we definitely recommend reading:

Hardware Hook-up

There is a little bit of soldering, so if you need a quick refresher on that I suggest taking a look at our soldering tutorial.

To begin, snap off 15 pins from the break-away headers, and solder them to the through-holes on the side opposite the LED array of the BadgerStick.

BadgerStick with headers

You can place the headers in the breadboard to help keep them in place as you solder.

Soldering BadgerStick with breadboard

The rest of the setup will be using the breadboard and the jumper wires.

Start by sticking the headers you just soldered to your stick at a corner of your breadboard.

Now we will connect the sensors as follows:

Component PinBadger/Redstick Pin
Soil Moisture Sensor VCCVCC
Soil Moisture Sensor GNDGND
Soil Moisture Sensor SIGA0
Temperature Sensor leftGND
Temperature Sensor middleA4
Temperature Sensor rightVCC

* Pins not listed are not used.


Here is a picture layout of how to connect everything up

Fritzing Diagram of badgerstick badgerhack add-on kit hookup

Fritzing diagram of a RedStick hookup (GND and VCC slightly different on a BadgerStick).

SparkFun BadgerStick and Sensor Add-on kit layout

IMPORTANT: You will need to power your Badgerstick/Redstick through its USB port or a USB extension cable, so that the analog sensors are getting a known voltage. You can cut the battery pack off, you can leave the battery pack attached but turned off, or you can power it through the battery pack. Just know that your temp reading will become less accurate the more your battery drains.

With everything hooked up, it’s time to upload some code.

Code

Analog sensors work by providing a voltage output that is proportional to the what they are measuring. This means with something like analog temp sensor we are using, the output voltage can be converted to temperature easily using the scale factor of 10 mV/°C. However, a little bit of math is required depending on what the input voltage is, so that will change based on if you are using the Badgerstick at 3.3V or the Redstick at 5V. (But don’t worry, this has already been done for you in the code.)

The soil moisture sensor works the same way, but we are leaving the data as is, since converting it to something usable like kg of water per kg or soil would be very difficult without knowing what kind of soil you have and how it reacts to electricity.

Plug the USB side of your BadgerStick into your computer. Make sure “BadgerStick” and the associated COM port are selected in the window below. Click “Run on Arduino.”

If you have the Redstick Make sure “Arduino Uno” and the associated COM port are selected in the window below. Click “Run on Arduino.” Also if you are using a Redstick, you will need to go into the code and change one variable at the end to have the correct temp output (instructions in the code).

Resources and Going Further

With that, you should have an environment sensing station over which you have full control.

If you make something cool with your Badger, share it with #BadgerHack, or create a tutorial on hackster.io.

Like sensors? Here are a few more sensors that are pretty cool:

FLiR Dev Kit

KIT-13233
$259.95
16
9 Degrees of Freedom - Razor IMU

SEN-10736
$74.95
7
SparkFun Load Cell Amplifier - HX711

SEN-13230
$9.95
13
SparkFun 9 Degrees of Freedom IMU Breakout - LSM9DS1

SEN-13284
$24.95
2

Resources

Other BadgerHack Projects

Check out some of the other things you can make with the Badger:

New!

BadgerHack: Gaming Add-On Kit

February 16, 2016

Make a Breakout clone with the BadgerHack Gaming Add-On Kit.


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

BadgerHack: Synth Add-On Kit

$
0
0

BadgerHack: Synth Add-On Kit a learn.sparkfun.com tutorial

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

Introduction

The BadgerStick that you received by visiting a SparkFun booth at one of the various events we’ve attended can be hacked to perform a wide variety of tasks. It can even make music, depending on your definition of music.

BadgerHack

This tutorial will guide you through turning your BadgerStick into a little noise-making circuit that’s easy to build, easy to program, and easy to alter and make your own!

BadgerStick with Synth Add-on

It looks a little messy, but it sounds pretty… okay, it doesn’t sound pretty either, but it is a lot of fun!

Follow along with this guide and you’ll be making sweet noise in no time!

NOTE: The BadgerStick and RedStick are two different products. The BadgerStick (aka BadgerHack) originated as an event-only platform to aid SparkFun in teaching soldering and programming at events like Maker local Faires and SXSW. The RedStick evolved from that concept and is the retail version of the BadgerStick, available for sale on SparkFun.com. All of the BadgerStick tutorials and expansion kits are compatible with both the BadgerStick and the RedStick, unless otherwise stated.

Required Materials

We will need a few other components to make this thing work:

As you can see, the parts count is pretty low and none of the components we’ll be using are very sophisticated. The BadgerStick (or RedStick) is doing all of the heavy lifting here. We just need a few control surfaces and a speaker.


Suggested Reading

Before starting this tutorial, we highly recommend you work through the main BadgerHack guide first.

BadgerHack

September 23, 2015

This tutorial shows users how to solder their SparkFun interactive badges as well as put them to use in other projects.

Additionally, if you are new to soldering or electronics, we recommend you check out the following:

When you are ready to start hacking your badge, we definitely recommend reading:

Hardware Hookup

Badger on a Breadboard

The BadgerStick is a great form factor for breadboard prototyping. If you have a fresh BadgerStick or RedStick out of the box, you can add male breakaway headers to both sides and sink it right into the breadboard over the gap. Make sure to add headers to pins A0 through VCC and pins 2 through 9. The holes on the BadgerStick are staggered so that the headers will stay in place while you solder them, simply snap off two strips of 8 headers and press them into place before securing them with a series of solder joints.

I’m going to assume for the purposes of this tutorial, however, that you’ve already assembled the BadgerStick into an interactive badge and therefore already have female right-angle headers installed on pins 2 through 9. You can use male right angle headers to mate your BadgerStick/RedStick to the breadboard instead of having to desolder those headers. Alternatively, you can desolder the headers and replace them with straight male headers.

Solder pins to the BadgerStick

This picture isn’t exactly right but you get the idea

A Jungle of Jumper Wires

A pack of jumper wires on our site contains 30 jumpers. Today, we’re going to be using every single one of those. Start by placing all of your parts on the breadboard like this:

Place parts on the breadbaord

Potentiometers, DIP Switch, and BadgerStick on Breadboard.

The potentiometers in the above picture don’t look like the ones I suggested in my wishlist, but they’ll work the same way. Now, with the jumper wires, begin making the connections listed here:

Connect this:To This:
DIP Switch Pins 1-8BadgerStick Pins 2-9
All Potentiometers' Pin 1GND Rail of Breadboard
All Potentiometers' Pin 3VCC Rail of Breadboard
All Potentiometers' Pin 2BadgerStick A0-A3
Speaker Pin 1BadgerStick A4
Speaker Pin 2BadgerStick A5
GND Rail of BreadboardBadgerStick GND
VCC Rail of BreadboardBadgerStick VCC

Once these connections have been made, your breadboard should look more or less like the image below. I did use a larger breadboard just so that there was enough room to clearly illustrate each jumper connection:

All jumper connections have been made on the breadboard

All jumper connections have been made on the breadboard.

That wraps up the hardware portion of this hack, let’s go take a look at the code!

Code

Plug the USB side of your BadgerStick into your computer. Make sure “BadgerStick” and the associated COM port are selected in the window below. Click “Run on Arduino.”

Note: If you have the Redstick, make sure to instead selecte “Arduino Uno” in the window below.

This code steps through each pin on the DIP switch, reading the input to the BadgerStick. If a switch is open, the BadgerStick will make a noise based on the potentiometer inputs. Changing the potentiometers will change the random tones created by the BadgerStick.

Resources and Going Further

That’s it! Go forth and make noise!

The code we’ve provided for you is the bare bones of a step sequencer, but there are a lot of sweet hacks and mods that you can make to get more functionality out of it. For more information on step sequencing with Arduino, check out my Auduino Step Sequencer Build.

If you make something cool with your Badger, share it with #BadgerHack, or create a tutorial on hackster.io.

Resources

Other BadgerHack Projects

Check out some of the other things you can make with the Badger:

New!

BadgerHack: Sensor Add-On Kit

February 16, 2016

Turn your Badger or Redstick into a temperature and soil moisture sensing display with the BadgerHack Sensor Add-On Kit

New!

BadgerHack: Gaming Add-On Kit

February 16, 2016

Make a Breakout clone with the BadgerHack Gaming Add-On Kit.

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

Viewing all 1123 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>