Arduino Semaphor

I saw a Monty Python skit that used semaphore. It was interesting so I decided to built a robot semaphore system.

I bought two smaller steppers from recycledgoods.com. They are pretty low power so I was able to power them from USB. I used an LCD from fungizmos.com to show the letter that is being flagged.

The circuit to drive the stepper and lcd is pretty standard. There is a good stepper tutorial on the arduino site. Fungizmo has the circuit for the LCD.

My arduino code basically reads a number from serial input. The number must be in the range from 00 to 26. With 00 = space, 01 = A and so on. Once it reads the number, the arduino then drives the steppers to flag the letter. I wrote a little perl program that will read from standard input, then send the characters over serial to the arduino, one character at a time. That way I can just cat | any text file into the arduino.

arduino setup
My arduino code:

#include 
#include 

int lcd_addr = 0x50;		//default I2C hex address from datasheet

// change this to the number of steps on your motor
// My stepper is 7.5 degrees per step, or 48 steps per revolution
#define STEPS 48

// create an instance of the stepper class, specifying
// the number of steps of the motor and the pins it's
// attached to

Stepper leftFlag = Stepper (STEPS, 8, 10, 9, 11);
Stepper rightFlag = Stepper (STEPS, 7, 5, 6, 4);

// Set stepper starting position
int leftFlagStep = 48;
int rightFlagStep = 0;

int incomingByte1 = 0;		// for incoming serial data
int incomingByte2 = 0;		// for incoming serial data

int debug = 0;

// LCD buffer
char lcd[20] = "Ready          ";

// Letter array. we read a number over serial, then convert it to a letter 
char letters[] =
  { ' ', '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'
};

//  Create and array that has the flag positions.  
// 395 = 54
// 360 = 48
// 315 = 42 
// 270 = 36 
// 225 = 30 
// 180 = 24 
// 135 = 18
//                           0   1   2   3   4   5   6   7   8   9  10  11  12  13 
 14  15  16  17  18  29  20  21  22  23  24  25  26 
//                          '',  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 
int leftFlagPositions[] =
  { 48, 48, 48, 48, 48, 29, 36, 42, 54, 54, 36, 24, 30, 36, 42, 18, 24, 30,
  36, 42, 24, 30, 42, 36, 42, 36, 36
};

// 225= 30
// 180= 24
// 135= 18
// 90 = 12
// 45 =  6
//  0 =  0
int rightFlagPositions[] =
  { 0, 6, 12, 18, 24, 0, 0, 0, 12, 18, 24,
 6, 6, 6, 6, 12, 12, 12, 12, 12, 18,
  18, 24, 30, 30, 18, -6
};

void
setup ()
{

  delay (1000);			//allow lcd to wake up.

  Wire.begin ();		//initialize Wire library

  // Wire library expects 7-bit value for address and shifts left appending 0 or 1 for read/write
  // Lets adjust our address to match what Wire is expecting (shift it right one bit)
  lcd_addr = lcd_addr >> 1;

  //Send lcd clear command
  Wire.beginTransmission (lcd_addr);
  Wire.send (0xFE);		//Cmd char
  Wire.send (0x51);		//Home and clear
  Wire.send (lcd);              // Put up the default message

  Wire.endTransmission ();

  // set the speed of the motor to 30 RPMs
  leftFlag.setSpeed (30);
  rightFlag.setSpeed (30);

  Serial.begin (19200);		// opens serial port, set data rate 
}

void
loop ()
{
  // check for incoming data 
  if (Serial.available () > 0)
    {
      if (Serial.available () == 2)
	{
	  // read the incoming 2 bytes then convert them to an integer
	  // convert from ascii
	  // This number will correspond to the letter to semaphore. A = 01, B = 02 and so on
	  incomingByte2 = Serial.read ();
	  incomingByte1 = Serial.read ();
	  setFlags ((incomingByte1 - 48) + 10 * (incomingByte2 - 48));
	}
      else
	{

	}
    }
}


