2015年10月30日 星期五

Processing: Get Datas From Adafruit BNO055 Sensor

since: 2015/10/30
update: 2015/11/01

reference:
1. Adafruit BNO055 Absolute Orientation Sensor

A. 硬體:

    1. Adafruit BNO055 Sensor
    2. Arduino Nano
    3. Mac OS X

-----------------------------------------------------------------------------------------------

B. 軟體:
    1. Arduino IDE
    2. Processing

-----------------------------------------------------------------------------------------------

C. 將 Arduino 程式碼寫入:

     1. 下載 Adafruit_BNO055 driverAdafruit_Sensor
 
     2. 解壓縮後, 將其資料夾更名為: Adafruit_BNO055Adafruit_Sensor

     3. 複製到 /Users/Lanli/Documents/Arduino/libraries 下:

     4. 打開  Arduino IDE , 參考剛剛 libraries 資料夾下的
         /Adafruit_BNO055/examples/rawdata/rawdata.ino, 撰寫以下的程式碼:
 
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>

/* This driver reads raw data from the BNO055

   Connections
   ===========
   Connect SCL to analog 5
   Connect SDA to analog 4
   Connect VDD to 3.3V DC
   Connect GROUND to common ground

   History
   =======
   2015/MAR/03  - First release (KTOWN)
*/

/* Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (100)

Adafruit_BNO055 bno = Adafruit_BNO055();

/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
*/
/**************************************************************************/

void setup(void)
{
  Serial.begin(9600);
  Serial.println("Orientation Sensor Raw Data Test"); Serial.println("");

  /* Initialise the sensor */
  if(!bno.begin())
  {
    /* There was a problem detecting the BNO055 ... check your connections */
    Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
    while(1);
  }

  delay(1000);

  /* Display the current temperature */
  /*
  int8_t temp = bno.getTemp();
  Serial.print("Current Temperature: ");
  Serial.print(temp);
  Serial.println(" C");
  Serial.println("");
  */

  bno.setExtCrystalUse(true);

  Serial.println("Calibration status values: 0=uncalibrated, 3=fully calibrated");
}

/**************************************************************************/
/*
    Arduino loop function, called once 'setup' is complete (your own code
    should go here)
*/
/**************************************************************************/

void loop(void)
{
  // Possible vector values can be:
  // - VECTOR_ACCELEROMETER - m/s^2
  // - VECTOR_MAGNETOMETER  - uT
  // - VECTOR_GYROSCOPE     - rad/s
  // - VECTOR_EULER         - degrees
  // - VECTOR_LINEARACCEL   - m/s^2
  // - VECTOR_GRAVITY       - m/s^2

 
  // EULER
  imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);

  /* Display the floating point data */
  /*
  Serial.print("X: ");
  Serial.print(euler.x());
  Serial.print(" Y: ");
  Serial.print(euler.y());
  Serial.print(" Z: ");
  Serial.print(euler.z());
  Serial.print("\t\t");
  */

  Serial.print("euler: ");
  Serial.print(euler.x());
  Serial.print(" ");
  Serial.print(euler.y());
  Serial.print(" ");
  Serial.print(euler.z());
  Serial.print(" "); 
 
  // GYROSCOPE
  imu::Vector<3> gyroscope = bno.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);

  Serial.print("gyro: ");
  Serial.print(gyroscope.x());
  Serial.print(" ");
  Serial.print(gyroscope.y());
  Serial.print(" ");
  Serial.print(gyroscope.z());
  Serial.print(" ");
 
  // ACCELEROMETER
  imu::Vector<3> accelerometer = bno.getVector(Adafruit_BNO055::VECTOR_ACCELEROMETER);

  Serial.print("acc: ");
  Serial.print(accelerometer.x());
  Serial.print(" ");
  Serial.print(accelerometer.y());
  Serial.print(" ");
  Serial.print(accelerometer.z());
  Serial.print(" "); 
 
  /*
  // Quaternion data
  imu::Quaternion quat = bno.getQuat();
  Serial.print("qW: ");
  Serial.print(quat.w(), 4);
  Serial.print(" qX: ");
  Serial.print(quat.y(), 4);
  Serial.print(" qY: ");
  Serial.print(quat.x(), 4);
  Serial.print(" qZ: ");
  Serial.print(quat.z(), 4);
  Serial.print("\t\t");
  */


  /* Display calibration status for each sensor. */
  uint8_t system, gyro, accel, mag = 0;
  bno.getCalibration(&system, &gyro, &accel, &mag);
  //Serial.print("CALIBRATION: Sys=");
  Serial.print("CAL: Sys=");
  Serial.print(system, DEC);
  Serial.print(" Gyro=");
  Serial.print(gyro, DEC);
  Serial.print(" Accel=");
  Serial.print(accel, DEC);
  Serial.print(" Mag=");
  Serial.println(mag, DEC);

  delay(BNO055_SAMPLERATE_DELAY_MS);
}

     4. 選取板子:
         Arduino > 工具 > 板子 > Arduino Nano 

     5. 選取序列埠:
         Arduino > 工具 > 序列埠 > /dev/cu.usbserial-AJ02WWCS 


     6. 上傳:
         Arduino > 檔案 > 上傳  

     7. 完成:

-----------------------------------------------------------------------------------------------

D. Processing:
    1. 相關程式碼如下:

void setup() {
....
  // initial Serial
  println(Serial.list());

  Serial port;
  // baudRate: 從一裝置發到另一裝置的位元率,即每秒鐘多少位元(bit/s)。
  int arduinoBaudRate = 9600;     
  int arduinoPortIndex;
  int lineFeed= 10;         // ASCII: line feed (new line)
  String arduinoSerialName = "
usbserial";
  String arduinoPort;

  // automatic set arduino port index 

 
for (int i = 0; i < Serial.list ().length; i++) {
    if (Serial.list()[i].indexOf(
arduinoSerialName) > 0) { // if find string "usbserial"
      arduinoPortIndex = i;
      println(">>> arduino Port Index = " + arduinoPortIndex)      
      break;
    }
  }

    arduinoPort = Serial.list()[arduinoPortIndex];
    port = new Serial(this, arduinoPort, arduinoBaudRate);
    port.bufferUntil(lineFeed);

....
}

void serialEvent(Serial p) { 
  String rawStr = p.readString();
  println(">>> BNO055 = " +  rawStr);
}


    2. 執行結果:

2015年10月20日 星期二

CUDA: Try To Measuring The Kernel By Timer

since: 2015/10/20
update: 2015/10/20

reference:
1. Professional CUDA C Programming
2. I touchs: Get Started On NVIDIA Jetson TK1
3. I touchs: How to re-flash your Jetson TK1 Development Kit 
4. I touchs: Using the Jetson TK1 as a remote development environment for CUDA


A. Timing With CPU Timer

     1. 在 Nsight Eclipse Edition 撰寫程式如下:
         // 檔名: sumArraysOnGPU-timer.cu
#include <cuda_runtime.h>
#include <stdio.h>
#include <sys/time.h>


// check error

void CHECK(cudaError_t call)
{
    const cudaError_t error = call;
    if (error != cudaSuccess)
    {
        fprintf(stderr, "Error: %s:%d, ", __FILE__, __LINE__);
        fprintf(stderr, "code: %d, reason: %s\n", error,
                cudaGetErrorString(error));
    }
}

 
// the timer on cpu
double seconds()
{
    struct timeval tp;
    struct timezone tzp;
    int i = gettimeofday(&tp, &tzp);
    return ((double)tp.tv_sec + (double)tp.tv_usec * 1.e-6);
}


// verifying your kernel
void checkResult(float *hostRef, float *gpuRef, const int N)
{
    double epsilon = 1.0E-8;
    bool match = 1;

    for (int i = 0; i < N; i++)
    {
        if (abs(hostRef[i] - gpuRef[i]) > epsilon)
        {
            match = 0;
            printf("Arrays do not match!\n");
            printf("host %5.2f gpu %5.2f at current %d\n", hostRef[i],
                   gpuRef[i], i);
            break;
        }
    }

    if (match) printf("Arrays match.\n\n");

    return;
}

 

// initial random data
void initialData(float *ip, int size)
{
    // generate different seed for random number
    time_t t;
    srand((unsigned) time(&t));

    for (int i = 0; i < size; i++)
    {
        ip[i] = (float)( rand() & 0xFF ) / 10.0f;
    }

    return;
}



// sum Arrays On Host

void sumArraysOnHost(float *A, float *B, float *C, const int N)
{
    for (int idx = 0; idx < N; idx++)
    {
        C[idx] = A[idx] + B[idx];
    }
}


// sum Arrays On GPU
__global__ void sumArraysOnGPU(float *A, float *B, float *C, const int N)
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;

    if (i < N) C[i] = A[i] + B[i];
}


// the main function

