Sunday, March 26, 2017

Study the capability of the RF transmitter ( FS1000A/XY-FST) and the receiver (XY-MK-5V).


Objective: 


Top is ( FS1000A/XY-FST) and the bottom RF receiver (XY-MK-5V).




Use Arduino to produce square wave, and as power supply to the Tx.  A small capaceter add to data pin to reduce noise.

There are three pin.  From let to right are: Data pin, Vcc pin, and GND pin

Rx circuit

Pin from the left to the right are: Vcc, Data1, Data2, and GND.  Note: Data 1 = Data 2

25us delay

The lowest stable frequency is 2Hz.  The receiver's voltage is ~4V.

When frequency is too low, receiver cannot work normally

The highest stable working frequency is 17KHz

1KHz 5% duty cycle work stably

1KHz 95% Duty cycle is not stable.  But, 90% is stable.

The operational frequency range:

  • 2Hz to 17KHz with digital signal only

Power Consumption Range:

  • Rx::30mW, =5Vx 6mA
  • Tx: 35mW=5Vx7mA

Transmission range:

  • 50ft distance in house and with 4 layer of dry wall has been tested
  • Max distance is to be tested...  


Summary:

  • This is a simple and effective device digital RF Tx/Rx work.  It can work with or without Arduino.  If use it working with Arduino, you may not need library at all.  
  • Try to avoid sending and low frequency signal because it is unstable at low frequency.  During idle time, try to send a based frequency as well.  It does not work well with DC signal (H or L) signal.

Wednesday, March 22, 2017

Arduino Automatic Garage Door Closer

Project Objective:

  • A device to monitor garage door's status.  If the door remains open for too long (for example, people forget to close it).  It will close the door by itself.  Some false positive and negative should be consider to software design to reduce the potential risk by using this device.



Feature: 

  1. Monitor the garage door is opened or closed
  2. If the door is open more then 540 second (9 min), it sounds slow reminder alarm.
  3. If the door remain in opened in 600 second (10 min), it will sound rapid door closing alarm 
  4. After the door switch is triggered, 
    1.  it will check the status of the door in 23 second.  
    2. 23 second is the door close and re-open cycle time if something/someone prevent the door from closing.
  5. If the door is still closed, it will back to normal monitor cycle. 
  6. If the door is still opened, it will attempt to close it again, and then stay in the infinity loop with error reminder (blanking LED and chipping) 
  7. Risk assessment, What if:
    1. FP: it will attempt to close the door twice.  It will end up just open and close the door.  
    2. FN: it will do nothing.
    3. The overall risk is low for using this device.
  8. It communicates to user with simple Morse code, such as "Hi" after initialized, or "D" after closing the garage door. 


Component List:

  • 1x Arduino Nano
  • 1x HC-SR04
  • 1x PC817 (or equivalent)
  • 1x A-1557 (or equivalent) 
  • 1x Red LED
  • 1x Green LED
  • 1x 5V Buzzer 
  • 1x 10K ohm resistor 
  • 1x 170 ohm LED resistor, (or any similar resistor)
  • 1x 440 ohm LED resistor, (or any similar resistor)
  • 1x 110 ohm PC817 resistor, (or any similar resistor)
  • 5V power supply
  • 1x power switch (for power supply)
  • 1x power switch or jumper (for mode selection)
  • 2x quick connector
  • Wires
  • Project enclosure box


Schematic:

It is a simple schematic (please excuse my chicken scratch...)

Breadboarding.  It is for example only, a bit difference from schematic. When you build it, please only reference to schematic

Assembly and integration.  Add a power switch.
Quick Connection for power and door switch
Installed on top of garage door.
It does NOT detecting door id open.


It detects the garage door is open (the red LED is ON)


Demo 1 (Normal operation.  User just forget to close the garage door.)



Demo 2 (None standard operation.  For example, someone or some thing prevent the door from closing)


Arduino Code:

/* Automatic Garage Door Closer Project
 *
 * Author: Samson Yang
 * Date: 3/20/2017
 *
 * Feature:
 *  1. Monitor the garage door is opened or closed
 *  2. If the door is open more then 540 second (9min), it sounds slow reminder alarm.
 *  3. If the door remain in opened in 600 second (10 min), it will sound rapid door closing alarm
 *  4. After the door switch is trigered,
 *    a. it will check the status of the door in 23 second.
 *    b. 23 second is the door close and re-open cycle time if something/someone prevent the door from closing.
 *  5. If the door is still closed, it will back to normal monitor cycle.
 *  6. If the door is still opened, it will attemp to close it again, and then stay in the inifinity loop with error reminder (blanking LED and chipping)
 *  7. Risk assesment, What if:
 *    a. FP: it will attemp to close the door twice.  It will end up just open and close the door.
 *    b. FN: it will do nothing.
 *    c. The overall risk is low for using this device.
 *  
 *  Note:
 *  * FP(false positive, dooe is closed, but sensor say it is opened).
 *  * FN(false negative, door is opened, but sensor say it is closed).
 *
 *  Pin Arrangement:
 *  D2 --> Garage door switch
 *  D4 --> Door status red LED
 *  D5 --> Test mode selection (with pull up)
 *  D7 --> US Trigger
 *  D8 --> US Echo
 *  D9 --> Buzzer
 *  
 *  
*/
#include <TimeLib.h>
bool buzer = 1;
int Pre_closing_alarm_time=540;   //after 9 minutes sound reminder
int Closing_door_time=600;        //after 10 minutes close door
int Closed_Door_Threshold=600;
int Time_check_door_is_closed=23000;  //Wait 23 sec, if door cannot be closed, it can be detected after 23 seconds.
long int count=0;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);
  pinMode(2, OUTPUT);   //Door Control switch
  pinMode(4, OUTPUT);   //Door status indicator
  pinMode(7, OUTPUT);   //Triger pin
  pinMode(9, OUTPUT);  //Alarm pin

  pinMode(8, INPUT);    //Counting pin
  pinMode(5, INPUT);    //Test pin, 1: testing, 0:Normal

  digitalWrite(2, LOW);
  digitalWrite(4, LOW);
  digitalWrite(7, LOW);
  digitalWrite(9, LOW);




  //Test mode when pin 5 is high
  if(digitalRead(5)){
    Pre_closing_alarm_time=3;
    Closing_door_time=7;
    Time_check_door_is_closed=10000;
  }
  say_hi();
}

int door_open_time=0;
void loop() {
  int time_gap=0;
  //count=0;

  bool door_status = check_door();

  //Check how much time the door has been opened
  time_gap=now()-door_open_time;

  //Door is opened
  if (door_status) {
    digitalWrite(4, HIGH); //Turn on door status indicator LED
    if (time_gap>Pre_closing_alarm_time){
      digitalWrite(9, buzer);
      buzer=!buzer;
      }
    }
 
  else {
    //Door is closed
    digitalWrite(4, LOW); //Turn off door status indicator LED
    door_open_time=now();
    digitalWrite(9, LOW); //Turn off buzer
  }

  //Check is it time to close the door
  if (time_gap>Closing_door_time){
    close_door();
    door_open_time=now();
  }

  //Send message out
  Serial.print("");Serial.print("  ");
  Serial.print(now());Serial.print("  ");Serial.println(door_open_time);

  //Max frequency is 10Hz, or use 100 or higher value
  delay(500);                    
}

void close_door(){
  int i;
  buzer = 1;
  for (i = 1;i<50;i++){
    digitalWrite(9, buzer);
    buzer=!buzer;
    delay(50);
  }
  digitalWrite(9, LOW);//Turn off buzer

  //Close garage door
  digitalWrite(2, HIGH);
  delay(1000);
  digitalWrite(2, LOW);

  delay(Time_check_door_is_closed);
  if (!check_door()) say_done();
  else {
    //Something wrong, and show slow blanking door status LED.
    //Try close and the door 2nd times  
    //It should mitigate FP (false positive).  Its means door is closed, but sensor think it is opened issue.
    //If there is FP, the second dooe closing activity, will close the door when the first FP open the door.
    buzer = 1;
    for (i = 1;i<100;i++){
      digitalWrite(9, buzer);
      buzer=!buzer;
      delay(100);
    }
    digitalWrite(9, LOW);//Turn off buzer
 
    //Close garage door
    digitalWrite(2, HIGH);
    delay(1000);
    digitalWrite(2, LOW);

    //Infinity loop and show blanking door status LED.
    while (1){
      digitalWrite(4, HIGH);
      delay(200);S();
      digitalWrite(4, LOW);
      delay(3000);
   
    }  
  }
}

