Basic Home Automation With an IR LED and Receiver

Controlling devices that have infrared remotes is an easy and low-cost form of home automation, so I decided to make a YouTube tutorial video about it. I'm using the "IRremote" library by Ken Shirriff, and wrote some firmware that uses an IR receiver and an IR LED as a computer-controlled universal remote. The end result was being able to press a key on my keyboard, and having household decives respond accordingly. I set it up so i can turn my TV and tower fan on or off.

After installing the IRremote library, the firmware is pretty simple:

#include <IRremote.h> IRrecv receiver(2); // receiver is connected to pin2 IRsend sender; decode_results results; long repetitions; long count; unsigned int durations[100]; void (*reset)(void) = 0; void setup() { Serial.begin(9600); receiver.enableIRIn(); // start receiving signals } void loop() { // check for text from the PC // the PC sends a string containing "r,n,a,b,c,d,e,..." where r is how many times to repeat the command, // n is the number of durations, and a/b/c/d/e/... are the durations. // the durations are how long each mark and space period of an infrared command should last, in microseconds. if(Serial.available()) { // parse the text repetitions = Serial.parseInt(); count = Serial.parseInt(); for(int i = 0; i < count; i++) durations[i] = Serial.parseInt(); // send the command using 40kHz PWM for(int i = 0; i < repetitions; i++) { sender.sendRaw(durations, count, 40); delay(50); } // for a bit of fault tolerance, reset the arduino after receiving any command reset(); } // check if a decoded infrared signal is available if(receiver.decode(&results)) { Serial.println(results.value, HEX); Serial.print(results.rawlen - 1); for(int i = 1; i < results.rawlen; i++) { unsigned int number = results.rawbuf[i] * USECPERTICK; Serial.print(","); Serial.print(number); } Serial.println(""); receiver.resume(); } }

If you aim a remote at the IR receiver and press a button, details about that waveform will be printed to the serial port. To have the Arduino send that IR command, just send that text back to the Arduino, but add a number and comma to the beginning. That number specifies how many times to repeat the command. Some protocols, like Sony's, require a command be sent three times. So you would send "3," followed by the text the Arduino printed out.

We now have the hardware and firmware all setup, but it's a pain to send those IR commands (copy-and-pasting text into the Serial Monitor.) We can create some batch files to automate the sending of text to the Arduino. These will need to be adjusted for your IR commands and COM port, but for me it was:

fan_on_off.bat

mode COM3 baud=9600 parity=n data=8 stop=1 echo "1,23,1200,450,1250,400,400,1300,1200,450,1200,450,400,1250,400,1250,400,1300,350,1300,400,1250,400,1250,1250" > COM3

tv_on_off.bat

mode COM3 baud=9600 parity=n data=8 stop=1 echo "3,25,2400,600,600,600,1150,600,1200,600,1150,650,1150,600,1150,650,550,600,1200,600,600,600,550,660,600,600,600" > COM3

By default the Arduino will reset immediately after you connect to it's serial port, so that needs to be disabled. I show how in the video, you just need to cut a trace on the PCB. After that, double clicking on those batch files will send the IR commands.

I used AutoHotKey to have key presses trigger those batch files. A simple script tells AutoHotKey to turn my tv on/off if I press F12, and turn my fan on/off if I press F11:

f12:: Run, C:\Users\FarrellF\Desktop\tv_on_off.bat Return f11:: Run, C:\Users\FarrellF\Desktop\fan_on_off.bat Return

See the video for more details.

This is the infrared LED and receiver that I used in the first part of the video: http://amzn.to/2lZ7pTy

For a higher-power LED: http://amzn.to/2lZ6oLk

Building a Balancing Robot from Start to Finish

Almost three years ago I made my first balancing robot but it didn't perform very well. A few months ago I decided to give it another shot and record videos of the whole process from start to end. The end result was a robot that could balance very well, didn't drift very much, and was fun to drive around.

The first part of this journey involved modifying a pair of RC hobby servos. I removed the pin on the output gear to allow for continuous rotation, and I also disabled the internal servo control circuitry. Four wires now exit each servo: two for power, and two for driving the H-bridge externally.

