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);
    }
}

Thanks for all

Thanks for all evden eve nakliyat
evden eve nakliyat comments evden eve nakliyat please go on

That's pretty awesome. I've

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
Copy the characters (respecting upper/lower case) from the image.