bool check_door(){
  //if Closed return 0
  //if Opened return 1
  long int count_in=0;

  //Triger the signal
  digitalWrite(7, HIGH);
  digitalWrite(7, LOW);
 
  //Wait ultra sound echo
  while (!digitalRead(8));

  //Measure the distance
  while (digitalRead(8)){count_in++;}

  if (count_in<Closed_Door_Threshold)
    {return 1;}
  else
    {return 0;}
}

void say_done(){
  //Say mose code D (it means done)
  L();S();S();
}

void say_hi(){
  S();S();S();S();_();S();S();
}

void L(){
  digitalWrite(9, HIGH);
  delay(300);
  digitalWrite(9, LOW);
  delay(50);
}

void S(){
  digitalWrite(9, HIGH);
  delay(100);
  digitalWrite(9, LOW);
  delay(50);
}

void _(){
  digitalWrite(9, LOW);
  delay(300);
}

Saturday, March 11, 2017

Arduino TVOut Project

Objective:

    Experience with TVOut library with Arduino.


Software:

  • Download library from https://github.com/Avamander/arduino-tvout/
  • Note: For some reason, I cannot use the library as is.  During compiling, it pop up below error message.  I stuck in this step for weeks.




  • After I copy all files except README.md from under TVoutfronts folder, and paste them to its upper level folder TVOUT.  I can compile this Arduino code now.  :) If anyone know why this is happening, please let me know.  Thanks.



Copy file from above folder 


Paste file to above folder location


Reference website:



Hardware setup:

Arduino Uno Pin 9: Sync
Arduino Uno Pin 7: Video


Simple Hardware Setup


Arduino Code -1:

#include <TVout.h>
#include <fontALL.h>

TVout TV;
int sensorPin = A0;
int sensorValue = 0;

void setup()  {
  TV.begin(NTSC);  
  TV.select_font(font6x8);
}

void loop() {
  int x, y;

  TV.draw_line(0,0,0,95,1);
  TV.draw_line(0,0,127,0,1);
  TV.draw_line(0,95,127,95,1);
  TV.draw_line(127,0,127,95,1);

  for(y=0;y<TV.vres();y++){
    for(x=0;x<TV.hres();x++){
      TV.set_cursor(40,43);TV.print("(");TV.print(x);TV.print(", ");TV.print(y);TV.print(")  ");
      TV.set_pixel(x,y,2);
    }
  }
  TV.clear_screen(); 
}


Simple Demo

Arduino Code -2:


#include <TVout.h>
#include <fontALL.h>
#include "schematic.h"
#include "TVOlogo.h"

TVout TV;

int zOff = 150;
int xOff = 0;
int yOff = 0;
int cSize = 50;
int view_plane = 64;
float angle = PI/60;

float cube3d[8][3] = {
  {xOff - cSize,yOff + cSize,zOff - cSize},
  {xOff + cSize,yOff + cSize,zOff - cSize},
  {xOff - cSize,yOff - cSize,zOff - cSize},
  {xOff + cSize,yOff - cSize,zOff - cSize},
  {xOff - cSize,yOff + cSize,zOff + cSize},
  {xOff + cSize,yOff + cSize,zOff + cSize},
  {xOff - cSize,yOff - cSize,zOff + cSize},
  {xOff + cSize,yOff - cSize,zOff + cSize}
};
unsigned char cube2d[8][2];


