Thursday, October 31, 2013

Arduino Round V: Light Seeking Robot

Having received a stepper motor in the mail the other day, I started playing around with the built in stepper motor library, "stepper.h". Using a dual H-Bridge drive that can source and sink current

Stepper motor(768, in1Pin, in2Pin, in3Pin, in4Pin); // These pins are the outputs from the arduino. '768, refers to then number of steps per full motor rotation
motor.setSpeed(speed); // After about a speed of 20, it barfs
motor.step(N); // With a bipolar driver, a positive or negative N can be used for clockwise/counter clockwise rotation

The project I decided on to have a little fun with the motor was a "light-seeking robot". The robot would have a left and right eye (photoresistors) and would rotate via the stepper motor until both eyes measured equal brightness.

To accomplish this, we can subtract the right-eye's voltage from the left-eye's voltage to for an error signal. If there is more light to the right than to the left, a positive error signal results and the motor turns right. If the left side is brighter, the difference is negative and the motor turns left. At some point, the difference goes to zero at which point the motor doesn't turn at all. Furthermore, as the balance gets better, and the difference gets smaller, the robot slows down and smoothly approaches the Goldie-Locks amount of light on each eye. On the other hand, when the balance is way off, the error signal is huge and the motor corrects more strongly, a situation known as proportional feedback. If the motor had some inertia we'd have to add a little lag (integration) to the loop so that the robot didn't overshoot when it got to zero and oscillate back and forth but for a stepper motor, which is heavily damped, this is not a problem.
 
The eyes of the circuit are shown here: the photodiodes each are part of a voltage divider which go to separate arduino inputs. The eyes are attached to a decapitated lego figure (you gotta use what you got) whose rectangular feet fit nicely into the stepper motor.


The motor is driven by the following code:
#include "stepperh.h"

int in1Pin = 4;
int in2Pin = 5;
int in3Pin = 6;
int in4Pin = 7;

const int LEFT = A0;  // Analog input pin
const int RIGHT = A1;  // Analog input pin
int vL = 0;
int vR = 0;

int j = 1;
int m = 1; // polarity. If turning the wrong way, switch sign
int speed = 20;

Stepper motor(768, in1Pin, in2Pin, in3Pin, in4Pin);

void setup()
{
  Serial.begin(9600);
  pinMode(in1Pin, OUTPUT);
  pinMode(in2Pin, OUTPUT);
  pinMode(in3Pin, OUTPUT);
  pinMode(in4Pin, OUTPUT);
  pinMode(LEFT, INPUT);
  pinMode(RIGHT, INPUT);  
  
  motor.setSpeed(speed);
}

void loop()
{
  vL = analogRead(LEFT); // 0-5v <-> 0-1023
  vR = analogRead(RIGHT); // 0-5v <-> 0-1023
  Serial.print("Left = ");Serial.print(vL);  // Log the measured values for debugging
  Serial.print(", Right = ");Serial.print(vR); 
  Serial.print(", Difference = ");Serial.print(vR-vL);
  Serial.print("\n");
  motor.step(m*(vR-vL));
  delay(250);    // update at 4 Hz
}

The circuit layout is sketched here:



... and here's a video of the light seeking robot seeking light:


Thursday, October 10, 2013

Arduino Round IV: A Simple Character LCD

Right after I got my clutches on the Arduino, I ordered a bunch of stuff to connect it to, including a few stepper motors and an LCD. Well, today the LCD came and I whipped together a very simple, and somewhat stereotypical project - a light/temperature sensor. The circuit monitors the light incident on a photoresistor much like the python GUI a couple posts back, as well as the temperature via a Analog devices TMP36 sensor that I got from Adafruit industries.

The LCD I used was a HD44780 compatible 4x20 character LCD that I got on the cheap from an overseas shop called seeed studia bazaar. It shipped from China so it took a couple weeks and shaved a few bucks - in the future I'd probably spend another $2 and get it overnight from somewhere a little more local.

The first chore is to hook up some solder pins to the LCD board which allows you to stick the LCD module into a solderless breadboard. With my $10, 10 year old soldering iron that I got from Walmart back in the day this was more painful than it needed to be.



Now that we can access the pins, the pin layout is as follows:



To do a basic test of operations, we can start by powering the module up and verifying that it works. Pins 1 and 2 power the unit, 15 and 16 power the back light, and pin 3 sets the LCD contrast. The datasheet for the LCD recommends a 5k potentiometer between pins 2 and 3 to set the contrast, but this could be replaced with a voltage dived from the voltage pin or a PWM output, directly from the Arduino. I found that a good value to sent to pin three was around 900mV. Here a picture of the"first light" of the project. The inset is what the screen looks like with 900mV contrast setting (my poor photography couldn't capture the bright backlight and the circuit simultaneously.)






Next, we need to hook up the data bus: for regular 4 bit operation, pins 11-14 receive information, which we can hook up to Arduino outputs 9-12. We also need to tell the LCD module three things:

  1. Whether the data being received are instructions or data to be displayed. This is selected via the register select (RS) pin 4. The Arduino Liquid crystal library which is to be used takes care of that, but for now, send an Arduino output port (4, say) to RS.
  2. Whether we are writing data to (5V) the chip or reading from it (GND). This is pin 5, R/W. Since we're only writing to the chip, we'll just clamp pin 5 to ground.
  3. Data enable (pin 6) which gates the unit for receiving data. Connect this to Arduino pin 5.
 Once this is done, we're ready to write a quick lil' arduino program to display some text. The program, shown here loads teh liquid crystal library, initializes the LCD and draws some text. That's it.
#include 

// Connections:
// rs (LCD pin 4) to Arduino pin 4
// enable (LCD pin 6) to Arduino pin 5
// LCD pins d4-d7 to Arduino pins 9-12
LiquidCrystal lcd(4, 5, 9, 10, 11, 12);
void setup()
{
  lcd.begin(20,4);              // Initialize a 20x4 HD44780-compatible LCD
  lcd.clear();                  // clear the screen
  lcd.setCursor(0,0);           // set cursor to column 0, row 0 (the first row)
  lcd.write("The Rules:");      // Write text, starting here
  lcd.setCursor(0,1);  
  lcd.write("1. Don't harm humans");
  lcd.setCursor(0,2);  
  lcd.write("2. Obey human orders");
  lcd.setCursor(0,3);  
  lcd.write("3. Protect yourself");
}

void loop()
{
} 

The result, as well as the wired circuit being:


OK, now that we can write to the device, let's make it slightly more interesting by adding some real time data. We'll monitor the voltage across a photoresistor by placing it in voltage divider configuration and sending it to Arduino input pin A0. The luminosity is in arbitrary units since I have no idea what either the spectral content of the light in my living room is or what the spectral response of the photoresistor happens to be. We will then just output the brightness in arbitrary units with the understanding that the bigger the number, the brighter the environment. I also placed a capacitor in parallel with the second resistor to ground to smooth out the readings a bit. Not really necessary but it makes the look and feel a little nicer. As for the temperature, when pins 1 and 3 have 5V across them, pin 3 holds a voltage which is linearly related to temperature. The datasheet gives a graph which seems to state: $V_{out} = 10\frac{mV}{^\circ C}T+500mV$.

We can then invert this equation to find the temperature in Celcius is $T_C=50\left(2V_{out}-1\right)$ where $V_{out}$ is measured in Volts. The wiring for the sensors is sketched here:




In the Arduino code, we simply poll the input pins each loop and display the converted quantities. One final quirk - there is no degree sign that I could find in standard ascii. Luckily, the LCD allows you to program your own characters. This is a relief since it allows me to avoid using Fahrenheit. To build your own character, you just treat each row of 5 as a 5-bit binary number, with 1's where you want a pixel lit. There is a nice tool on the web which allows you draw your own character and it gives you the resultant binary number array. That's all we need. The code is:
#include 

// Connections:
// rs (LCD pin 4) to Arduino pin 4
// enable (LCD pin 6) to Arduino pin 5
// LCD pins d4-d7 to Arduino pins 9-12
LiquidCrystal lcd(4, 5, 9, 10, 11, 12);
// Input pins
const int LIGHT = A0;
const int TEMP = A1;
// Varibales to store temperature value
int tmp = 0;
// To hold text strings
char tVal[4];
char lVal[4];
// Create custom "degree" character pixelmap
byte deg[8] = {B110,B1001,B1001,B110,B0,B0,B0};
void setup()
{
  // Set up input pins
  pinMode(LIGHT,INPUT);
  pinMode(TEMP,INPUT);
  // initial custom character(s)
  lcd.createChar(1, deg);
  lcd.begin(20,4);              // Initialize a 20x4 HD44780-compatible LCD
  lcd.clear();                  // clear the screen
}

void loop()
{
// Static display text
  lcd.setCursor(0,0);
  lcd.print("Light Sensor:");
  lcd.setCursor(0,2);          
  lcd.print("Temperature (TM36)");

// Converst the voltage accross the thermistor to a temperature.
  tmp = ((675.0*analogRead(TEMP)/1280)-50.0);
// Read the value of the photoresistor, in arbitrary units into a string.
  sprintf(lVal,"%d",5*analogRead(LIGHT));
// and print to the LCD  
  lcd.setCursor(0,1);
  lcd.write(lVal);
  lcd.write("mV");
// I had to insert a delay, otherwise the display looked flickery.
  delay(200);
  lcd.clear(); // Prabably best to clear() directly after the delay
  sprintf(tVal,"%d",(int)tmp);
  lcd.setCursor(0,3);  
  lcd.write(tVal);
//  lcd.setCursor(2,3);  
  lcd.write(byte(1));
//  lcd.setCursor(3,3);
  lcd.write("C");
} 


Finally, here is the end result - and opto-temperature sensor:



Next, to toy with the motors and to try and built a python based oscilloscope.