In the video below I show two ways to modify servos: the first way allowed the servo to still be controlled with a servo signal. The second way allowed for controlling the h-bridge externally so you have better control over the motor. I also explained some the theory behind the h-bridge and how to use PWM signals to control it. Lastly, I showed how to mount an RC airplane wheel to the servo so it can be used to power small robots.

Then I built a chassis for the balancing robot. Some 1/4" brass square tube was used to form the chassis. It was cut to length with a Dremel, deburred with some needle files, and soldered together. The end result was a strong chassis that was easy and cheap to build:

Next I needed a sensor module for determining the robot's orientation. I used a GY-86 10DOF sensor breakout board. The board contains an InvenSense MPU6050 gyroscope / accelerometer, a Honeywell HMC5883L magnetometer and a Measurement Specialties MS5611 barometer. Here's a video showing the first steps of how to interact with those sensors:

The readings from the gyro and accelerometer needed to be combined in order to reliably calculate the orientation of the robot. I used Madgwick's filter because it works very well and is easy to use. There are only two filter settings that require attention: the gain, and the sample frequency. To help visualize the sensor fusion, I also wrote a very basic Java program using the Java3D and jSerialComm libraries. It shows a 3D cube rotating based on the quaternion output of the filter.

With orientation detection and motor control done, it was time to add wireless control. I used some TI CC2500 2.4GHz RF Modules. The video below starts with a short demo driving the robot around with a crude proportional-only control loop. Then I briefly covered the CC2500 datasheet, with explanations of the state diagram, the chip status byte, and a few other aspects of the chip. Finally I showed TI's SmartRF Studio software which makes it very easy to generate correct register values for a variety of RF configurations.

By far the largest fraction of time spent on this project involved writing a program to visualize live telemetry data received from the robot over a Bluetooth link. Since this tool will be helpful for countless other projects, I spent a lot of time to make it as reusable and helpful as possible. Telemetry is received via UART (wired or Bluetooth SPP) and the data can be visualized as: line charts (time domain), line charts (frequency domain), histograms, and as simple dials/gauges. The dial visualization also shows some basic statistics: min, max, mean, and standard deviation.

The only task remaining was to write and tune a PID control loop for the balancing robot. This last video starts with a brief demo of how the robot performs with a tuned PID control loop. The balancing robot does not have any wheel encoders or other position feedback, so the only control loop inputs are the pitch of the robot and the throttle input from the user. Because of that, the robot can drift a little if it picks up speed, but even so, with a properly tuned PID control loop it performs fairly well.

To demonstrate how to develop a PID control loop I showed how the robot behaves with proportional-only control, then PI control, then full PID control. With all three steps I demonstrated what happens if the gain is set too low or too high. I also showed the telemetry waveforms during the entire tuning process so you can see in detail how things change along the way.

Source code for the firmware is available here:
https://github.com/farrellf/Balancing_Robot_Firmware/blob/master/main.c?ts=4

Source code for the telemetry viewer software is available here:
https://github.com/farrellf/TelemetryViewer

Lattice MachXO2 Breakout Board HelloWorld with Diamond

Lattice offers a cheap and simple development board for their MachXO2 FPGA. It's just a breakout board with an FPGA, a couple voltage regulators, and an FTDI FT2232 to handle the JTAG stuff. The board is around $25 - $30 from the usual suppliers (Mouser, DigiKey, etc.) This post is my collection of notes for the Lattice Diamond toolchain. I'll cover the basics of setting up a project, simulating it, programming it to Flash or SRAM, and introduce the embedded logic analyzer tool. To keep this post reasonably short, the project is intentionally trivial. A counter is created and setup to only count up when the user holds down a push button. The 8 MSbits of the count are displayed on the 8 LEDs of the development board.

Some Useful Links

http://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/MachXO2BreakoutBoard.aspx
Product page for the development board.

http://www.latticesemi.com/Products/FPGAandCPLD/MachXO2.aspx
Product page for the MachXO2 FPGA

