Category Archives: Arduino

Arduino Sous Vide, Version 2.0

I previously built a sous vide machine based off Seattle Food Geek’s plans but with an arduino + relay in place of the PID. It ran off a shoddy script I wrote in Python to be used with Pyfirmata. The recommended Norpro heating devices in the Seattle Food Geek blog failed within 10 uses and the Pyfirmata script required a computer to be plugged into the arduino. It worked but was hardly optimal. This new sketch is written in C and doesn’t require Pyfirmata or an additional computer to be plugged into the arduino.

Very simple, works great!

The Sketch

// A simple arduino sous vide machine sketch

void setup() {

Serial.begin(9600);
}
void loop() {

// set pins and mode
// set relay pin and relay status to off
const int relay_pin = 2; 
int relay_status = LOW;
pinMode(relay_pin, OUTPUT);

int analogValue = analogRead(A0); // read the raw value for thermistor via analog pin0

// assign variables
float temperature; // the current temperature
float upper;       // the upper limit at which the relay & heat source shut off
float setpoint;    // the desired setpoint cooking temperature
float lower;       // opposite of upper
float steinhartA;  // steinhart-hart equation coefficients
float steinhartB;
float steinhartC;
float rt;          // thermistor resistance

setpoint = 60.0;   // desired cooking temperature in degrees C 
lower = setpoint - 1.0; // can manually edit cutoff values to affect hysteresis curve
upper = setpoint + 1.0;
steinhartA = 1.137699953e-3; // replace with your thermistor's unique steinhart-hart coefficients
steinhartB = 2.325339915e-4;
steinhartC = 0.9547893220e-7;

rt = 9910*(1023/float(analogValue)-1.0);
temperature = steinhartA + steinhartB*log(rt) + steinhartC*(log(rt)*log(rt)*log(rt));
temperature = (1.0/temperature)-273.15; // convert from K

Serial.println(temperature); // debug, print temp to serial

if (temperature >= upper)
{
relay_status = LOW; 
digitalWrite(relay_pin, relay_status);
Serial.println("RELAY OFF"); // debug, print status to serial
}

else if (temperature <= lower)
{
relay_status = HIGH;
digitalWrite(relay_pin, relay_status);
Serial.println("RELAY ON");
}

delay(30000);        //  30s delay between temperature reads
}

How to use

Use it with a thermistor, relay, and a heating device of your choice. Edit the setpoint temperature to your desired temp and be sure to edit the Steinhart-Hart values to reflect those of your thermistor. If you wish to change the temperature, you will need to upload an updated sketch (for now….).

My current setup

A few things have changed since my previous posts. Since my immersion heaters have failed, I had to find a new heating source. A commenter recommended a turkey roaster which sounds like a fantastic idea (and they look very similar to lab water baths which is a plus). I was averse to spending any more money on this project though so I scavenged around the house and am currently using a hot plate with a large stockpot on top. The stockpot holds an excess of water which helps maintain a more constant temperature and the pot + large volume of water retains heat better than the thin sterilite container used previously. Its greater size allows me to fit larger cuts of meat in it also which is a big plus. Getting heat up to the setpoint temperature no longer takes a century with the hotplate which is also very nice.

I am using a 10k ohm thermistor that I had laying around as I misplaced the old 4.7k ohm thermistor. I only mention it in case someone looks at any old posts and is left scratching their head over the sudden change in equation values.

I am using the same relay setup as described previously.

Future

I am waiting on an Amazon shipment to come with an LCD screen. Once that arrives (hopefully within another 3 weeks… I live in a remote location!), I will feature creep this sketch to include a live temperature readout and the ability to configure setpoint temperature without needing to modify the sketch and reupload.

Further resources:

My other posts on arduino sous vide

How to use a relay with an arduino

Seattle Food Geek sous vide machine

Everything you would ever want to know about using a thermistor with an arduino

Thermistor calculator

 

Sous Vide Update, 5/2014

I was about to get started on the code overhaul for the Arduino sous vide machine when I discovered that my immersion heaters no longer work. A word to the wise, you shouldn’t store them in freezing temperatures in a humid garage. The heaters I chose had mediocre reviews on Amazon, but were still the best reviewed and most affordable. I’m going to look into a few alternatives to find something heartier, but equally affordable.