int main(int argc, char **argv)
{
    printf("\n%s Starting...\n", argv[0]);

    // set up device
    int dev = 0;
    cudaDeviceProp deviceProp;
    CHECK(cudaGetDeviceProperties(&deviceProp, dev));
    printf("Using Device %d: %s\n", dev, deviceProp.name);
    CHECK(cudaSetDevice(dev));

    // set up data size of vectors
    int nElem = 1 << 24;
    printf("Vector size %d\n", nElem);

    // malloc host memory
    size_t nBytes = nElem * sizeof(float);

    float *h_A, *h_B, *hostRef, *gpuRef;
    h_A     = (float *)malloc(nBytes);
    h_B     = (float *)malloc(nBytes);
    hostRef = (float *)malloc(nBytes);
    gpuRef  = (float *)malloc(nBytes);

    double iStart, iElaps;

    // initialize data at host side
    iStart = seconds();
    initialData(h_A, nElem);
    initialData(h_B, nElem);
    iElaps = seconds() - iStart;
    printf("initialData Time elapsed %f sec\n", iElaps);
    memset(hostRef, 0, nBytes);
    memset(gpuRef,  0, nBytes);

    // add vector at host side for result checks
    iStart = seconds();
    sumArraysOnHost(h_A, h_B, hostRef, nElem);
    iElaps = seconds() - iStart;
    printf("sumArraysOnHost Time elapsed %f sec\n", iElaps);

    // malloc device global memory
    float *d_A, *d_B, *d_C;
    CHECK(cudaMalloc((float**)&d_A, nBytes));
    CHECK(cudaMalloc((float**)&d_B, nBytes));
    CHECK(cudaMalloc((float**)&d_C, nBytes));

    // transfer data from host to device
    CHECK(cudaMemcpy(d_A, h_A, nBytes, cudaMemcpyHostToDevice));
    CHECK(cudaMemcpy(d_B, h_B, nBytes, cudaMemcpyHostToDevice));
    CHECK(cudaMemcpy(d_C, gpuRef, nBytes, cudaMemcpyHostToDevice));

    // invoke kernel at host side
    int iLen = 256;
    dim3 block (iLen);
    dim3 grid  ((nElem + block.x - 1) / block.x);


    iStart = seconds();
    sumArraysOnGPU<<<grid, block>>>(d_A, d_B, d_C, nElem);
    CHECK(cudaDeviceSynchronize()); // used just for debugging purpose
    iElaps = seconds() - iStart;
    printf("sumArraysOnGPU <<<  %d, %d  >>>  Time elapsed %f sec\n", grid.x,
           block.x, iElaps);


    // the testing result ....
    //

    // sumArraysOnGPU <<<  16384, 1024  >>>  Time elapsed 0.040817 sec
    // sumArraysOnGPU <<<  32768, 512  >>>  Time elapsed 0.031031 sec
    // sumArraysOnGPU <<<  65536, 256  >>>  Time elapsed 0.029070 sec
    // sumArraysOnGPU <<<  131072, 128  >>>  Time elapsed 0.028804 sec

    // sumArraysOnGPU <<<  262144, 64  >>>  Time elapsed 0.056073 sec
    // sumArraysOnGPU <<<  524288, 32  >>>  Time elapsed 0.098515 sec
    // sumArraysOnGPU <<<  1048576, 16  >>>  Time elapsed 0.190098 sec
    // sumArraysOnGPU <<<  2097152, 8  >>>  Time elapsed 0.375030 sec
    // sumArraysOnGPU <<<  4194304, 4  >>>  Time elapsed 0.803681 sec
    // sumArraysOnGPU <<<  8388608, 2  >>>  Time elapsed 1.835205 sec
    // sumArraysOnGPU <<<  16777216, 1  >>>  Time elapsed 3.515245 sec


    // check kernel error
    CHECK(cudaGetLastError()) ;

    // copy kernel result back to host side
    CHECK(cudaMemcpy(gpuRef, d_C, nBytes, cudaMemcpyDeviceToHost));

    // check device results
    checkResult(hostRef, gpuRef, nElem);

    // free device global memory
    CHECK(cudaFree(d_A));
    CHECK(cudaFree(d_B));
    CHECK(cudaFree(d_C));

    // free host memory
    free(h_A);
    free(h_B);
    free(hostRef);
    free(gpuRef);

    return(0);
}


     2. 執行結果:

-----------------------------------------------------------------------------------------------

B. Timing With nvprof(NVIDIA profiling tool)
     1. Before this, Don't forget to Add CUDA bin Environment Variables
         => How to re-flash your Jetson TK1 Development Kit
         => G. Add CUDA bin Environment Variables


     2. Login to TK1:
         $ ssh ubuntu@192.168.0.106

     3. Go to the release directory:
        $ cd /home/ubuntu/RD/projects/cuda/Release

     4. Timing with nvprof:
         $ nvprof ./NSightCUDA

     5. Result:
./NSightCUDA Starting...
==2996== NVPROF is profiling process 2996, command: ./NSightCUDA
Using Device 0: GK20A
Vector size 16777216
initialData Time elapsed 4.632509 sec
sumArraysOnHost Time elapsed 0.060414 sec
sumArraysOnGPU <<<  65536, 256  >>>  Time elapsed 0.023884 sec
Arrays match.

