Telemetry Viewer v0.4

This version of Telemetry Viewer focused mostly on making things easier and more intuitive for the user.

Telemetry Viewer v0.4 Changelog (2017-07-21)

  • The GUI now guides the user on how to connect to a serial port or open an existing layout.
  • Arduino sketch templates are generated to make it easier to write the firmware.
  • The GUI now guides the user on how to place charts.
  • The charts were re-themed to use a tile-based layout instead of a plain grid.
  • Most of the chart attributes can now be hidden (axis titles, axis scales, legends, etc.)
  • When adding a chart, the chart is drawn live so you can see the effects of the settings.
  • Chart settings can also be changed by clicking the gear icon near the top-right corner of each chart.
  • Faster rendering for the Waveform and Waterfall modes of the Frequency Domain Chart.
  • Various small bug fixes. See the git commit log for more details.

Telemetry Viewer v0.4 Demo Video


Executables (.jar) and source code (.zip) can be downloaded at or the project can be viewed at

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:


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


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:

For a higher-power LED:

Telemetry Viewer v0.3

I started developing a telemetry visualization tool around half a year ago but never got around to making a post on my blog. This tool makes it easy to chart data received over a UART. Line charts, Fourier transforms, histograms and dials (gauges) are currently supported. The main goal was to be able to plot large amounts of data, live, without requiring a very powerful CPU or GPU. With antialiasing enabled, I'm currently able to plot around 600,000 points, at 4k60, with a mobile Core i7 (and no discrete GPU.) With antialiasing disabled, I can more than double that.

Since there are no blog posts for v0.2 and v0.1, I'll list the changelog and demo videos for all three versions:

Telemetry Viewer v0.3 Changelog (2017-02-11)

  • Added manual ranging (the y-axis) to Time Domain Charts.
  • Added manual ranging (the power axis) to Frequency Domain Charts.
  • Added new Waveform and Waterfall views to Frequency Domain Charts. These visualize the frequency domain's history over a period of time.
  • Added manual domains (the x-axis) and autoscaled-but-fixed-center domains to Histogram Charts.
  • Added manual ranging (the y-axis) to Histogram Charts.
  • Added y-axis scale choices to Histogram Charts: relative frequency, frequency, or both.
  • Added user-specified bin counts to Histogram Charts.
  • Added manual ranging to Dial Charts.
  • Added the ability to remove statistics from Dial Charts.
  • New Quaternion Chart to visualize orientation (rotation in three dimensions.)
  • For line charts, if you are zoomed-in enough that there are relatively few points on screen, dots are now rendered at each point.
  • Automatic logging has been removed and replaced with an "Export CSV Log" button.
  • Added support for high-resolution scrolling when using certain Logitech mice, such as the M705.
  • Various small bug fixes. See the git commit log for more details.

Telemetry Viewer v0.3 Demo Video

Telemetry Viewer v0.2 Changelog (2016-11-24)

  • Ported / rewrote all charts for OpenGL. Massive speed improvements. No longer using JFreeChart.
  • Added automatic logging to "log.csv"
  • Added timeshifting: use your scroll wheel to rewind and fast-forward through time.
  • Added zomming: use your scroll wheel while holding down Ctrl to zoon in and out.
  • Added display scaling: use your scroll wheel while holding down Shift to make fonts/lines/etc bigger or smaller.
  • Added ability to remove specific charts by clicking on an "X" at the top-right corner of a chart.
  • Added a "Help" button with a brief user guide.
  • Various small bug fixes. See the git commit log for more details.

Telemetry Viewer v0.2 Demo Video

Telemetry Viewer v0.1 Changelog (2016-09-27)

  • Initial release.
  • Five chart types: Time Domain, Time Domain Cached, Frequency Domain, Histogram, and Statistics.
  • The Time Domain, Frequency Domain and Histogram charts used the JFreeChart library, the others were written by me.
  • Very basic functionality.

Telemetry Viewer v0.1 Demo Video


Executables (.jar) and source code (.zip) can be downloaded at or the project can be viewed at

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:

Source code for the telemetry viewer software is available here:

Setting Up a Raspberry Pi Web Server

I've been using a Raspberry Pi as a low-cost/low-power server for the past couple years. This post is my short collection of notes related to setting up a Pi as a web server with the classic "LAMP" stack (Linux, Apache, MySQL, PHP.)