Arduino Sous Vide Machine: Part 2

Note: For an updated version with simpler code and important information about hardware issues see this new post: Arduino Sous Vide, Version 2

Darwin Award Disclaimer: Playing with electricity around big containers of water can be dangerous!

sous vide_fritz
The wiring scheme

After several successful cooks with the sous vide machine and ironing out a few software bugs, I decided it’s good enough to post. Like my other entries, it’s hardly pythonic, but gets the job done and it’s not all that bad for two months of self taught lackadaisical python study.

Photos to follow this post

I will upload some photos when I get a chance in the coming weeks.

The Assembly

You will need the parts listed in Part 1. The machine is assembled relatively easily from here. The immersion heaters plug into the GFCI relay box. The relay should be connected to the arduino with M to F jumper wires as pictured in the first post.

The thermistor should be enclosed in something that will lend additional waterproofing (partially sealing it in a piece of vacuum bag is a good idea or any old ziploc). The thermistor is connected to the arduino as depicted in the image above.  Don’t bother moving on unless you know the resistance of your thermistor at 25C and have determined your specific resistor’s Steinhart-Hart equation coefficients as described in this post. When you have these values, you will need to add them to the code below. (My values will work fine for the 4.7k ohm epoxy thermistor linked in Part 1).

The binder clips mentioned in Part 1 are useful for holding the Thermistor / waterproofing in place and keeping food filled vacuum bags in place when needed. The coat hanger / safety wire is used to hold the immersion heaters at the proper place in the container. I used two and have the heaters pinched in between.  It’s important to not submerge them completely, but leave some space between the water and the start of the electrical cord. The aquarium pump goes at the bottom along a wall of the container to ensure constant heat redistribution. The container lid is not necessary, but can be placed on top once you’ve started.

sousvideconsole2
This console output will refresh every 30 seconds with an updated temperature, time remaining, and whether the heater is on or off.

The Code

Code available for download. Hack it, improve it, MIT license yada yada yada…

# ARDUINO SOUS VIDE 
# v 0.1
# Simple arduino sous vide program
# Controls relay based on thermistor readings

import time
import os
import pyfirmata
from math import log

status = 'off'

def slp():
  '''
  INSERTS 5 SECOND DELAY 
  '''
  time.sleep(5)

def cls():
  '''
  CLEARS CONSOLE BETWEEN READINGS AND USER ENTRIES
  '''
  os.system('clear')

# SET COOKING PARAMETERS
def setup():
  ''' 
  SET UP COOKING PARAMETERS SUCH AS TEMP SCALE, TEMP, LENGTH OF TIME, PRECISION
  '''
  global cook_temp
  global cook_time
  global end_time
  global cook_temp_f
  global scale

  # CHOOSE TEMPERATURE SCALE AND COOKING TEMP
  n = True
  while n == True:
    cls()
    # SELECT TEMPERATURE SCALE
    scale = raw_input("Select temperature scale\n\n   1) Celsius \n\n   2) Fahrenheit \n\nEnter your selection: ")
    scale = scale.strip()
    if scale == '1':
      scale = [scale, 'Celsius', 1.0]			# scale list is temperature scale selection from menu, followed by name of scale, and last value is number of +/- degrees deviation allowed from cook_temp in cook() 
    elif scale == '2':
      scale = [scale, 'Fahrenheit', 2.66]
    else:
      print '\n\nERROR: You must enter 1 for Celsius or 2 for Fahrenheit\n\n'
      slp()
      continue
    cls()

    # SELECT COOKING TEMPERATURE; DON'T ALLOW NONSENSE ENTRIES SUCH AS < ROOM TEMP OR > BOILING POINT
    cook_temp = float(raw_input('Enter desired cooking temperature in degrees ' + scale[1] + ': '))
    if (scale[0] == '1' and cook_temp > 100) or (scale[0] == '2' and cook_temp > 212):
      print '\n\nERROR: Temperature may not be higher than boiling point of water (BP: 100 C, 212 F)\n\n'
      slp()
      continue

    elif (scale[0] == '1' and cook_temp < 25) or (scale[0] == '2' and cook_temp < 77):       print '\n\nERROR: Temperature may not be lower than room temperature (RT: 25 C, 77 F)\n\n'        slp()       continue          try:     # SET ALLOWED TEMPERATURE DEVIATION. DON'T ALLOW DEVIATION BEYOND +/- 5 DEGREES.        deviation = float((raw_input('Enter allowed +/- degrees deviation from setpoint. Press enter for default of ' +str(scale[2]) + ' degrees ' + scale[1] +': ')))       if deviation > 5:
	print '\n\nERROR: Deviation of ' +str(deviation) + ' degrees ' + scale[1] + ' is too great. Reduce your value to 5 degrees or lower for greater precision cooking.'
	print '\n\nExample: cook temp of 70 degrees C with 5 degrees deviation will allow a low temp of 65 C to be achieved before heaters are turned on and a high temp of 75 C before heaters are shut off'
	slp()
	continue
      scale[2] = deviation
    except:
      pass

    # SET COOKING TIME LENGTH IN MINUTES
    cook_time = raw_input("Enter desired cook time in minutes: ")
    cook_time = float(cook_time) * 60
    start_time = time.time()
    end_time = start_time + cook_time
    cls()

    # SETUP VERIFICATION / START
    print 'COOKING SETTINGS'
    print '\n\nSet for ' +str(cook_temp) +' degrees ' + scale[1] ,
    print 'for ' +str(cook_time / 60) +' minutes'
    print time.strftime('Cooking will complete at %a %I:%M %p', time.localtime(end_time)) #convert end_time seconds to readable day H:m format
    start = raw_input('\n\nDo you wish to continue with current settings? ')
    if start.lower() == 'n' or start.lower() == 'no':
      continue
    if start.lower() == 'y' or start.lower() == 'yes':
      n = False