==2996== Profiling application: ./NSightCUDA
==2996== Profiling result:
Time(%)      Time     Calls       Avg       Min       Max  Name
 57.86%  137.14ms         3  45.714ms  44.908ms  46.267ms  [CUDA memcpy HtoD]
 32.42%  76.837ms         1  76.837ms  76.837ms  76.837ms  [CUDA memcpy DtoH]
  9.73%  23.053ms         1  23.053ms  23.053ms  23.053ms  sumArraysOnGPU(float*, float*, float*, int)

==2996== API calls:
Time(%)      Time     Calls       Avg       Min       Max  Name
 54.19%  219.10ms         4  54.774ms  45.602ms  79.567ms  cudaMemcpy
 39.03%  157.79ms         3  52.598ms  1.0795ms  152.74ms  cudaMalloc
  5.87%  23.717ms         1  23.717ms  23.717ms  23.717ms  cudaDeviceSynchronize
  0.64%  2.5713ms         3  857.08us  661.42us  1.0873ms  cudaFree
  0.14%  582.58us        83  7.0190us  1.4160us  302.67us  cuDeviceGetAttribute
  0.08%  331.83us         1  331.83us  331.83us  331.83us  cudaGetDeviceProperties
  0.03%  119.25us         1  119.25us  119.25us  119.25us  cudaLaunch
  0.01%  45.583us         1  45.583us  45.583us  45.583us  cudaSetDevice
  0.00%  17.416us         2  8.7080us  4.5000us  12.916us  cuDeviceGetCount
  0.00%  17.333us         1  17.333us  17.333us  17.333us  cudaGetLastError
  0.00%  10.667us         1  10.667us  10.667us  10.667us  cuDeviceTotalMem
  0.00%  9.0000us         1  9.0000us  9.0000us  9.0000us  cudaConfigureCall
  0.00%  6.2500us         1  6.2500us  6.2500us  6.2500us  cuDeviceGetName
  0.00%  4.8340us         4  1.2080us     667ns  1.8340us  cudaSetupArgument
  0.00%  4.1670us         2  2.0830us  1.8330us  2.3340us  cuDeviceGet


  備註: The nvprof result is more accurate than the host-side timing result

openFrameworks: Serial Read String From Arduino Simulated Sensor

since: 2015/10/20
update: 2015/10/22
reference:
1. Serial read string from Arduino - 【oF】openFrameworks

A. Arduino 程式: 
// arduino_sensor.ino
long randNumber;
float randFloat;

String xAxis = "X: ";
String yAxis = "Y: ";
String zAxis = "Z: ";

String xValue = "";
String yValue = "";
String zValue = "";

void setup(){
  Serial.begin(9600);

  // if analog input pin 0 is unconnected, random analog
  // noise will cause the call to randomSeed() to generate
  // different seed numbers each time the sketch runs.
  // randomSeed() will then shuffle the random function.

  randomSeed(analogRead(0));
}

void loop() {

  // ex: X: 359.81252 Y: 11.81252 Z: 56.00005
  randNumber = random(0, 36000000);
  randFloat = randNumber / 100000.0; //
produce float random value: 0 ~ 360
  xValue = String(randFloat, 5);
 
  randNumber = random(-3600000, 3600000);
  randFloat = randNumber / 100000.0; //
produce float random value: -36 ~ 36
  yValue = String(randFloat, 5); 
 
  randNumber = random(0, 18000000);
  randFloat = randNumber / 100000.0;  //
produce float random value: 0 ~ 180
  zValue = String(randFloat, 5); 

  Serial.println(xAxis + xValue + " " + yAxis + yValue + " " + zAxis + zValue);
  delay(50);
}


-----------------------------------------------------------------------------------------------

B. openFrameworks 程式:
    1. main.cpp
#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){
    ofSetupOpenGL(1024,768,OF_WINDOW);            // <-------- setup the GL context

    // this kicks off the running of my app
    // can be OF_WINDOW or OF_FULLSCREEN
    // pass in width and height too:

    ofRunApp(new ofApp());
}

-----------------------------------------------------------------------------------------------

    2. ofApp.h
#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:
        void setup();
        void update();
        void draw();

        void keyPressed(int key);
        void keyReleased(int key);
        void mouseMoved(int x, int y );
        void mouseDragged(int x, int y, int button);
        void mousePressed(int x, int y, int button);
        void mouseReleased(int x, int y, int button);
        void windowResized(int w, int h);
        void dragEvent(ofDragInfo dragInfo);
        void gotMessage(ofMessage msg);
   
        //@add 2015/10/20 ########################################
        string ofxGetSerialString(ofSerial &serial, char until);
        string ofxTrimStringRight(string str);
        string ofxTrimStringLeft(string str);
        string ofxTrimString(string str);
   
        ofTrueTypeFont  font;
        float           readTime;           // when did we last read?
        ofSerial        serial;
        string          serialString;
};


