2017년 8월 22일 화요일

[8] 영상의 동기화 맞추기

[8] 영상의 동기화 맞추기


1) 라즈베리파이의 인터럽트 이용(실패)


아두이노 듀에서 나오는 톱니파 속도를 정해야 한다.
라즈베리에서의 인터럽트가 잘 디텍팅 되지 않는다.
저번에 했던 코드는 100ms라는 느린 펄스파를 감지한거라서 정확하게 갯수와 rising, falling이 검출되었지만 영상을 본격적으로 하기위해서 짠 아두이노 코드에서 나오는 s_p_signal은 rising을 검출하지 못했다. 또는 rising을 검출할 때는 falling을 검출하지 못함.
저번에 된 코드로 테스트 해보니 이 문제는 아두이노에서 나오는 펄스파의 속도가 빨라서 그랬던 거였음.

주기
주파수
톱니파에 맞추려면
2ms
500Hz
Rpi 인터럽터에 맞추려면
100ms
10Hz


Rpi 인터럽트에 맞추려면 결국 100ms / 512 samples = 195.3125 u/sample
약 200us 주기로 라즈베리파이에서 ADC 신호를 읽으면 된다.


-인터럽트 동기화 문제
wiringPI 라이브러리에서 제공하는 인터럽트 함수를 썻을 때 문제점이 있었다.
1)인터럽트 설정에서 INIT_EDGE_FALLING으로 설정하더라도 falling edge만 디텍팅 하는 것이아니라 rasing edge까지 디텍팅 되었다.
2)rinsing edge와 falling edge 디텍팅 사이의 시간이 100ms 정도가 있어야 정확한 (사직 한 두개 빠질때도 있음) 디텍팅이 되었다.
3)아누이노의 s_p_signal에서 발생되는 falling edge를 검출하면 바로 원하는 루틴으로 들어가서 데이터를 읽기 시작해야 하는 데 아두이노에서 falling edge가 발생한 후 몇 msec의 오랜 시간이 걸린다음에 인터럽트가 발생했다. .... 그래서 동기화가 안맞았음.
.
채널1(노란색) - 아두이노의 s_p_signal 핀 측정
채널2(파란색) - 라즈베리파이의 인터럽트 측정


=>그래서 인터럽트를 포기함.


2) while 문으로 구현


라즈베리파이의 s_p_signal 핀의 값을 계속 확인하면서 whlie문을 계속 돌다가 아두이노에서 falling edge를 보내면 원하는 루틴으로 들어가도록 하였다.
채널1(노란색) - 아두이노의 s_p_signal 핀 측정
채널2(파란색) - 아두이노의 ADC 톱니파


아두이노에서 나오는 ADC 톱니파을 위 사진에서 초록색깔 모듈인 ADC의 입력에 바로 연결하여 이미지를 만들어 보았다.
그 결과 오른쪽에서 왼쪽으로 갈수록 점점 밝아지는 이미지가 나왔다. 이것은 왼쪽으로 갈 수록 아날로그 값이 선형적으로 커지는 것을 의미하므로 정확하게 이미지를 잘 만들었다는 것을 확인할 수 있었다.


3) 미세 떨림 보정
=>하지만 조그만 흔들림이 있었다.
=>이것은 라즈베리파이가 멀티 프로세싱을 하기때문에 그 때 그때 시작하는 시간이 미세하게 달라지기 때문이다.
=>그래서 단순히 데이터를 읽고 약간의 시간 지연을 위해서 usleep()을 쓰는 것이 아니라 프로그램 내부에서 시간을 측정해서 원하는 시간이 되면 while문을 빠져나가도록 하였다.
=> 그 결과 오실로스코프로 보았을 때, 미세한 떨림이 눈으로는 확인하기 힘들 정도로 줄어들었다.  


-convert picture to C code array


원본 이미지와 받은 이미지 비교


arduino due code


//#include "smile.h"
#include "bol.h"

#define ENABLE 0
#define DISABLE 1
#define START 0
#define STOP 1
#define MAXDIGITAL 1024


#define ENABLE_PIN 7
#define DISABLE_PIN 6
#define S_P_SIGNAL_PIN 2
#define OUTPUT_PIN DAC0


volatile int enablePinState;


void makeSawtooth();
void enableISR();
void disableISR();
//void init_img(unsigned char* src);

int raw=0, col=0;
//unsigned char img[256*256] = {0};

void setup(){
//  init_img(img);
 Serial.begin(9600);
 //output
 analogWriteResolution(10);
 analogWrite(OUTPUT_PIN, 512);
 //s_p_signal
 pinMode(S_P_SIGNAL_PIN, OUTPUT);
 digitalWrite(S_P_SIGNAL_PIN, STOP);
 //enable
 pinMode(ENABLE_PIN, INPUT_PULLUP);
 pinMode(DISABLE_PIN, INPUT_PULLUP);
 attachInterrupt(ENABLE_PIN, enableISR, FALLING); //http://m.blog.naver.com/yuyyulee/220310875023
 attachInterrupt(DISABLE_PIN, disableISR, RISING);
 if(digitalRead(ENABLE_PIN)){
   enablePinState=DISABLE;
   //enablePinState=ENABLE;
   Serial.println("first state is DISABLE");
 }else{
   enablePinState=ENABLE;
   Serial.println("first state is ENABLE");
 }

}


