Close

Final

A project log for Little Monster Scanner

In preparation for Halloween this year I want to make a scanner to find those "little monsters" for some animatronics fun.

agpcooperagp.cooper 01/09/2018 at 13:000 Comments

Final

Here is the arduino code:

/*
  Little Monster Scanner 
  ======================
  Written by Alan Cooper (agp.cooper@gmail.com)
  This work is licensed under the 
  Creative Commons Attribution - Non Commercial 2.5 License.
  This means you are free to copy and share the code (but not to sell it).
  Also it is good karma to attribute the source of the code.
*/

#define DirX    2  // Reserved for Head 1
#define DirY    3  // Reserved for Head 2
#define DirZ    4  // Scanner
#define StepX   5  // Reserved for Head 1
#define StepY   6  // Reserved for Head 2
#define StepZ   7  // Scanner
#define Enable  8  // Enable all stepper motors (active LOW)
#define Sensor1 A4 // SE-10 PIR Scanner (active LOW)
#define Sensor2 A5 // Reserved for RCWL-0516 (active LOW)
#define N       19 // Sample array size

volatile bool scanDone=false;
volatile byte forwardScan[N];
volatile byte reverseScan[N];

volatile unsigned int magic=0;
volatile int dirFlag=0;
volatile int stepCount=1200+80;  // Offset for sensor zero (+4.5 degrees)
volatile int stepTrip=2400;      // +/-60 degrees (400 step motor and 1/16 mircosteps)
volatile int index=0;            // Used to save data to an array
ISR(TIMER2_OVF_vect)
{
  static unsigned int phase=0;
  if (phase<0x8000) {
    phase+=magic;
    if (phase>=0x8000) {
      digitalWrite(StepZ,LOW);
    }
  } else {
    phase+=magic;
    if (phase<0x8000) {
      digitalWrite(StepZ,HIGH);
      stepCount++;
      index=(stepCount>>7); // 0 to N-1
      if (dirFlag==0) {
        if (digitalRead(Sensor1)==LOW) {
          forwardScan[index]=1;
        } else {
          forwardScan[index]=0;
        }
      } else {
        if (digitalRead(Sensor1)==LOW) {
          reverseScan[N-1-index]=1;
        } else {
          reverseScan[N-1-index]=0;
        }
      }
      if (stepCount>stepTrip) {
        stepCount=0;
        dirFlag=1-dirFlag;
        if (dirFlag==1) {
          digitalWrite(DirZ,HIGH);
        } else {
          digitalWrite(DirZ,LOW);
        }
        scanDone=true;
      }
    }
  }
}

void setup()
{
  // LED
  pinMode(LED_BUILTIN,OUTPUT);
  pinMode(DirZ,OUTPUT);
  pinMode(StepZ,OUTPUT);
  pinMode(Enable,OUTPUT);
  pinMode(Sensor1,INPUT_PULLUP);  // Sensor1 is open collector
  digitalWrite(LED_BUILTIN,HIGH); // Off
  digitalWrite(DirZ,LOW);
  digitalWrite(StepZ,LOW);        
  digitalWrite(Enable,LOW);       // On
  
  // Use Timer 2 for ISR
  // Good for ATmega48A/PA/88A/PA/168A/PA/328/P
  cli();
  TIMSK2=0;                                                 // Clear timer interrupts
  TCCR2A=(0<<COM2A0)|(0<<COM2B0)|(3<<WGM20);                // Fast PWM
  TCCR2B=(1<<WGM22)|(2<<CS20);                              // 2 MHz clock and (Mode 7)
  OCR2A=243;                                                // Set for 8197 Hz
  OCR2B=121;                                                // PWM 50% - Not used
  TIMSK2=(1<<TOIE2)|(0<<OCIE2A)|(0<<OCIE2B);                // Set interrupts
  sei();


  Serial.begin(9600);
  delay(200);
  
  // Pause to align scanner
  Serial.println("Little Monster Scanner V1.0");
  Serial.flush();
  Serial.println("Waiting 10s for alignment of scanner");
  Serial.flush();
  delay(10000);
  
  // Update frequency without interrupt (Note frequency should be between 1 and 4095)
  unsigned int freq=400;                  // Using 400 step motor and 1/16 microsteps 
  cli();
  magic=(freq<<3);
  sei();

}

void loop()
{
  int i,tmp,cnt,mean;

  if (scanDone) {
    scanDone=false;
    mean=0;
    cnt=0;
    for(i=0;i<N;i++) {
      tmp=reverseScan[i]+forwardScan[i];
      mean+=i*tmp;
      cnt=cnt+tmp;
    }
    if (cnt>0) {
      mean=mean/cnt;
    } else {
      mean=N/2;
    }
    for(i=0;i<mean;i++) Serial.print('.');
    if (cnt>0) {
      Serial.print('*');
    } else {
      Serial.print(':');      
    }
    for(i=mean+1;i<N;i++) Serial.print('.');
    Serial.println();     
  }
}

An ISR runs the stepper motor and the mean uses forward and reverse scans.

Here is me sitting in my partners chair:

Little Monster Scanner V1.0
Waiting 10s for alignment of scanner
.........:.........
.........:.........
.........:.........
.........:......... Behind scanner (no signal)
...........*....... Walking to seat (crossing scanner path)
.........*......... Seated (scanner centred on seat)
.........*......... Seated (scanner centred on seat)
.........*......... Seated (scanner centred on seat)
........*.......... Walking left of scanner
........*.......... Wakling left of scanner
.........:......... Behind scanner (no signal)
.........:.........
.........:.........

So it is now ready (except for the controller box) to drive some spooky head(s).

AlanX

Discussions