-----------------------------------------------------------------------------------------------

    3. ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------

//@add 2015/10/20 ########################################
string ofApp::ofxGetSerialString(ofSerial &serial, char until) {
    static string str;
    stringstream ss;
    char ch;
    int ttl=1000;
    while ((ch=serial.readByte())>0 && ttl-->0 && ch!=until) {
        ss << ch;
    }
    str+=ss.str();
    if (ch==until) {
        string tmp=str;
        str="";
        return ofxTrimString(tmp);
    } else {
        return "";
    }
}


//@add 2015/10/20 ########################################
// trim right trailing spaces

string ofApp::ofxTrimStringRight(string str) {
    size_t endpos = str.find_last_not_of(" \t\r\n");
    return (string::npos != endpos) ? str.substr( 0, endpos+1) : str;
}


//@add 2015/10/20 ########################################
// trim left trailing spaces

string ofApp::ofxTrimStringLeft(string str) {
    size_t startpos = str.find_first_not_of(" \t\r\n");
    return (string::npos != startpos) ? str.substr(startpos) : str;
}


//@add 2015/10/20 ########################################
// trim trailing spaces

string ofApp::ofxTrimString(string str) {
    return ofxTrimStringLeft(ofxTrimStringRight(str));;
}


void ofApp::setup(){
    //@add 2015/10/20 ########################################
    ofSetVerticalSync(true);
   
    ofBackground(255);
    // http://openframeworks.cc/documentation/utils/ofLog.html
    ofSetLogLevel(OF_LOG_VERBOSE);
   
    ofSetColor(0);
    font.loadFont("DIN.otf", 32);
   
    serial.listDevices();
    /*
     [notice ] ofSerial: [0] = tty.usbmodem1441
     [notice ] ofSerial: [1] = cu.usbmodem1441
     [notice ] ofSerial: [2] = tty.Bluetooth-Incoming-Port
     [notice ] ofSerial: [3] = cu.Bluetooth-Incoming-Port
     */
   
    /*
    vector<ofSerialDeviceInfo> deviceList = serial.getDeviceList();
    vector<ofSerialDeviceInfo>::iterator it = deviceList.begin();
   
    while( it != deviceList.end() ){
        ofLogVerbose() << (*it).getDeviceID() << ": " << (*it).getDeviceName();
        ++it;
    }
    */

   
    int baud = 9600;
    // Tells the computer which port to be listening to
    serial.setup(0, baud); //open the first device
   
    readTime = 0;
    serialString = "";
}

