TinyProjector Lab Notebook

top | summary | prototypes | original proposal | diary

previous section 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12



Diary of May 2002 16-31

 

May 16, 2002

I wrote new PIC code that intercepts serial input even during projection, using the KBHIT function (tp2_cont.c) (Figure 114). It works nicely with the Java iDen phone. I also fixed several other bugs: messed up character templates; detects now both lowercase and uppercase single characters; preset lines are limited to 8 characters, etc.

 

#include <16F877.h>

 

// File name: tp2_cont.c

 

// Configure PIC to use: HS clock, no Watchdog Timer,

// no code protection, enable Power Up Timer

 

#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP

 

// Tell compiler clock is 4MHz.  This is required for delay_ms()

// and for all serial I/O.  These functions use software delay

// loops, so the compiler needs to know the processor speed.

 

#use Delay(Clock=4000000)

 

// Declare that we'll manually establish the data direction of

// each I/O pin on ports A, B, and C.

 

#use fast_io(A)

#use fast_io(B)

#use fast_io(C)

#use fast_io(D)

 

#use RS232(Baud=9600,xmit=PIN_A0,Rcv=PIN_A3,INVERT)

 

// Set variable that maps to memory

#byte PORTA = 5

#byte PORTB = 6

#byte PORTC = 7

#byte PORTD = 8

 

#define MAX_CHAR 8

#define DELAY_TI 16500

 

 

byte _ALL[5] = {

  0b00000000,

  0b00000000, 

  0b00000000,

  0b00000000,

  0b00000000 };

 

byte _SPACE[5] = {

  0b11111111,

  0b11111111,

  0b11111111,

  0b11111111,

  0b11111111 };

 

byte _EXCL[5] = {

  0b11111111,

  0b11111111,

  0b01100000,

  0b11111111,

  0b11111111 };

 

byte _A[5] = {

  0b00000001,

  0b11101110,

  0b11101110,

  0b11101110,

  0b00000001 };

 

byte _B[5] = {

  0b00000000,

  0b01110110,

  0b01110110,

  0b01110110,

  0b10001001 };

 

byte _C[5] = {

  0b10000001,

  0b01111110,

  0b01111110,

  0b01111110,

  0b10111101 };

 

 

// ETC, ETC, all character templates

 

char char1;

 

int i;

int x;

 

void project3(byte the_character[5], int the_line) {

 

    PORTB = the_character[the_line];

    delay_us(80);

    PORTB = 0xFF;

    delay_us(60);

}

 

void project2(char c, int line_number) {

 

  switch(c){

      case 'A': project3(_A,line_number);

         break;

      case 'a': project3(_A,line_number);

         break;

 

      case 'B': project3(_B,line_number);

         break;

      case 'b': project3(_B,line_number);

         break;

 

      case 'C': project3(_C,line_number);

         break;

      case 'c': project3(_C,line_number);

         break;

 

// ETC, ETC, switching statements for all characters

 

 

      case ' ': project3(_SPACE,line_number);

         break;

      case '!': project3(_EXCL,line_number);

         break;

      case '9': project3(_ALL,line_number);

         break;

 

      default:  project3(_SPACE,line_number);

   }

}

 

void project1(char the_char) {

   int v;

   for (v=0; v<5; v++) {

       project2(the_char, v);

   }

   delay_us(500);

}

 