def connection():
  '''
  CONNECT TO ARDUINO
  '''

  global pin0
  global pin4
  global board
  n = 0							# first port number to try ie: ttyACM0
  PORT = '/dev/ttyACM' + str(n)    			# device location, yours may very. if unable to connect, try /dev/USB or check dmesg
  connected = False 

  # ATTEMPT TO CONNECT TO ARDUINO. ITERATE THROUGH 1000 PORT NUMBERS UNTIL CONNECTED OR FAIL ON 1001.
  while connected == False:
    try:
      print 'Trying ' + PORT
      board = pyfirmata.Arduino(PORT)
      print 'Port found, connecting...'
      connected = True
      print "Connection established"
    except:
      n = n+1
      if n > 1000:
	raise Exception("Error connecting to arduino. Check to make sure it's connected and check dmesg for correct location. If other than /dev/ttyACMx, edit line #102 of sousvide.py to reflect your location.")
      PORT = '/dev/ttyACM' + str(n)
      pass

  pin0 = board.get_pin('a:0:i')				# edit to reflect your setup
  pin4 = board.get_pin('d:4:o')

  it = pyfirmata.util.Iterator(board)
  it.start()

  pin4.write(0)						# start with pin off
  pin0.enable_reporting()

  print 'Waiting on reading...'
  while pin0.read() is None:				# ignore input until pin is active
      pass

def temp_check():
  '''
  FUNCTION THAT POLLS ANALOG PIN FOR TEMPERATURE, USED EVERY 30 SECONDS
  '''

  global current_temperature
  current_temperature = ''				# reset temperature each time 

  while pin0.read() is None:				# ignore input until pin is active
      print 'waiting on thermistor reading...'
      pass

  analog_value = pin0.read()

  # VOLTAGE DIVIDER CALCULATION
  analog_value = analog_value  * 5			
  analog_value = 4700.0 * ((5.0/analog_value) -1.0) 	# make sure you use the correct number here reflecting your thermistor. ie: for 10k ohm resistor, replace 4700 with 10000

  # STEINHART-HART EQUATION 
  temp = (1 / (0.001308463361 + 0.0002344771590 * log(analog_value) + 0.0000001041772095 * log(analog_value)**3)) # substitute your thermistor's unique values for A, B, C. 

  # CONVERT TEMPS FROM KELVIN 

  # TEMP IN CELSIUS
  if scale[0] == '1':
    current_temperature = temp - 272.15

  # TEMP IN FAHRENHEIT
  if scale[0] == '2':
    current_temperature= 9/5.0*(temp-272.15) + 32

  # TIME / TEMPERATURE LOGGING
  f = open('/tmp/sousvide.log', 'a')
  f.write(str(time.time()) + ' ' + str(current_temperature) + '\n')
  f.close()

  # STATUS REPORTING TO CONSOLE
  cls()
  print 'ARDUINO SOUS VIDE v 0.1'
  print '-'*80+'\n\n'
  print ' '*5 + 'Set temperature: ' + str(cook_temp) + '\n\n'
  print ' '*5 + 'Current temperature: ' + str(current_temperature) + ' ' + scale[1] + '\n\n'
  print ' '*5 + 'Heating element(s): ' + status + '\n\n'
  print ' '*5 + 'Time remaining: ' + str((end_time - time.time())/60.0) + ' minutes\n\n\n\n'
  print  '-'*80
  slp()

