[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 핀 측정
 
 
댓글 없음:
댓글 쓰기