// Move the flags to make the letter
void
setFlags (int letter)
{

  lcdPrint (letter);

  if (debug)
    {
      Serial.print ("letter = ");
      Serial.println (letter, DEC);
    }

  do
    {
      if (leftFlagStep > leftFlagPositions[letter])
	{
	  leftFlag.step (-1);
	  leftFlagStep--;
	}

      if (rightFlagStep > rightFlagPositions[letter])
	{
	  rightFlag.step (-1);
	  rightFlagStep--;
	}

      if (leftFlagStep < leftFlagPositions[letter])
	{
	  leftFlag.step (1);
	  leftFlagStep++;
	}

      if (rightFlagStep < rightFlagPositions[letter])
	{
	  rightFlag.step (1);
	  rightFlagStep++;
	}
    }
  // Loop as long as one of the flags needs to move
  while (leftFlagPositions[letter] != leftFlagStep
	 || rightFlagPositions[letter] != rightFlagStep);

  // Send out a "Z" to signal we have finished this letter
  Serial.println ("Z");
}

void
lcdPrint (int letter)
{

  // Shift everything in the LCD buffer to the left
  // Then print it to the LCD screen
  for (int cnt = 0; cnt < 16; cnt++)
    {
      lcd[cnt] = lcd[cnt + 1];
    }
  lcd[15] = letters[letter];

  Wire.beginTransmission (lcd_addr);
  Wire.send (0xFE);		//Cmd char
  Wire.send (0x46);		//Home and clear
  Wire.endTransmission ();


  Wire.beginTransmission (lcd_addr);
  Wire.send (lcd);
  Wire.endTransmission ();
}

The perl code is pretty straightforward. It reads from standard input, converts the characters to numbers, then writes the numbers to the arduino over the serial port. The syntax is: cat rickroll.txt | perl ./semaphore.pl

Here is my perl code:

use Device::SerialPort;

# Set up the serial port
# 19200, 81N on the USB ftdi driver
my $port = Device::SerialPort->new("/dev/ttyUSB0");
$port->databits(8);
$port->baudrate(19200);
$port->parity("none");
$port->stopbits(1);

# hash of letters
# send the letter number to the arduino
%letter = (
    ' ' => '00',
    'a' => '01',
    'b' => '02',
    'c' => '03',
    'd' => '04',
    'e' => '05',
    'f' => '06',
    'g' => '07',
    'h' => '08',
    'i' => '09',
    'j' => '10',
    'k' => '11',
    'l' => '12',
    'm' => '13',
    'n' => '14',
    'o' => '15',
    'p' => '16',
    'q' => '17',
    'r' => '18',
    's' => '19',
    't' => '20',
    'u' => '21',
    'v' => '22',
    'w' => '23',
    'x' => '24',
    'y' => '25',
    'z' => '26',
);


#  Read the characters from standard in
while () {
    $_ =~ tr/A-Z/a-z/;
    $_ =~ s/[^a-z ]+//gi;
    @chars = split( //, $_ );

    foreach $character (@chars) {
        print $character;
        print "Sending " . $letter{$character} . "\n";

        $port->write( $letter{$character} );

        # Poll to see if any data is coming in
        # Wait for the arduino to tell us it is finished with the last letter
        my $response = '';
        while ( !$response ) {
            $response = $port->lookfor();
        }

        # just wait for a second 
        sleep(1);
    }
}

Comments

Anonymous:

I've only being experimenting with my Arduino for about a month now, but I hope to get this skilled in time.Dissertation Help | Essay Writing | Research Paper Help

Claudine:

vous êtes vraiment un génie! Tous inventé et réalisé par nous-mêmes!

Anonymous:

ovvvvv all right :)

ovvvvv all right :)

ovvvvv all right :)
film indir film indir film izle
film izle
SpooExi
dizi izle
mp3 indir
sex porno izle

Nate C.:

How are you getting a variable to display in the LCD screen? All I can get to display are strings.
I have int counter = 1; set at the top and I have tried everything below:

Wire.send("counter");
Wire.send('counter');
Wire.send(counter);

All with no luck. Any help would be appreciated

Eddy:

How did you figure that out dude?You must be a genius!
I am still doing the stepper tutorial.

----------
online drugs are addictive!

Joshua:

That's pretty awesome. I've only being experimenting with my Arduino for about a month now, but I hope to get this skilled in time.

Post new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
This question is used to make sure you are a human visitor and to prevent spam submissions.
Image CAPTCHA
Enter the characters shown in the image.