def cook():
  while True:

    global status

    while time.time() < end_time: # continue cook function until time up
      temp_check()
      if current_temperature < (cook_temp - scale[2]): 	# start heating element every time temp drops X degrees below goal temp 	pin4.write(0)	# START HEAT 	board.pass_time(5) 	time.sleep(20) 	status = 'on'       elif current_temperature > (cook_temp + 0.4 * scale[2]): # kill heating element every time temp goes 0.5X degrees over goal temp
	pin4.write(1)	# KILL HEAT
	board.pass_time(5)
	time.sleep(20)
	status = 'off'
      else:  				      		# if temperature is within X*2 degrees (-X goal +X) of goal temp, continue with whatever is currently happening
	board.pass_time(5)
	time.sleep(20)
	pass 

    if time.time() > end_time or time.time() == end_time:
      pin4.write(1)
      cls()
      print "all finished, killing heat..."
      slp()
      board.exit()
      exit()

setup()
connection()
cook()

Features

The code offers the following features:

  • Fahrenheit and Celsius heating options
  • Status updates every 30 seconds
  • Control over hysteresis with modifiable temperature range from setpoint (the deviation option)
  • Automatic logging of temperature and time to /tmp/sousvide.log

What’s Next

Now to get cooking, there are some excellent resources online. Douglas Baldwin offers some of the most oft quoted resources. He has some good information on his website, including some carefully calculated pasteurization tables that if followed, let you cook food low and slow while still getting all the nasties.

For a more general overview, you can check out his presentations that he did for the American Chemical Society, Sous Vide Cooking and Chemistry and Giving Thanks for the Water Bath: Sous Vide Cooking for the Holidays.

Limitations

This set up and code is good to go as-is ‘out of the box’. FYI: timer starts immediately after accepting  cook settings. You must take into account preheat time (approximately one hour to obtain 60C from room temp water, see ‘future updates’ section below).

A little fine tuning may be helpful to get the most precise and near constant temperature. In order to avoid a constant on/off, a hysteresis curve is simulated in the cook() function. After about 6 cooks, I’ve gotten it calibrated pretty well. It originally was giving some wild peaks due to the fact that the heaters continue to heat after shutting off.

Case in point:

sous vide premodification

I found that reducing the deviation variable to 40% for the cut off temp and reducing the temperature check interval by 10s greatly improved the outcome. I may go one step further and reduce the polling interval by another 5s to try to get equidistant ‘peaks’ to ‘troughs’ from setpoint temp).

I cooked my chicken for more than 1 hour. Scale abbreviated to better match above graph.
I cooked my chicken for more than 1 hour. Scale abbreviated to better match above graph.

If your sous vide cooking relies on even more precise cooking that deviates less than 1C from setpoint, feel free to fiddle with the cook() function and/or set deviation to something very low (< 0.5 degrees).

Future Updates

I ran out of time in the short run to make any new updates to this. For my own satisfaction, I will likely add a preheat function from the data gleaned in the last post that will preheat the water bath and once preheated, start the timer from there. Should be a quick fix. As an exercise in dealing with formatting Python time strings, I may make the time input a little smarter with options other than minutes.

I’m also considering modifying the code to make use of PyPi and the Raspberry Pi via its GPIO pins.

Arduino Sous Vide Machine: Part 1

Note: For an updated version with simpler code and important information about hardware issues see this new post: Arduino Sous Vide, Version 2

Heavily inspired by an old blog post by the brilliant Seattle Food Geek, I set out to build an arduino powered sous vide / thermal immersion circulator machine.  Instead of a PID controller, it uses an arduino with a relay + waterproof thermistor. A little less sexy, but just as effective with the added bonus of being modular with reusable parts.