http://www.latticesemi.com/view_document?document_id=43937
User's Guide for the development board. It has the schematic, BoM, and a general explanation of the board.

http://www.latticesemi.com/latticediamond
Lattice Diamond (IDE) product page. You'll need to register with Lattice. It's free. Register with a valid e-mail address because they email your license file.

http://www.latticesemi.com/view_document?document_id=51417
Lattice Diamond 3.6 Tutorial. A great introduction that walks you through the basics of the IDE.

http://www.latticesemi.com/view_document?document_id=51419
Lattice Diamond 3.6 User's Guide.

http://www.latticesemi.com/view_document?document_id=51424
Lattice Reveal 3.6 User's Guide. Reveal is their embedded logic analyzer tool.

http://www.latticesemi.com/~/media/LatticeSemi/Documents/DataSheets/MachXO23/MachXO2FamilyDataSheet.pdf
Lattice MachXO2 datasheet. It covers the usual stuff: the family of chips, what's possible, overview of how things work, electrical characteristics, timing, etc.

http://www.latticesemi.com/view_document?document_id=39080
Lattice MachXO2 sysCLOCK PLL Design and Usage Guide. You'll need to instantiate the internal RC oscillator for most projects, and that's covered on pages 28-30.


There are lots of other useful documents, but the ones linked above will get things started. Be sure to check out the Documentation sections on the MachXO2 and Diamond product pages.

Install Lattice Diamond

  1. Download Diamond from the link above. Run the installer and let it install all drivers.
  2. Open Diamond. The first time you launch it, there will be two errors regarding a missing license file. Click OK both times.
  3. When the License Debug window pops up, go to the License Information tab. Note your NIC ID near the bottom of that tab.
  4. Go to http://www.latticesemi.com/Support/Licensing/DiamondAndiCEcube2SoftwareLicensing/DiamondFree.aspx and enter your NIC ID (without the colons between bytes.)
  5. Close the License Debug window by clicking OK.
  6. A "license.dat" file will be emailed to you, place it inside C:\lscc\diamond\3.6_x64\license
  7. Restart your PC. Yes, this really seems to be required. If you don't, Diamond will repeatedly fail to find the license file.

Create a New Project

  1. Open Diamond.
  2. Create a new project:
    File > New > Project Next > give it a name and choose a better project location > Next > Next Pick your device. The XO2 Breakout Board has a LCMXO2-7000HE-4TG144C Next > Next > Finish

Write the Code

  1. Create a top file:
    File > New > File Verilog Files > name it "top" > New
  2. Write some code:
    module top (leds, pushbutton); output wire [7:0] leds; input wire pushbutton; wire fpga_clock; OSCH #(.NOM_FREQ("133.00")) rc_oscillator(.STDBY(1'b0), .OSC(fpga_clock)); slow_counter counter(.clock(fpga_clock), .enable(pushbutton), .output_byte(leds)); endmodule module slow_counter (clock, enable, output_byte); input wire clock; input wire enable; output reg [7:0] output_byte; reg [31:0] counter; initial begin output_byte = 8'b11111111; counter = 32'b0; end always @(posedge clock) begin if(enable == 1'b1) begin counter <= counter + 1'b1; output_byte <= ~counter[31:24]; end end endmodule
  3. Synthesize the code to make sure there are no errors. A green checkmark indicates success.
    Process tab > double-click on Synthesize Design