//--------------------------------------------------------------
void ofApp::update(){
    //@add 2015/10/20 ########################################
    serialString = "";
    serialString = ofxGetSerialString(serial,'\n'); //read until end of line
    if (serialString.length() > 0) {
        readTime = ofGetElapsedTimef();
        ofLogVerbose() << "serialString = " << serialString << "\n";
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
    string msg;
    msg += "read: " + serialString + "\n";
    msg += "(at time " + ofToString(readTime, 3) + ")";
    font.drawString(msg, 50, 100);
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}

//--------------------------------------------------------------

void ofApp::mousePressed(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}


       備註:
       記得將 .... /openFrameworks/of_v0.8.4_osx_release/examples/ communication/
       serialExample/bin/data
內的 DIN.otf copy 到相對的位置內.


-----------------------------------------------------------------------------------------------

C. 執行結果:

2015年10月16日 星期五

Raspberry Pi: Using a standard USB webcam

since: 2015/10/16
update: 2015/10/16

reference:
1. Using a standard USB webcam
2. Raspberry Pi 安裝 Webcam 和 Motion Webcam Server
3. Raspberry Pi 筆記(十九): Webcam 拍照與瀏覽串流媒體

A. 單張照片拍照功能:
     1. $ lsusb
...
Bus 001 Device 004: ID 1871:0341 Aveo Technology Corp.
...

     2. $ ls /dev/video0
/dev/video0

     3. 安裝 fswebcam
         $ sudo apt-get update
         $ sudo apt-get upgrade
         $ sudo apt-get install fswebcam

     4. 抓圖測試:
         $ fswebcam -d /dev/video0 test.jpg
         (or $ fswebcam image.jpg)

--------------------------------------------------------------------------------------------

B. 移動偵測拍照功能:

     1. 安裝 motion
         $ sudo apt-get install motion
         $ mkdir /tmp/motion
         $ sudo chmod -R 777 /tmp/motion
         $ sudo chmod -R 777 /etc/motion/motion.conf

     2. $ sudo nano /etc/default/motion
# set to 'yes' to enable the motion daemon
#start_motion_daemon=no

start_motion_daemon=yes

     3. $ sudo nano /etc/motion/motion.conf
....

# Start in daemon (background) mode and release terminal (default: off)
#daemon off

daemon on

# Image width (pixels). Valid range: Camera dependent, default: 352
# width 320

width 640

# Image height (pixels). Valid range: Camera dependent, default: 288
# height 240

height 480

# Maximum number of frames to be captured per second.
# Valid range: 2-100. Default: 100 (almost no limit).
#framerate 2

framerate 60

# The mini-http server listens to this port for requests (default: 0 = disabled)
webcam_port 8081

# Quality of the jpeg (in percent) images produced (default: 50)
# webcam_quality 50

webcam_quality 100

# Restrict webcam connections to localhost only (default: on)
webcam_localhost on

# TCP/IP port for the http server to listen on (default: 0 = disabled)
control_port 8080

# Restrict control connections to localhost only (default: on)
control_localhost on

....

     4. $ sudo service motion restart

     5. 在 pi 上, 測試:
         a. $ startx
         b. 開啟瀏覽器輸入: http://127.0.0.1:8081/

--------------------------------------------------------------------------------------------

C. 簡易 Pi 視窗桌面相機:
     1. $ sudo apt-get install camorama

     2. $ startx

     3. 測試: Graphics > Camorama Webcam Viewer

    備註:
    1. 亦可在進入視窗模式後, 利用終端機啟動 ($ camorama --help)

    2. 調整存擋位置:
         Edit > Preferences > Local Capture > Browse... > OK

2015年10月1日 星期四

製作 OS X El Capitan USB 安裝開機碟

since: 2015/10/01
update: 2015/10/01

reference:
1. How to Create a OS X El Capitan Boot Installer USB Flash Drive

A. 準備動作:     

     1. 16 GB 的 USB 隨身碟.(至少需 8 GB)

     2. 從 Mac App Store 下載 OS X El Capitan, 下載完成後, 離開安裝步驟, 先不要安裝.

         備註: 並確認下載的檔案是在 /Applications 下
                  $ cd /Applications
                  $ ls | grep "Install"
                     Install OS X El Capitan.app

--------------------------------------------------------------------------------------------

B. 製作可開機的 USB 碟:
    1. 將 USB 隨身碟連結 Mac, 並開啟 "磁碟工具程式",
        從左邊的磁碟清單點選 USB 隨身碟.

    2. 點選 "清除" 頁籤, 格式選為: Mac OS 擴充格式(日誌式), 按下 "清除" 並確認.

    3. 點選 "分割" 頁籤, 將分割區佈局從旁邊的下拉式選單選取 "1個分割區",
        並將分割區資訊裡的名稱, 改成: Untitled .
 
  4. 點選 "選項...", 點選 "GIUD 磁碟分割區表格" > 套用 > 分割 > 確認

    5. 磁碟工具程式 > 結束磁碟工具程式

--------------------------------------------------------------------------------------------

C. 更改要安裝 OS X El Capitan 的 USB 隨身碟名稱, 以方便識別:
     ---> 將其名稱改成 "ElCapInstaller"


--------------------------------------------------------------------------------------------

D. 製作 OS X El Capitan 安裝碟:
     1. 開啟 "終端機", 鍵入以下的指令:
    $sudo /Applications/Install\ OS\ X\ El\ Capitan.app/Contents/Resources/createinstallmedia --volume /Volumes/ElCapInstaller --applicationpath /Applications/Install\ OS\ X\ El\ Capitan.app --nointeraction

     2. 鍵入 admin 密碼, 等待完成的訊息(約 20 分鐘), 離開終端機.

     3. 完成後, 可以在 Mac Finder 看到剛出爐的 OS X El Capitan 安裝碟.

--------------------------------------------------------------------------------------------

E. 進行安裝:
     重新開機, 按下 "option" 鍵, 就可以選擇 "Install OS X El Capitan" 了.

openFrameworks: Control The Raspberry Pi Camera Module

since: 2015/10/01
update: 2016/04/25
reference:
1. jvcleave/ofxRPiCameraVideoGrabber
2. 在 Raspberry Pi 中擷取螢幕畫面(Snapshot)的工具 - G. T. Wang

A. 說明
     在此處會利用 Mac 的 Xcode 當成程式的編輯工具, 而編譯執行皆需在 Pi 上進行. 

-----------------------------------------------------------------------------------------------

B. 啟用 Pi 的相機模組功能
    1. $ sudo raspi-config

    2. 選擇 5. Enable Camera

    3. > Enable

    4. > Yes

C. 安裝附加在 openFrameworks 上的相機模組程式
     分別在 Mac 與 Pi 上的 openFrameworksaddons 目錄下安裝:

     // Pi
     $ cd /home/pi/of_v0.8.4_linuxarmv7l_release/addons
     $ git clone https://github.com/jvcleave/ofxRPiCameraVideoGrabber

     // Mac
     $ cd /Lanli/RD/project/openFrameworks/of_v0.8.4_osx_release/addons
     $ git clone https://github.com/jvcleave/ofxRPiCameraVideoGrabber  

-----------------------------------------------------------------------------------------------

D. 在 Xcode 上新增 openFrameworks 的 app 專案
      1. 於所安裝 openFrameworks 版本下的 projectGenerator_osx 目錄內,
          點二下: projectGenerator.app

      2. 設定新專案的資訊:
          Name: RPiCamera
          Addons: ofxRPiCameraVideoGrabber
          > 按下: "GENERATE PROJECT"

      3. 完成後, 可於所安裝 openFrameworks 版本下的 apps > myApps 目錄下看到:
          RPiCamera 專案資料夾, 其資料夾下的 addons.make 檔案內容即是附加的
          程式名稱.

-----------------------------------------------------------------------------------------------

E. 用 Xcode 開啟 RPiCamera 專案目錄下的 RPiCamera.xcodeproj     
      1. 參考剛剛下載 addons 的 ofxRPiCameraVideoGrabber 目錄下的 example 程式碼

      2. 修改 main.cpp, ofApp.hofApp.cpp 程式碼如下:
          // main.cpp
#include "ofMain.h"
#include "ofApp.h"
#include "ofGLProgrammableRenderer.h"

int main()
{
    ofSetLogLevel(OF_LOG_VERBOSE);
    ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE);
   
    //ofSetupOpenGL(1280, 720, OF_WINDOW);
    //@update 2015/10/01

    ofSetupOpenGL(1280, 800, OF_FULLSCREEN);
    ofRunApp( new ofApp());
}


