2011/11/24

zlibでメモリ上のデータを圧縮(IplImage)

ネットワーク通信の部分もそこそこできたので、
次はArduinoタンクで撮影した画像を転送する部分に取り掛かりたいと思います。

Arduinoタンク側のBeagleBoard-xmで撮影した画像(IplImage)を、そのまま転送するとかなりのデータ量になりそうです。そこで、zlibを使って圧縮してから転送しようと考え、zlibの使いかたを調べてみました。

参考にしたサイト: zlib入門

今回作ったコードは別館の方においてあります(compress.zip)。

さて、早速VGAサイズの画像データをzlibを使って圧縮してみます。

//------------------IplImageをzlibで圧縮するサンプルプログラム
/mnt/ramdisk/compress$ output_compress cat011.jpg 
width: 480  height:640
widthStep:1440  channel:3
buffer size is 921600 bytes
compbuf:1013760 bytes allocated.
res:0, size:755.9023 kByte.
成功
圧縮にかかった時間: 36.81 ms 圧縮比:0.84
解凍 成功
res:0, decomp size:921600


。。。ん?
あまり小さくなってない。。
複雑な画像だと、可逆圧縮の場合は圧縮比がそんなに良くならないようです。

また、処理時間がデスクトップ(Phenom 2.6GHz)で40msかかるので、BeagleBoardだともっとかかると思います。回線がある程度速い場合は、圧縮しないほうが良いかもしれません。


ではまた。

2011/11/20

telnet経由でArduinoにコマンド送信

前回、前々回とLinuxのソケット通信とシリアル通信のプログラムをコピペして動作確認してみましたが、コピペだけだと応用が効かないのでLinuxのプログラミングについて書籍で勉強することにしました。

我が家の本棚はもう満タンなのでKindleに放り込める書籍を探したところ、
The Linux Programming Interface
という本を見つけました。
2010年の10月に出版された本で、レビューもほとんど星5つだったので買ってみました。
紙の本だと7300円しますが、Kindleだと57ドル(4500円ぐらい?)で買えたのでお得でした。

わからない単語はかなり飛ばして読みましたが、
forkやシグナル、プロセス管理などについて学ぶことができました。
学んだことを生かし、telnet経由でArduinoにコマンドを送信するものを作りました。

概要図
サーバー側PCでこのアプリケーションを起動すると、クライアントからの接続を待ち受けます。
クライアントからTelnetで接続し文字を送ると、そのままArduinoにシリアル通信で文字を転送します。
現時点ではArduinoからの応答はサーバー側にしか返されませんが、もう少しいじればクライアント側に応答を返すことができそうです。
Arduino用に作ってはありますが、シリアルポートに接続するものであれば、ArduinoでなくてもなんでもOKです。

クライアント側もtelnetが使える端末ならば何でも良いので、XoomやIS03などからも操作ができそうです。

ソースコードは別館の方においてあります。

ではまた。

2011/11/14

BeagleBoardのベアボーン・BeagleBone

BeagleBoardのサイトに行ってみたら、何やら新しい製品の案内があるではありませんか。

手のひらサイズのBeagleBoard,BeagleBoneです。
Arduinoみたいな感じですが、CPUはA8を積んでおり、Arduinoよりかなり速いです。



BeagleBoneのリファレンスマニュアルからざっくり抜粋してみました。
CPU:AM3359プロセッサ(550MHz〜720MHz)
メモリ:DDR2 256MB
電源:USBまたは5V DCジャック
LED:電源用1個 、ユーザがいじれるLED4個
USB:USB2.0Host 1ポート(5V500mA供給可能)
        miniUSB 1ポート(USBクライアント用)
イーサネット:10M/100M RJ45コネクタ(つまり普通のLANコネクタ)
ユーザインターフェース:リセットボタン 1個
ストレージ:4GBのマイクロSDカード付き
お値段:89ドル
通信:I2C 2ポート UART 4ポート


miniUSBからの給電で動作できるようなので、モバイルブースターとかでも動作させることができるかも?
説明文にはBeagleBoneの中に開発環境があり、ブラウザでアクセスしてコーディングするスタイルをとれるとのことです。なんだかとても面白そう。

今年の年末頃にアメリカで販売されるようです。
日本のDigikeyで扱ってくれるのはいつ頃になるかなぁ。。

2011/11/08

Linuxのシリアル通信プログラム

前回はLinux上でのネットワークプログラミングをやって(コピペして)みましたが、
今回はシリアル通信のプログラミングをやってみたいと思います。

参考元:The Linux Serial Programming HOWTO(日本語版)
時々見れない場合もあるので、そんなときは英語版の方を参照してください。
検索すれば他の日本語訳のサイトも見つかるかもしれません。


上記ページにあったサンプルコードをいじって、受信と送信でプロセスを分けて処理する形に変更してみました。
実験したところ、無事Arduinoからのデータの受信と、送信ができるようになりました。



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <sys/wait.h>

/* <asm/termbits.h> で定義されているボーレートの設定.これは
 <termios.h>からインクルードされる. */
#define BAUDRATE B9600
//Arduinoのソフトウェアシリアルでも使えるように9600bpsにする

/* 適切なシリアルポートを指すように,この定義を変更
 * 我が家の環境ではArduinoは/dev/ttyACM0になってました*/