Prepare an SD Card

Unzip the Raspbian archive and use Win32DiskImager to write the .img to an SD card. To run Win32DiskImager, you might to Right Click -> Run as Administrator. When the write completes, place the SD card in the Pi and plug in ethernet and micro USB cables. There is no need for a keyboard, mouse or monitor.

Connect to the Pi via SSH

Use your router to figure out the Pi's IP address and optionally setup the router to assign the Pi a static IP address. Run TeraTerm and start a SSH connection to that IP address. The default username is "pi" and the default password is "raspberry".

Optionally change the hostname by replacing all instances of "raspberrypi" with a new hostname:

sudo nano /etc/hostname sudo nano /etc/hosts

Optionally change the username by replacing all instances of "pi" with a new username:

sudo -s nano /etc/passwd (change the username AND home dir) nano /etc/shadow nano /etc/group nano /etc/gshadow nano /etc/sudoers mv /home/pi /home/newusername passwd newusername shutdown -r now

Reopen TeraTerm and login with the new username and password.

Configure Raspbian and Install Software Updates

Run raspi-config to setup the OS:

sudo raspi-config Expand the filesystem Set boot options to "B1 Console" Optionally set internationalization options to "en_US" and set the timezone Finish and let it reboot

Install software updates:

sudo apt-get update sudo apt-get upgrade

Install and Configure Apache, MySQL and PHP

Install the web server software:

sudo apt-get install apache2 php5 mysql-server mysql-client sudo chown -R yourusername /var/www sudo chgrp -R yourusername /var/www ln -s /var/www/html ~/html

At this point it's all up and running. Going to the Pi's IP address in a web browser should reveal the default Apache page. That page is stored in /var/www/html/index.html, and also accessable through the link you made as ~/html/index.html. Assuming you want the web server to be public, you probably want to setup port forwarding on your router (TCP port 80) and use a domain name and dynamic DNS service so people can type in a .com instead of an IP that might change over time.

I use Google Domains. It's around $12/year for a .com and they include dynamic DNS service at no extra cost. Here's how to setup the dynamic DNS service they offer:

Login to In the rows of domain names, click on the DNS icon for the domain you want to setup In the Synthetic Records section, select Dynamic DNS For the subdomain, use "@" (without the quotes) for no subdomain (like when someones goes to instead of Then make another record for the "www" (without quotes) subdomain Click on the > icon next to each record, then click View Credentials

You can use software like ddclient to notify Google when your IP changes, or you can keep things simple and just visit a specially-crafted URL periodically to keep Google up-to-date. I wrote a simple script to visit that URL and record it's response to a text file. Be sure to make the script executable:

nano ~/ wget -qO dns_update_results.txt wget -qO- >> dns_update_results.txt echo " Last run: `date`" >> dns_update_results.txt chmod +x ~/

The script downloads the web pages to the text file (the first wget creates the text file, the second wget appends to the text file) and then I also append the current date and time to the text file.

Setup a cron job to run the script at the start of every hour:

crontab -e 0 * * * * ~/

Using Virtual Hosts to Serve Multiple Domains

A single computer can serve multiple domains. Apache supports this and calls it a "Virtual Host." You can repeat the following steps for as many domains as needed:

sudo nano /etc/apache2/sites-available/yourdomain.conf <VirtualHost *:80> ServerName ServerAlias * DocumentRoot /var/www/yourdomain </VirtualHost> sudo mkdir /var/www/yourdomain sudo chown -R yourusername /var/www/yourdomain sudo chgrp -R yourusername /var/www/yourdomain ln -s /var/www/yourdomain ~/yourdomain sudo a2ensite yourdomain sudo service apache2 reload

Using Swish-SFTP to Copy Files to the Pi

After installing Swish-SFTP, there will be a "Swish" device listed in File Explorer > This PC. Double-click it, then choose "Add SFTP Connection" near the top of the window. After making a connection you can drag-and-drop files between Windows and the Pi.

That's it. You now have a web server that requires less than 5 watts of power to run, and occupies hardly any space in your home.

YouTube Video

I also made a YouTube video showing the process. In the video I did not cover Virtual Hosts.

  1  Next >