Materials

  1. Sterilite® Ultra Latch 17 L container $4
    • Made of polyproplyene, softens at ~155°C according to the Merck index, melts at 165°C; perfect for our application of temps < 100°C.
    • Avoid long term exposure to UV light as paranoid precaution against degradation
    • You can simply use a big pot instead of the plastic container. I Outlet boxhave an enamelled cast iron pot that is excellent for maintaining a steady temperature.
  2. Arduino (I’m using UNO rev3) $35
  3. Waterproof temperature sensor / thermistor (DS18b20 ) $2.03

    • This thermistor is waterproof but not rated for full immersion
    • I sealed mine in a small bit of plastic with the vacuum sealer. problem solved
    • See previous post for how to calibrate
  4. Immersion heater (2x) $13
  5. 3 prong power cable free if sacrificed, otherwise $6+
  6. 5V 1 channel relay  $1.36
    • This relay is really cheap and was starting to fall apart on me; I substituted it with another one I had laying around. YMMV
  7. Aquarium water pump 80GPH $6.88
  8. Ziploc V150 vacuum sealer system $30 (on clearance at Target)
  9. GFCI outlet $12.30
  10. Outlet faceplate $1 (optional)
  11. Outlet box $0.50 (link is to pack of 100, cheaper to buy in store)
  12. Wire coat hanger / safety wire
  13. Large binder clips (2x) $0.50
  14. Male to female (3x) and male to male jumper wires (the more the merrier) $2.00
  15. A 4.7 k Ω resistor for thermistor $0.05

Grand Total:  $114.62 if you buy everything. You can add an extra heater or two if desired. I found that two alone work pretty well. My units have been calculated to heat at about 0.01 C per second, taking an hour to get up to an average cooking temp of 65C from room temperature water.

norpro temperature graph

Step 1: Building the relay

The first step is building a functioning relay. The beauty of this sous vide machine is that it is comprised of parts that can be cannibalized and put to other uses when you’re not sous vide cooking. The relay is especially cool as it allows you to control high voltage devices from the measly 5V microcontroller of the arduino. The options from here are limited only by your creativity and/or depravity. (Lots of options of pairing it with motion!)

I followed a Sparkfun tutorial on how to build a Controllable Power Outlet. Quite frankly, there is no need to rehash something that is described better there. Check it out.

Here’s a diagram for the relay listed  in the parts list. You can figure it all out from this picture alone.

relay wiring

Step 2: Testing Relay

Controlling a relay with pyfirmata

Controlling the relay is incredibly easy with pyfirmata. It’s as simple as turning a pin on and off to open and close the relay. If you know how to switch a LED on, you can control a relay.

Here’s some example code to function test it.

import pyfirmata

port = '/dev/ttyACM0'

board = pyfirmata.Arduino(port)

it = pyfirmata.util.Iterator(board)
it.start()

pin4 = board.get_pin('d:4:o')

while True:
	ui = raw_input("Enter 'on' or 'off': ")
	if ui == 'on':
		pin4.write(1)
	elif ui == 'off':
		pin4.write(0)
	else:
		pass

Plug your relay into the arduino, plug your arduino into a PC and test it out by plugging in your relay controlled power outlet and lamp into the outlet.

That’s all there is to it. It’s only a small leap from here to put some devices online that you can control remotely. (Check out X10 for anything beyond a few devices).

Next…

Building a feedback loop with a thermistor and using thermostat-like hysteresis curves for controlling the immersion heaters.

Thermistor + pyfirmata

Want to know how to use a thermistor with your arduino via pyfirmata? Look no further…

I’ve been playing with thermistors as part of a home monitoring system I’ve been building and for an upcoming sous vide project. Thermistors are cheap and can be highly accurate for a pretty wide range of temperatures. I’m using an epoxy coated and waterproofed thermistor for my sous vide project.

The Setup

You need:

  • an arduino
  • a thermistor
  • a resistor that matches your thermistor (ie: 10k ohm resistor with 10 k ohm thermistor)
  • a breadboard with jumper wires

pyfirmata thermistor

The Code

Code available for download