void loop(){
 //enablePinState=ENABLE;
 while(enablePinState == DISABLE){

 }

     //speed control
   //  1) 50, 2) 50
   //  3) 10
 delay(50); //delay for STOP signal
 
 digitalWrite(S_P_SIGNAL_PIN, START);  //falling edge

 while(1){
   if(enablePinState == DISABLE){
     analogWrite(OUTPUT_PIN, 512);
     col=0;
     raw=0;
     break;
   }

   analogWrite(OUTPUT_PIN, smile[raw*256+col]*4);
   //speed control
   //  1) 440
   //  2) 220
   delayMicroseconds(220);
   col++;
   if(col == 256){
     col=0;
     break;
   }
 }
 
 digitalWrite(S_P_SIGNAL_PIN, STOP);   //rising edge
 
 analogWrite(OUTPUT_PIN, 512);

 raw++;
 if(raw==256){
   raw = 0;
 }
}





void enableISR(){
 enablePinState = ENABLE;
 Serial.println("enable");
}


void disableISR(){
 enablePinState = DISABLE;
 //enablePinState = ENABLE;
 Serial.println("disable");
}

/*
void init_img(unsigned char* src){
 int i=0, j=0;
 
 for(i=0; i<256; i++){
   for(j=0; j<256; j++){
     src[i*256+j] = j;
   }
 }
}
*/


capcher.h
#ifndef CAPCHERIMAGE_H
#define CAPCHERIMAGE_H

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <wiringPi.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <QtCore>
#include <QMutex>
#include <QThread>
#include "myspi.h"
#include "readdetector.h"
#include <sys/time.h>
#include <unistd.h>
#include "jpeglib.h"

//PIN NUMBER
#define S_P_SIGNAL_PIN 7 //pysical 7
#define SYNCHRONIZATION_PIN 25 //pysical 37

//set value
#define FRAME_NUMBER 1
#define MAXROW 512
#define MAXCOL 1000
#define DELAYSECOND 10
#define START 0
#define STOP 1
#define ERROR -1

//tread state
#define TREAD_START     0
#define TREAD_END       1
#define TREAD_RUNNING   2
#define TREAD_PAUSE     3
#define TREAD_RESUME    4
#define DISPLAY_IMAGE 5

volatile static int s_p_signal = STOP;

class CapcherImage : public readDetector
{
   Q_OBJECT



public:
   QMutex mutex;
   volatile unsigned int* gpio;
   CapcherImage(){readDetector::Init_8bit_GPIO(); m_stop = false; m_pause = false;}
   void readOneFrame(unsigned char* oneFrame);
   void init_Interrupt();
   void arduinoSAWTOOTHWAVE(int command);
   void run();
   void pause() { m_pause = true; }
   void resume() { m_pause = false; m_pauseCondition.wakeAll();}
   int makeJPEG(unsigned char* oneFrame);

private:
   bool m_stop;
   bool m_pause;
   QWaitCondition m_pauseCondition;

signals:
   void state(int treadState);
   void imageMakingProgress(int raw);
};

void interruptISR(void) ;


#endif // CAPCHERIMAGE_H

capcher.cpp
#include "capcherimage.h"

void CapcherImage::run(){

 unsigned char img[256*256]={0};

  qDebug("Image Thread start!"); //"start!!"
  emit state(TREAD_START);

  while(1)
  {
      if (m_pause)
      {
          emit state(TREAD_PAUSE); //"complete!!"
          m_pauseCondition.wait(&mutex);
          emit state(TREAD_RESUME);//"start!!"
      }

      //running code
      arduinoSAWTOOTHWAVE(ENABLE);
      readOneFrame(img);
      arduinoSAWTOOTHWAVE(DISABLE);

      emit state(TREAD_RUNNING); //"image make..."

      if(makeJPEG(img) == ERROR){
          m_pause = TRUE;
          qDebug("make image error!!");
          continue;
      }

      emit state(DISPLAY_IMAGE);

      //running code end


      m_pause = TRUE;

  }

  emit state(TREAD_END); //"complete!!"
  qDebug("Image Thread stop!");
}

void CapcherImage::arduinoSAWTOOTHWAVE(int command){
   if(command == ENABLE){
       digitalWrite(ARDUINO_ENABLE_PIN, ENABLE);
   }else if(command == DISABLE){
       digitalWrite(ARDUINO_ENABLE_PIN, DISABLE);
   }
}