void setup() {
  TV.begin(NTSC,120,96);
  TV.select_font(font6x8);
  intro();
  TV.println("I am the TVout\nlibrary running on a freeduino\n");
  TV.delay(2500);
  TV.println("I generate a PAL\nor NTSC composite  video using\ninterrupts\n");
  TV.delay(2500);
  TV.println("My schematic:");
  TV.delay(1500);
  TV.bitmap(0,0,schematic);
  TV.delay(10000);
  TV.clear_screen();
  TV.println("Lets see what\nwhat I can do");
  TV.delay(2000);
  
  //fonts
  TV.clear_screen();
  TV.println(0,0,"Multiple fonts:");
  TV.select_font(font4x6);
  TV.println("4x6 font FONT");
  TV.select_font(font6x8);
  TV.println("6x8 font FONT");
  TV.select_font(font8x8);
  TV.println("8x8 font FONT");
  TV.select_font(font6x8);
  TV.delay(2000);
  
  TV.clear_screen();
  TV.print(9,44,"Draw Basic Shapes");
  TV.delay(2000);
  
  //circles
  TV.clear_screen();
  TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/3,WHITE);
  TV.delay(500);
  TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/2,WHITE,INVERT);
  TV.delay(2000);
  
  //rectangles and lines
  TV.clear_screen();
  TV.draw_rect(20,20,80,56,WHITE);
  TV.delay(500);
  TV.draw_rect(10,10,100,76,WHITE,INVERT);
  TV.delay(500);
  TV.draw_line(60,20,60,76,INVERT);
  TV.draw_line(20,48,100,48,INVERT);
  TV.delay(500);
  TV.draw_line(10,10,110,86,INVERT);
  TV.draw_line(10,86,110,10,INVERT);
  TV.delay(2000);
  
  //random cube forever.
  TV.clear_screen();
  TV.print(16,40,"Random Cube");
  TV.print(28,48,"Rotation");
  TV.delay(2000);
  
  randomSeed(analogRead(0));
}

void loop() {
  int rsteps = random(10,60);
  switch(random(6)) {
    case 0:
      for (int i = 0; i < rsteps; i++) {
        zrotate(angle);
        printcube();
      }
      break;
    case 1:
      for (int i = 0; i < rsteps; i++) {
        zrotate(2*PI - angle);
        printcube();
      }
      break;
    case 2:
      for (int i = 0; i < rsteps; i++) {
        xrotate(angle);
        printcube();
      }
      break;
    case 3:
      for (int i = 0; i < rsteps; i++) {
        xrotate(2*PI - angle);
        printcube();
      }
      break;
    case 4:
      for (int i = 0; i < rsteps; i++) {
        yrotate(angle);
        printcube();
      }
      break;
    case 5:
      for (int i = 0; i < rsteps; i++) {
        yrotate(2*PI - angle);
        printcube();
      }
      break;
  }
}

void intro() {
unsigned char w,l,wb;
  int index;
  w = pgm_read_byte(TVOlogo);
  l = pgm_read_byte(TVOlogo+1);
  if (w&7)
    wb = w/8 + 1;
  else
    wb = w/8;
  index = wb*(l-1) + 2;
  for ( unsigned char i = 1; i < l; i++ ) {
    TV.bitmap((TV.hres() - w)/2,0,TVOlogo,index,w,i);
    index-= wb;
    TV.delay(50);
  }
  for (unsigned char i = 0; i < (TV.vres() - l)/2; i++) {
    TV.bitmap((TV.hres() - w)/2,i,TVOlogo);
    TV.delay(50);
  }
  TV.delay(3000);
  TV.clear_screen();
}

void printcube() {
  //calculate 2d points
  for(byte i = 0; i < 8; i++) {
    cube2d[i][0] = (unsigned char)((cube3d[i][0] * view_plane / cube3d[i][2]) + (TV.hres()/2));
    cube2d[i][1] = (unsigned char)((cube3d[i][1] * view_plane / cube3d[i][2]) + (TV.vres()/2));
  }
  TV.delay_frame(1);
  TV.clear_screen();
  draw_cube();
}

void zrotate(float q) {
  float tx,ty,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    ty = cube3d[i][1] - yOff;
    temp = tx * cos(q) - ty * sin(q);
    ty = tx * sin(q) + ty * cos(q);
    tx = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][1] = ty + yOff;
  }
}

void yrotate(float q) {
  float tx,tz,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    tz = cube3d[i][2] - zOff;
    temp = tz * cos(q) - tx * sin(q);
    tx = tz * sin(q) + tx * cos(q);
    tz = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][2] = tz + zOff;
  }
}

void xrotate(float q) {
  float ty,tz,temp;
  for(byte i = 0; i < 8; i++) {
    ty = cube3d[i][1] - yOff;
    tz = cube3d[i][2] - zOff;
    temp = ty * cos(q) - tz * sin(q);
    tz = ty * sin(q) + tz * cos(q);
    ty = temp;
    cube3d[i][1] = ty + yOff;
    cube3d[i][2] = tz + zOff;
  }
}

void draw_cube() {
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[1][0],cube2d[1][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[2][0],cube2d[2][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[4][0],cube2d[4][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[5][0],cube2d[5][1],WHITE);
}