### THERMISTOR TEMPERATURE READINGS VIA PYFIRMATA 
### JS Kouri 2/1/2014, no rights reserved
### In this example, I am using a 4.7 kΩ resistor 
### (Digi-Key Part Number NTCLE400E3472H)
### Values for Steinhart-Hart equation calculated 
### at http://bit.ly/1nPiOLv from datasheet info

import pyfirmata
from math import log
from time import sleep

n = 0							#first port number to try ie: ttyACM0
PORT = '/dev/ttyACM' + str(n)    			# device location, yours may very. if unable to connect, try /dev/USB or check dmesg
connected = False 

def connection():
  global board
  board = pyfirmata.Arduino(PORT)
  print 'Port found, connecting...'
  it = pyfirmata.util.Iterator(board) # start iterator thread
  it.start()

# ATTEMPT TO CONNECT TO ARDUINO. ITERATE THROUGH PORT NUMBERS UNTIL CONNECTED  
while connected == False:
  try:
    print 'Trying' + PORT
    connection()
    connected = True
    print "Connection established"
  except:
    n = n+1
    PORT = '/dev/ttyACM' + str(n)
    pass

# WAIT UNTIL INPUT RECEIVED AT ANALOG PIN  
pin0 = board.get_pin('a:0:i')				# edit to reflect your setup
print 'Waiting on reading...'
while pin0.read() is None:				# ignore input until pin is active
    pass

while True:

  analog_value = pin0.read()
  #print analog_value 					# optional debug info

  # VOLTAGE DIVIDER CALCULATION
  analog_value = analog_value * 5			# we multiply by 5 (volts) to get the true voltage read at pin (ie: we get 3 v instead of 0.6. pyfirmata reports analog values in the range of 0 to 1. 
  analog_value = 4700.0 * ((5.0/analog_value) -1.0) 	# solve for resistance at thermistor. change 4700 to match your resistor used.

  #print str(analog_value) + ' this is calculated resistance in ohms at thermistor' # optional debug info

# STEINHART-HART EQUATION
  temp = (1 / (0.001308463361 + 0.0002344771590 * log(analog_value) + 0.0000001041772095 * log(analog_value)**3)) # substitute your thermistor's unique values for A, B, C. 

  # TEMP IN KELVIN
  print str(temp) + ' kelvin'

  #TEMP IN CELSIUS
  t_celsius = temp - 273.15
  print str(temp) + ' degrees celsius'

  #TEMP IN FAHRENHEIT
  t_fahrenheit = 9/5.0*temp + 32
  print str(t_fahrenheit) + ' degrees fahrenheit\n\n'  

  sleep(30) 						# wait 30 seconds between polling pin

The Explanation

The code features a few important aspects that understanding will be helpful.

Converting Pyfirmata Analog Values to Voltage

Pyfirmata reports analog values as a float of 0 to 1. We need to determine what the voltage is at the analog pin. We’re using 5 VDC so we multiply it by 5.  This will provide Va for the next portion.

The Voltage Divider

A neat little explanation of why we use voltage divider circuits with thermistors and other sensors can be found here. No need to rehash it.

In order to obtain the resistance of the thermistor, we need to calculate it based off the voltage readings from the analog pin. (Which we just adjusted). We use an equation derived from Ohm’s Law that lets us calculate the resistance in a voltage divider.

RT = R  [1 / (V / VA – 1) ]

Where RT = thermistor resistance in ohms, R = resistor resistance, V = input voltage, VA = voltage reading from analog pin (Read more at Wikipedia Voltage Divider)

 Armed with the resistance at the thermistor, we can finally calculate the temperature.

Steinhart-Hart Equation

There are  a couple ways of calculating this, I chose the Steinhart-Hart equation, but you can also use the simpler β equation. (See Wikipedia)

Where R = thermistor resistance. (Written as RT in last section)

It is very important to have your datasheet in order to accurately calculate the values needed for this equation. If you don’t have the datasheet, you can determine your own values by obtaining resistance in ohms at three known temperatures.

thermistor_datasheet
my thermistor’s data sheet and the values I used in the calculator

 

Once you get your  resistance values for three known temperatures from your datasheet or experimental data, plug them into a Steinhart-Hart calculator and build your equation.

Replace my values in the code above with yours. Be sure to format the coefficients properly. The calculator I linked to above gives coefficients in scientific notation. Convert scientific notation to the long form decimal notation. (n-1 preceding decimal places for E to the n power)