void CapcherImage::readOneFrame(unsigned char *oneFrame){
   int raw = 0, col=0;
   long int start_time;
   long int time_difference;
   struct timespec gettime_now;
   int percent = 0;
   int lock = ON;
   long int in_start_time;
   long int in_time_difference;
   struct timespec in_gettime_now;

   s_p_signal=STOP;
   imageMakingProgress(percent);

   gpio_8bit_usage(ENABLE);

   //while start

   while(1){


       //measure strat time
       clock_gettime(CLOCK_REALTIME, &gettime_now);
       start_time = gettime_now.tv_nsec;


       if(digitalRead(S_P_SIGNAL_PIN) == STOP){
           lock = OFF;
       }

       if(digitalRead(S_P_SIGNAL_PIN) == START && lock == OFF){
            lock = ON;

            /*
            //measure strat time
            clock_gettime(CLOCK_REALTIME, &gettime_now);
            start_time = gettime_now.tv_nsec;
            */

            //speed control
            //     1) 500
            //     2) 30
            //usleep(30);


            //mearsure end time
            do{
                clock_gettime(CLOCK_REALTIME, &gettime_now);
                time_difference = gettime_now.tv_nsec - start_time;
                if(time_difference<0)
                    time_difference += 1000000000;
                //qDebug("msec : %lf", time_difference/1000000.0);
            }while(time_difference < 100000);



            //synchronization test
            digitalWrite(SYNCHRONIZATION_PIN, START);

            while(1){
                //measure strat time
                clock_gettime(CLOCK_REALTIME, &in_gettime_now);
                in_start_time = in_gettime_now.tv_nsec;

                //read
                oneFrame[raw*256 + col] = Read_8bit_GPIO();
                col++;

                //speed control
                //     1) 410
                //     2) 160
                //usleep(160);

                if(col == 256){

                    //synchronization test
                    digitalWrite(SYNCHRONIZATION_PIN, STOP);

                    /*
                    //mearsure end time
                    clock_gettime(CLOCK_REALTIME, &gettime_now);
                    time_difference = gettime_now.tv_nsec - start_time;
                    if(time_difference<0)
                        time_difference += 1000000000;
                    qDebug("msec : %lf", time_difference/1000000.0);
                    */

                    col =0;
                    raw++;


                    if((raw+4) % 26 == 0){
                       int percent = (raw+4)/26;
                       imageMakingProgress(percent); //take 50 usec
                    }


                    break;
                }

                //mearsure end time
                do{
                    clock_gettime(CLOCK_REALTIME, &in_gettime_now);
                    in_time_difference = in_gettime_now.tv_nsec - in_start_time;
                    if(in_time_difference<0)
                        in_time_difference += 1000000000;
                    //qDebug("msec : %lf", in_time_difference/1000000.0);
                }while(in_time_difference < 234000);

            }
        }


        if(raw == 256){
            break;
        }

    }

   //while end

    gpio_8bit_usage(DISABLE);

}

int CapcherImage::makeJPEG(unsigned char *oneFrame){
   const int image_height=256, image_width=256;
   const char *filename = "result.jpeg";

   //initialize image array
   /*
   for(int i=0; i<256*256; i++){
       oneFrame[i] = 200;
   }*/

   struct jpeg_compress_struct cinfo;
   struct jpeg_error_mgr jerr;

   FILE *outfile;
   JSAMPROW row_pointer[1];
   int row_stride;

   cinfo.err = jpeg_std_error(&jerr);
   jpeg_create_compress(&cinfo);

   outfile = fopen(filename, "wb");

   if(outfile  == NULL){
       fprintf(stderr, "can't open %s\n", filename);
       exit(1);
   }

   jpeg_stdio_dest(&cinfo, outfile);

   cinfo.image_width = image_width;
   cinfo.image_height = image_height;
   cinfo.input_components = 1;
   cinfo.in_color_space = JCS_GRAYSCALE;

   jpeg_set_defaults(&cinfo);
   jpeg_set_quality(&cinfo, 75, TRUE);

   jpeg_start_compress(&cinfo, TRUE);

   row_stride = image_width * 1;

   while(cinfo.next_scanline < cinfo.image_height){
       row_pointer[0] = &oneFrame[cinfo.next_scanline * row_stride];
       (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
   }

   jpeg_finish_compress(&cinfo);

   fclose(outfile);
   qDebug("image file is created");

   return 0;

}

void CapcherImage::init_Interrupt(){

   pinMode(S_P_SIGNAL_PIN, INPUT);
   pullUpDnControl(S_P_SIGNAL_PIN, PUD_UP);
   pinMode(SYNCHRONIZATION_PIN, OUTPUT);

/*
   if ( wiringPiISR (S_P_SIGNAL_PIN, INT_EDGE_FALLING, &interruptISR) < 0 ) {
     fprintf (stderr, "Unable to setup ISR: %s\n", strerror (errno));
     exit(-1);
   }
   */
}



void interruptISR(void) {

   char val = digitalRead(S_P_SIGNAL_PIN);
   if(val == LOW){
       s_p_signal = START;
       //qDebug("falling edge detected");
   }
   else if(val == HIGH){
       s_p_signal = STOP;
       //qDebug("rising edge detected");
   }
}






프로그램 수행 시간 측정


-clock_gettime()


채널1(노란색) - 라즈베리파이의 enable 핀 측정

채널2(파란색) - 아두이노의 s_p_signal 핀 측정

댓글 없음:

댓글 쓰기

clear images were obtained