*************************************************************************


          // ofApp.h
#pragma once

#include "ofMain.h"
#include "ofAppEGLWindow.h"
#include "TerminalListener.h"
#include "ImageFilterCollection.h"
#include "ofxRPiCameraVideoGrabber.h"

class ofApp : public ofBaseApp, public KeyListener{
   
public:
   
    void setup();
    void update();
    void draw();
    void keyPressed(int key);
   
    void onCharacterReceived(KeyListenerEventData& e);
    TerminalListener consoleListener;
    ofxRPiCameraVideoGrabber videoGrabber;
   
    ImageFilterCollection filterCollection;
   
    bool doDrawInfo;
};


*************************************************************************


          // ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup()
{
    ofSetLogLevel(OF_LOG_VERBOSE);
    ofSetLogLevel("ofThread", OF_LOG_ERROR);
    //ofSetVerticalSync(false);
   
    doDrawInfo    = true;
   
    consoleListener.setup(this);
   
    OMXCameraSettings omxCameraSettings;
    //omxCameraSettings.width                = 1280;
    //omxCameraSettings.height                = 720;

    omxCameraSettings.width                    = 1280;
    omxCameraSettings.height                = 800;
    omxCameraSettings.isUsingTexture        = false;
   
    omxCameraSettings.doRecording            = false;        //default: false
    if (omxCameraSettings.doRecording)
    {
        omxCameraSettings.doRecordingPreview    = true;
        omxCameraSettings.recordingFilePath        = "";        //will self generate if left blank
        omxCameraSettings.doConvertToMKV        = false;    //converts file to .mkv using mkvmerge(if present)
    }
   
    videoGrabber.setup(omxCameraSettings);
    filterCollection.setup();
}

//--------------------------------------------------------------
void ofApp::update()
{
}

//--------------------------------------------------------------
void ofApp::draw(){
    //Nothing really to do here as the output is rendered directly to full screen
}

//--------------------------------------------------------------
void ofApp::keyPressed  (int key)
{
    ofLog(OF_LOG_VERBOSE, "%c keyPressed", key);
   
    if (key == 'e')
    {
        videoGrabber.applyImageFilter(filterCollection.getNextFilter());
    }
   
    if (key == 'g')
    {
        doDrawInfo = !doDrawInfo;
    }
    if (key == 'q')
    {
        ofLogVerbose(__func__) << "SENDING QUIT";
        videoGrabber.stopRecording();
    }
    if (key == 't')
    {
        videoGrabber.toggleLED();
    }
}

void ofApp::onCharacterReceived(KeyListenerEventData& e)
{
    keyPressed((int)e.character);
}


備註: 在 Xcode 上, 只需用到: Product > Clean , 將在 Mac 上不支援 Pi 的語法清除.

-----------------------------------------------------------------------------------------------