Simulate

  1. Create a testbench file:
    File > New > File Verilog Files > name it "testbench" > New
  2. Write some code that simulates a user holding down the pushbutton for one second:
    `timescale 1 ns / 1 ns module testbench; reg pushbutton; wire [7:0] leds; top dut(.leds(leds), .pushbutton(pushbutton)); initial begin pushbutton = 0; #1000000000 // 1s pushbutton = 1; #1000000000 // 1s pushbutton = 0; #1000000000 // 1s $finish; end endmodule
  3. Mark top.v for "synthesis and simulation" and mark testbench.v for "simulation"
    File List > impl1 > Input Files > top.v > right-click > Include for > Synthesis and Simulation File List > impl1 > Input Files > testbench.v > right-click > Include for > Simulation
  4. Run the simulation. It will take a while to run because three seconds of time will be simulated. Most simulations run for just a few microseconds, but this is a long run due to the intentionally slow behavior of the LEDs.
    Tools > Simulation Wizard Next > give it a name > Next > Next > Next > Next > Finish Aldec Active-HDL will run but defaults to pausing the simulation after 1us. Simulation > Run > OK
  5. Zoom the waveform to see all of it. Observe the LEDs slowly changing over time. Note that it looks like a count-down but in real life it will look like a count-up because the LEDs are wired active-low on the PCB.
    Waveform > Zoom to Fit

Assign Pins and Generate the Bitstream File

  1. Re-synthesize the code.
    Process tab > double-click on Synthesize Design
  2. Open the Spreadsheet View and assign pin numbers:
    Tools > Spreadsheet View Assign the "leds" nets to the pins for the LEDs. (Pin numbers are on page 13 of the dev board user guide.) Assign the "pushbutton" net to pin 3.
  3. If you want to look at reports, enable the ones you want:
    Process tab > Map Design > check "Map Trace" Process tab > Place and Route Design > check "Place and Route Trace" Process tab > Place and Route Design > check "I/O Timing Analysis"
  4. Generate a "JEDEC File" if you want to program to flash, and/or generate a "Bitstream File" if you want to program to SRAM.
    Process tab > Export Files > check "JEDEC File" Process tab > Export Files > check "Bitstream File" Double-click on Export Files. This will generate the files and perform all prerequisite functions.

Program to Flash or SRAM

  1. Program to flash:
    Tools > Programmer Detect Cable Pick the "...Lattice FTUSB Cable Interface A..." device > OK Device = "LCMXO2-7000HE" File Name = your .jed file (The .jed file will be in the "impl1" folder inside your project folder.) Design > Program
  2. Optionally change to SRAM programming mode:
    Double-click below "Operation" Access Mode = Static RAM Cell Mode Operation = SRAM Erase, Program, Verify Programming File = your .bit file (The .bit file will be in the "impl1" folder inside your project folder.) OK Design > Program

Embed a Logic Analyzer

  1. Open Reveal Inserter and specify what signal(s) to "probe" and specify what signal will clock the logic analyzer. I'm probing the counter's enable signal (the pushbutton) and the counter's internal 32bit count. I'm clocking the logic analyzer with the 133MHz FPGA clock.
    Tools > Reveal Inserter Drag-and-drop any signals you want to probe from the Design Tree over to the Trace area of the Trace Signal Setup tab. Drag-and-drop your clock signal over to the Sample Clock box of the Trace Signal Setup tab.
  2. Specify what signal(s) to trigger off of in the Trigger Unit section. Specify a trigger expression in the Trigger Expression section. I'm triggering off of a rising edge on the counter's enable signal. I don't need a complicated expression, so I just specify the trigger unit as the expression.
    Click on the Trigger Signal Setup tab In the Trigger Unit area: Double-click below Signals Choose the counter's enable signal, click the ">" button, click OK Set Operator to Rising Edge Set Value to 1 In the Trigger Expression: Set Expression to TU1
  3. Check for errors, then embed the logic analyzer into the project:
    Debug > Design Rule Check Look at the Output tab at the bottom of the window for "Design Rule Check PASSED." Debug > Insert Debug OK > Specify a filename for the Reveal project > Save
  4. Re-generate the JEDEC and/or Bitstream files, then re-program the FPGA:
    Double-click on "Export Files" in the Process tab. Tools > Programmer Design > Program

Use the Logic Analyzer

  1. Open and setup Reveal Analyzer:
    Tools > Reveal Analyzer Click "Create A New File" > give it a name Click "Detect" Click "Scan" Click "Browse" > pick the .rvl file you saved earlier > OK OK
  2. Start the logic analyzer:
    Click the Run icon (looks like a play symbol) next to Ready "Ready" will change to "Connecting" then "Running" It's now waiting for a trigger. Press the pushbutton to trigger it.
  3. You can zoom the waveform with Ctrl-scrollwheel.
  4. You can change the radix of a multi-bit signal by clicking in the Data column.
  5. You can re-arm the logic analyzer by clicking the Run icon (play symbol) again.

YouTube Video

Servo Tester / 2.4GHz Spectrum Analyzer / Tetris

Back in 2012 I started working with the STM32 line of microcontrollers and my first big project was a servo tester. That project worked out great and the tool I made has been in use for the last two years. Recently I decided to update the project and expand upon it. I added a color LCD with touchscreen, voltage and current sensing, a 2.4GHz spectrum analyzer, and for fun I decided to implement a simple version of Tetris. The end result:

It took quite a bit of work to get this project done. The prototype was a mess of jumper wires and breakout boards. I also started out with push buttons for the user interface but switched to using the touchscreen in an effort to keep things simple.

Here's a short video clip of me testing the Tetris game:

This project marked the first time I have ever had a PCB professionally fab'd. I was very relieved and pleased when everything worked perfectly with the first PCB revision. After I got the PCBs in the mail I checked them over, assembled one board, flashed the firmware... and it worked!

I bought a project box, Dremel'd and filed it to shape, then hot glued the electronics in place:

I'll post a video clip and the firmware within the next day or two.

A Complete STM32F0 Development Environment

This post expands on (and updates) a few of my earlier posts about developing for the STM32F0 microcontroller. Some parts have become easier and I've found a few more useful ways to get things done. Some of the commands below assume a Debian-based Linux distribution, but should be reworkable for your particular setup.

Let's start by making some directories for the STM32 tools and projects:

$ mkdir ~/stm32 $ mkdir ~/stm32/projects

Installing the Toolchain

The GCC ARM Embedded package is a collection of utilities (compiler, assembler, libraries, debugger, etc.) that's maintained by ARM employees. It's available in the regular repositories, but you can use a PPA to get more up-to-date versions. OpenOCD facilitates communication between your PC and the ST-Link programmer. Install both tools:

$ sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded $ sudo apt-get update $ sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi libnewlib-doc gdb-arm-none-eabi openocd

There's currently a minor bug: those packages don't include the newlib-nano library. If you need newlib-nano you can manually install the GCC ARM Embedded package. Instead of using the above three commands, use these:

$ sudo apt-get install openocd ia32-libs $ cd ~/stm32 $ wget https://launchpad.net/gcc-arm-embedded/4.8/4.8-2014-q1-update/+download/\ gcc-arm-none-eabi-4_8-2014q1-20140314-linux.tar.bz2 $ tar -xjvf gcc-arm-none-eabi-4_8-2014q1-20140314-linux.tar.bz2 $ echo export PATH=$PATH:/home/username/stm32/gcc-arm-none-eabi-4_8-2014q1/bin >> ~/.bashrc $ source ~/.bashrc

Regardless of how you install GCC Arm Embedded, you'll also want the CMSIS and STM StdPeriph libraries:

$ cd ~/stm32 $ git clone https://github.com/szczys/stm32f0-discovery-basic-template.git $ cd stm32f0-discovery-basic-template/Libraries/ $ make

We're now ready to build and flash some firmware. I'll cover three ways to accomplish that: using the command line, using the Geany IDE, and using the Eclipse IDE.

Building and Flashing: From the Command Line

For a very simple workflow you can just use the command line to get everything done. Write your code in whatever editor you like, and use a Makefile to encapsulate all of the build, debugging and device programming commands.

My basic empty project is available as a zip file or through my stm32f0-empty-project repository on GitHub. Extract it to ~/stm32/projects/. It has a main() that just configures a GPIO and toggles it in an infinite loop. The f0lib/ directory contains my incomplete and unpolished collection of potentially reusable code. There's also a Makefile and configuration files for GDB and OpenOCD. Usage is trivial:

make compiles the firmware into an ELF and a BIN.
make install flashes the firmware to the STM32F0 with OpenOCD.
make clean deletes the ELF and BIN.
make debug_server, make debug_nemiver and make debug_cli are used for debugging. More on this in the debug sections below.

Building and Flashing: With the Geany IDE

Geany is a simple IDE and perhaps my favorite environment for programming in C. The IDE is essentially a text editor with a few extra features to support coding. It's minimalist and very fast. The only settings you need to change are the build commands. Go to Build > Set Build Commands. Configure them as compile = make clean, build = make, execute = make install. While this might sound weird, it makes the three build icons in the toolbar perfect for one-click actions instead of having to use the drop-down build menu.

Side note: if you're using Cinnamon or Gnome3 with a high-DPI display, the experimental GTK3 support in Geany gives you a beautiful high-DPI-friendly IDE. You'll have to build Geany from source with ./configure --enable-gtk3 && make && make install.

Building: With the Eclipse IDE

Many people prefer the Eclipse IDE. While I don't care for it's busy interface and relatively sluggish performance, there is a must-have plug-in that gives awesome annotated register views in the debugger. Start by installing the Eclipse and CDT packages, then install the GNU ARM Eclipse and EmbSysRegView plug-ins. Don't install Eclipse from the repositories -- the repo version of Eclipse is a few years old.

Download from https://www.eclipse.org/downloads/ Extract to ~/stm32 Open Eclipse Help > Install New Software > Work with > Kepler Programming Languages > C/C++ Development Tools Help > Install New Software > Add Name = GNU ARM Eclipse Plug-in Location = http://gnuarmeclipse.sourceforge.net/updates Select: Cross Compiler Support, Generic Project Templates, STM32Fx Project Templates, OpenOCD Debugging Support Help > Install New Software > Add Name = EmbSysRegView Plug-in Location = http://embsysregview.sourceforge.net/update Select: embsysregview (both components)

I only use Eclipse for debugging, so you might be better served by reading the GNU ARM Eclipse plug-in documentation. My way is a bit of a dirty hack to just get things working well enough to debug. Here's what I do:

File > New > C Project Executable > Empty Project > Cross ARM GCC > Next > Next Toolchain Path = ~/stm32/gcc-arm-none-eabi-4_8-2014q1/bin Finish Copy the contents of your project folder into the Eclipse project's folder. Then in Eclipse: Right click on project > Refresh Right click on project > Properties C/C++ General > Paths and Symbols > GNU C > Add > File system Navigate to: ~/stm32/stm32f0-discovery-basic-template/Libraries/CMSIS/Device/ST/STM32F0xx/Include OK > OK > Yes Right click on project > Properties C/C++ Build > Build Settings tab Uncheck “Use default build command” Uncheck “Generate Makefile automatically” Build command = make Build directory = ${workspace_loc:/your_project_name_goes_here} C/C++ Build > Behavior tab "Build (incremental build)" = leave it empty

Again: I only use Eclipse for debugging. If you actually want to do any development in Eclipse, don't do what I do.

Debugging: With the Eclipse IDE

Having already prepared your project, now setup the debugging parts:

Right click on project > Debug as > Debug Configurations Double-click on GDB OpenOCD Debugging Name = STM32_Debug Debugger tab Uncheck “Start OpenOCD locally” GDB Client Setup Executable = arm-none-eabi-gdb Apply Close Window > Preferences C/C++ > Debug > EmbSys Register View Architecture = cortex=m0 Vendor = Stmicro Chip = stm32f051x Board = STM32F0DISCOVERY In a terminal in the project directory: make debug_server (Leave this running) Click on the debug drop-down in the toolbar > STM32_Debug > Yes Window > Show View > Other Debug > EmbSys Registers

You can now debug using step/next/etc. Double-click on registers in the EmbSys Registers tab to view their contents. It automatically updates as you step though code.

Debugging: With Nemiver

Nemiver is a fast and no-frills debugger. Using it with this project is trivial:

$ make debug_server $ make debug_nemiver

make debug_server will have to stay running for the duration of the debugging process, so run it in a separate terminal window. After closing Nemiver you can close the server with Ctrl-C.

Debugging: From the Command Line

Command line debugging with this project is also really easy:

$ make debug_server $ make debug_cli

make debug_server will have to stay running for the duration of the debugging process, so run it in a separate terminal window. After closing gdb you can close the server with Ctrl-C.

  1  Next >