#define MODEMDEVICE "/dev/ttyACM0"

#define BUFFSIZE 256
#define COULDNOTFORK -1

#define FALSE 0
#define TRUE 1

volatile int STOP = FALSE;
static int fd = -1;

/* Functions */
void serial_init(int fd);
void child_process();
void parent_process(pid_t result_pid);

/* Main */
int main(void);

// シリアルポートの初期化
void serial_init(int fd) {
    struct termios tio;
    memset(&tio, 0, sizeof(tio));
    tio.c_cflag = CS8 | CLOCAL | CREAD;
    /*
     BAUDRATE: ボーレートの設定.cfsetispeed と cfsetospeed も使用できる.
     CS8     : 8n1 (8 ビット,ノンパリティ,ストップビット 1)
     CLOCAL  : ローカル接続,モデム制御なし
     CREAD   : 受信文字(receiving characters)を有効にする.
     */

    tio.c_cc[VTIME] = 0; /* キャラクタ間タイマは未使用 */

    /*
     ICANON  : カノニカル入力(行単位入力)を有効にする
     */
    tio.c_lflag = ICANON;

    /*
     IGNPAR  : パリティエラーのデータは無視する
     ICRNL   : CR を NL に対応させる(これを行わないと,他のコンピュータで
     CR を入力しても,入力が終りにならない)
     それ以外の設定では,デバイスは raw モードである(他の入力処理は行わない)
     */
    tio.c_iflag = IGNPAR | ICRNL;

    // ボーレートの設定
    cfsetispeed(&tio, BAUDRATE);
    cfsetospeed(&tio, BAUDRATE);
    // デバイスに設定を行う
    tcsetattr(fd, TCSANOW, &tio);
}

void child_process() {

    char buf[BUFFSIZE];
    char input[BUFFSIZE];
    int count;
    int i;
    int writecount = 0;

    fprintf(stdout, "CHILD:RCV Start\n");

    //STOPになるまで無限ループ
    while (FALSE == STOP) {
        memset(&buf, 0, sizeof(buf));
        count = read(fd, &buf, BUFFSIZE);
        if (count < 0) {
            fprintf(stdout, "CHILD:Could not read from serial port\n");
            STOP = TRUE;
        } else {
            fprintf(stdout, "CHILD:RCVD CHAR %s %d", buf, count);

        }
    }

    fprintf(stdout, "CHILD:BYE!\n");
}

void parent_process(pid_t result_pid) {

    char input[BUFFSIZE];
    int writecount = 0;
    fprintf(stdout, "Parent:Waiting for Input\n");
    int i = 0;
    int inputcount = 0;
    while (1) {
        memset(&input, 13, sizeof(input));

        fgets(input, sizeof(input), stdin);
        fflush(stdin);

        //改行コード埋め込み
        for (i = 0; i < BUFFSIZE; i++) {
            if (input[i] == 0) {
                inputcount = i;
                input[i] = 13;
                input[i + 1] = 10;
                break;
            }
        }

        writecount = write(fd, &input, inputcount);
        if (writecount < 0) {
            fprintf(stdout, "Could not write to serial port %d\n", writecount);
            break;
        } else {
            fprintf(stdout, "Send %d bytes\n", writecount);

        }

    }
}

int main(void) {
    pid_t result_pid;

    struct termios oldtio, newtio;
    char buf[255];
    /*
     読み書きのためにモデムデバイスをオープンする.ノイズによって CTRL-C
     がたまたま発生しても接続が切れないように,tty 制御はしない.
     */

    fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
    if (fd < 0) {
        perror(MODEMDEVICE);
        return (-1);
    }

    tcgetattr(fd, &oldtio); /* 現在のシリアルポートの設定を待避させる*/
    memset(&newtio, 0, sizeof(newtio));/* 新しいポートの設定の構造体をクリアする */

    //シリアルポート準備
    serial_init(fd);

    //forkして受信用と送信用に分ける
    result_pid = fork();

    if (result_pid == -1) {
        fprintf(stderr, "fork failed.\n");
        return COULDNOTFORK;
    }

    if (result_pid == 0) {
        child_process();
    } else {
        fprintf(stderr, "fork completed");

        parent_process(result_pid);
    }
    STOP = TRUE;

    return 0;
}


ではまた。

2011/11/03

USB接続LEDライト制作

最近は暗くなるのが非常に早くなりました。
18時ぐらいになったらもう明かりが必要になってきます。

というわけでLEDライトを作ることにしました。

LEDを使うとなると5V電源が必要になってきますが、今回は市販のUSB電源を使うことにしました。基板ごとに電源回路をつけるとお金がかかる為です。

USBコネクタはDCジャックに比べ設置面積が必要ですが、コネクタ形状が長方形なのでDCジャックのようにクルクル回転しないで済みます。


L字型 DCジャックだったものを改造


eneloopで点灯した様子
5V200mA使用

ハイパワーLEDだと明るくて良いのですが、電池の減りが速いため、電力を抑えた角形LED版も作ってみました。



角形LED使用版
5V 80mA
モバイルブースターの大容量版を使えば、1日ぐらいならつけっぱなしでも大丈夫かもしれません。