main() {

  // Since we've declared #use fast_io(A)(B)(C) (above), we MUST

  // include a call to set_tris_a/b/c() at startup.

 

  set_tris_a(0b00001000);  // A3 is input (serial)

  set_tris_b(0b00000000);  // all Bs are outputs

  set_tris_c(0b00000001);  // C0 is input (photodiode)

  set_tris_d(0b00000000);  // all Ds are outputs

 

 

  while(1) {

 

    if (kbhit()) {

      char1 = getc();

    }

 

    switch(char1){

      case '9':

 

           if (input(PIN_C0)) {     // most of the time, diode is not covered:

              PORTB = 0xFF;         // turn lasers off

           }else{                   // at the point where the diode is covered:

              delay_us(DELAY_TI);

 

              for (x=0; x<MAX_CHAR; x++) {

                 project1(char1);

              }

 

           } // end of diode is covered

 

         break;

 

      case '8':

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             project1('H');

             project1('E');

             project1('L');

             project1('L');

             project1('O');

             project1('!');

             project1('!');

 

          } // end of diode is covered

 

        break;

 

      case '7':

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             project1('W');

             project1('E');

             project1('L');

             project1('C');

             project1('O');

             project1('M');

             project1('E');

             project1('!');

 

          } // end of diode is covered

 

        break;

 

     case '6':

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             project1('M');

             project1('E');

             project1('D');

             project1('I');

             project1('A');            

             project1('L');

             project1('A');

             project1('B');

        

          } // end of diode is covered

 

        break;

 

     case '5':

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             project1('T');

             project1('I');

             project1('N');

             project1('Y');

             project1('D');

             project1('E');

             project1('M');

             project1('O');

 

          } // end of diode is covered

 

        break;

 

    case '4':

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             project1('Y');

             project1('O');

             project1('U');

             project1(' ');

             project1('S');

             project1('U');

             project1('C');

             project1('K');

 

          } // end of diode is covered

 

        break;

 

   case '3':

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             project1('O');

             project1('H');

             project1(' ');

             project1('Y');

             project1('E');

             project1('A');

             project1('H');

             project1('!');

 

          } // end of diode is covered

 

        break;

 

   case '2':

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             project1('G');

             project1('O');

             project1(' ');

             project1('H');

             project1('O');

             project1('M');

             project1('E');

             project1('!');         

 

          } // end of diode is covered

 

        break;

 

      default:

 

          if (input(PIN_C0)) {     // most of the time, diode is not covered:

             PORTB = 0xFF;         // turn lasers off

          }else{                   // at the point where the diode is covered:

             delay_us(DELAY_TI);

 

             for (x=0; x<MAX_CHAR; x++) {

                project1(char1);

             }

 

          } // end of diode is covered

 

    } // end of case switch   

 

  } //end of big while loop

 

} // end of main

Figure 114: Final PIC C code for prototype 9: it intercepts serial input even during projection with the KBHIT function (tp2_cont.c). Missing in this listing are only the complete set of character templates, and the complete set of switching statements. For full code, send me email.

 

I wrote another version of the PIC code that detects a drop of the photodiode pin (tp2_ger.c): it starts the blinking sequence only when there is a high pin immediately before a low pin. This was a suggestion of Gerardo. It did not make the jitter go away, but the projector misses now many cycles. I did not pursue this approach.

 

 

I made a new servo arm out of aluminum, salvaged from a square aluminum tube. I removed the ABS one (although it was glued with Epoxy, it came off easily), Krazy glued the aluminum arm to the motor, and oiled the pushrod/hole with WD40.

 

The projection is now stable: the beginning of the sentence certainly is, the end (after 8 characters) fluctuates a little, due to irregular rotational speed of the motor. Basically, the length of the sentence varies with the speed of the motor. If the motor speed goes up, the sentence gets stretched, etc.

 

I took several pictures and movies of the projection (Figure 115). (Choosing the amount of ambient light turned out to be tricky, because it is either too dark and the projection gets smeared, or too bright and then the projection does not have a lot of contrast.)

 

 

 

 

 

 

 

Figure 115: Example projections, and a close-up of TinyProjector prototype 9 in the dark (above).

 

Since the jitter was almost gone, I conclude that the jitter problem must have been caused by mechanical slack of the hole in the plastic crank arm that holds the pushrod.

 

Logically, the still remaining jitter could be due to the connection of the pushrod with the mirror, which starts to get loose, too. To make the projection even more stable, I should make a new mirror with an aluminum holder. (But I have to unglue the servo arm from the motor, which is a pain, even with the Krazy glue remover.)

 

 

May 17, 2002

I tried to make a PIC software version that reads the serial port during the delay time before the blinking sequence. I didn't succeed.

 

Fixed other bugs in the PIC software, e.g., initial waiting time is now 16.5ms (16500 us).

 

Started designing an outer hull for the projector, which was going to be prototype 10.

 

 

May 18, 2002

I made a 3D model of all elements, in order to model the outer hull of prototype 10. Made two versions: hull with straight walls (TinyProjector2_all_v3.3dm), and hull with curved walls (TinyProjector2_all_v4.3dm) (Figure 116)

 

Figure 116: Designs for protecting the outside of the laser diode assembly. Straight (left), and curved walls (right)

 

May 19, 2002

I refined the complete 3D model (TinyProjector2_all_v5.3dm), and created some 3D snapshots of hull (Figure 117). It is still not complete, since the motor compartment is not done yet.

 

 

Figure 117: TinyProjector prototype 10



previous section | May 2002 16-31

section 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 12


Send me some comments! Stefan Marti Last updated February 23, 2003.

Copyright © 1997-2004 by Stefan Marti and MIT Media Lab. All rights reserved