F. 編譯與執行
     1. 將 Xcode 建立的整個 RPiCamera 專案資料夾, 拷貝並上傳到 Pi 相對的位置下:
         /home/pi/of_v0.8.4_linuxarmv7l_release/apps/myApps/

     2. 在 Pi 上建立 app 捷徑(symbolic link)
         $ cd
         $ ln -s /home/pi/of_v0.8.4_linuxarmv7l_release/apps/myApps/RPiCamera ./RPiCamera

     3. 編譯
         $ cd
         $ cd RPiCamera
         $ make

     4. 在 Pi 上執行
         $ cd ~/RPiCamera
         $ make run

-----------------------------------------------------------------------------------------------

G. 結果

-----------------------------------------------------------------------------------------------

H. 加入拍照功能:
     1. 安裝 raspi2png
         a. 先安裝 png 函式庫
             $ sudo apt-get install libpng12-dev

         b. 下載 raspi2png
             $ cd ~
             $ git clone https://github.com/AndrewFromMelbourne/raspi2png.git

         c. 編譯 raspi2png
             $ cd ~/raspi2png
             $ make

     2. 擷取畫面測試
         $ cd ~/raspi2png
         $ ./raspi2png        (預設檔名: snapshot.png)

         備註: ./raspi2png --help
     3. 於程式加上 print screen 功能:
         開啟 ofApp.cpp 檔案, 修改如下:
....
void ofApp::keyPressed  (int key)
{
....
    if (key == 't')
    {
        videoGrabber.toggleLED();
    }

    //@add 2015/10/21: print screen ######################################
    if (key == 'p')
    {
        string mySweetCommand = "/home/pi/raspi2png/raspi2png --pngname ";
       
        // yyyymmddhhmmss
        mySweetCommand += ofToString(ofGetYear()) + ofToString(ofGetMonth())+ ofToString(ofGetDay())+ ofToString(ofGetHours())+ ofToString(ofGetMinutes()) + ofToString(ofGetSeconds());

        mySweetCommand += ".png";
       
        system(mySweetCommand.c_str());
    }
}

....


     4. 於 Pi 上編譯, 並執行. 按下 "p" 即會在 ~/RPiCamera/bin 下產生擷取的影像畫面

-----------------------------------------------------------------------------------------------

I. 備註:     
   reference:
   a. Capturing HD Video With The Pi Camera Module 24
   b. Streaming Video Using VLC Player

   c. Raspberry Pi Camera 簡介

   1. 單純拍攝短片或照片
   
         a. raspicam commands
             1. 錄製 10 秒鐘影片:
                 $ raspivid --codec MJPEG -o video.mpg -t 10000
                 在 pi 上播放:
                 $ omxplayer ./video.mpg

         b. Python picamera
             1. install python-picamera
                 $ sudo apt-get install python-picamera
                 $ sudo apt-get install python3-picamera
                 $ sudo apt-get install python-picamera-docs

             2. camera_test.py
#!/usr/bin/python3

import picamera

camera = picamera.PiCamera()

# auto white balance
# off,auto,sun,cloud,shade,tungsten,fluorescent,incandescent,flash,horizon
#camera.awb_mode = 'auto'


camera.start_preview()


#for i in range(100):
#    camera.brightness = i
#    sleep(0.2)


#camera.capture('image.jpg')

camera.start_recording('video.h264')
camera.wait_recording(3)
camera.stop_recording()

camera.stop_preview()


             3. 播放
                 (1). 下載
video.h264 在 Mac 上, 利用 VLC 播放
                 (2). 先將 h264 轉乘 mp4 再播放
                       $ sudo apt-get install gpac
                       $ MP4Box -add video.h264 video.mp4

                       $ omxplayer ./video.mp4                          (亦可下載到 Mac 上播放)     -----------------------------------------------------------------------------------------------
   2. 開機自動執行
RPiCamera 程式
       a. 開機後自動登入
           $ sudo nano /etc/inittab

           ....
           #1:2345:respawn:/sbin/getty --noclear 38400 tty1
           1:2345:respawn:/bin/login -f pi tty1 </dev/tty1 >/dev/tty1 2>&1

       b. 登入後自動執行 RPiCamera 程式
           $ sudo nano ~/.bashrc
....
# auto run RPiCamera after start up 10 second, but not SSH sign in
sleep 10
echo "tty = $(tty)"

if [ $(tty) == "/dev/tty1" ]; then

  echo "We have a match."
  cd ~/RPiCamera
  ./bin/RPiCamera

else
  echo "We dont match."
fi


-----------------------------------------------------------------------------------------------
   3. 排程: 每天下午5點整關機
       $ sudo crontab -e
          # shutdown at 17:00 everyday
          00 17 * * * /sbin/shutdown -h now

-----------------------------------------------------------------------------------------------

   4. 當要使用一般的 USB Webcam 時, 記得要再執行: $sudo raspi-config ,  
       將 Pi 的相機模組功能停用.