Now run it and get your temperature!

 Sky’s The Limit

And there you have it. From here you can easily save your values in a text file or a database, build cool charts with matplotlib (if you don’t pull your hair out first trying to get it to work), or do something more dynamic like create feedback loops and control things based on temperature.

Overengineered Morse Code with the Arduino

As a first foray into python, arduino, and pyfirmata (after lighting a single LED), I wrote this small python script for converting text into morse code. I first ran it with a single LED on a breadboard, but it was much more fun to throw in a piezo buzzer and get the unmistakeable morse beeps.

See the code and schematics below. As someone with less than a month of on and off again python study, don’t expect anything too ‘pythonic’ and pretty. It works though!

Script requires the pyfirmata module. Be sure to adjust the pin number and port/device location of the arduino in the script.

### Arduino / Raspi Morse Code Generator
### Enter a word, and get morse code translation in console output & LED lights / beeps



import pyfirmata


### MORSE CODE ALPHABET ###
morse = {'a':['.','-'],
	 'b':['-','.','.','.'],
	 'c':['-','.','-','.'],
	 'd':['-','.','.'],
	 'e':['.'],
	 'f':['.','.','-','.'],
	 'g':['-','-','.'],
	 'h':['.','.','.','.'],
	 'i':['.','.'],
	 'j':['.','-','-','-'],
	 'k':['-','.','-'],
	 'l':['.','-','.','.'],
	 'm':['-','-'],
	 'n':['-','.'],
	 'o':['-','-','-'],
	 'p':['.','-','-','.'],
	 'q':['-','-','.','-'],
	 'r':['.','-','.'],
	 's':['.','-','-','-'],
	 't':['-','.','-'],
	 'u':['.','-','.','.'],
	 'v':['-','-'],
	 'w':['-','.'],
	 'x':['-','-','-'],
	 'y':['.','-','-','.'],
	 'z':['-','-','.','-'],
	 ' ':' '}


### CONNECT TO ARDUINO ###
port = '/dev/ttyACM0'
board = pyfirmata.Arduino(port)

### SET PIN NUMBER ###
pin = 7 

def program():

### DELAY FACTORS ###
  delay = 0.15						# Length of time LED between inter elemental lighting
  delay_factor = 1					# Speed up or slow down entire program by set percentage Default: 1
  delay_intraletter = delay * delay_factor * 3		# Length of time between letters 
  delay_interword = delay * delay_factor * 7		# Length of time between words
  delay_dit = delay * delay_factor			# Length of illumination for dot/dit
  delay_dah = delay_intraletter	 


  user_list = [] 									# blank list
  user_input = raw_input("Enter your word to convert to morse code: ").lower()		# Take user input, convert to lowercase
  for x in user_input:
    user_list.extend(morse.get(x))
  print user_list
  print '\n Creating morse message now...'
  user_list = ''.join(user_list)
 # print 'DEBUG: joined user list'
 # print user_list
 
  for l in user_list:
    
    if l == '.':
      board.pass_time(delay_intraletter)
      board.digital[pin].write(1)
      print 'TRANSMITTING: .'
      board.pass_time(delay_dit)
      board.digital[pin].write(0)
    
    elif l == '-':
      board.pass_time(delay_intraletter)
      board.digital[pin].write(1)
      print 'TRANSMITTING: -'
      board.pass_time(delay_dah)
      board.digital[pin].write(0)
      
    elif l == ' ':
      board.pass_time(delay_interword)
      print 'NEW WORD'	

    else:
	pass
      
   
   
program()
  

The circuit is even simpler than the script. It amounts to nothing more than a piezo buzzer (unsure of the specs of mine), LED, and resistor in series.

Easy enough, right?
Easy enough, right?

So what had originally sprung up as an idea to play around with the pyfirmata syntax turned into a drive to learn morse code, which quickly faded into disinterest by the time I had finished transcoding the alphabet. I have since made an updated version that includes numbers and communicates between two computers on a network via the python SOCKS module. I was considering adding a reverse translator as well that translates user input (via pushbutton) morse into letters. I think I have a few other projects in mind that will be of more immediate practical use.

Download the latest source files for this project here

Morse key adopted from https://en.wikipedia.org/wiki/Morse_code.