2015年2月22日日曜日

GrovePi お試し。

 本日のガラクタは、GrovePi です。一ヶ月以上も前に Dexter Industries社に直接発注してあったんですが、Dexter社は即日発送してくれたにもかかわらず、その後USPS(アメリカの郵便局?)に荷物が渡った後、トラッキング照会すると、3週間以上前にシカゴに着いたまま荷動きがありません。通関業務で止まってしまっているのか?このまま、どこかへ消滅してしまうのかはわかりませんが、そんなこんなしている間に、スイッチサイエンスさんから GrovePi+ が発売されていたので、まずは、そちらで手に入れました。GrovePi+ は GrovePi の改良版で、GrovePi を Raspberry Pi B+ にスタックするとLANコネクタやUSBコネクタで基盤裏側のパーツのハンダランドがショートしてしまうのですが、GrovePi+ では裏側に部品のランドが出ない(内層)形になっています。それに合わせて、Arduino部分のチップがDIPから表面実装に変わっています。あと、カメラのフラットケーブルを通せるスリットが開いています。それ以外の違いは、自分はわかりませんが、以前のGrovePi (+じゃない)でも、LAN、USBコネクタの位置にGrovePiの裏側にマスキングテープなどを貼れば、問題なく使えるはずです。
 で、GrovePi は、Arduino の Grove System シリーズのセンサーなどをRaspbery Piで利用できるようにするベースシールド的なものですが、通常のベースシールドはArduinoの各ピンと接続されているわけですが、GrovePi ではGrove コネクタがRaspberry Pi にすべて直に接続されているわけではなく(されているコネクタもある。UARTとかI2Cとか。)て、間にArduino相当のマイコンを挟んでいます。
 GrovePi のWikiにある画像を借りると、



 上記のような感じで、 Raspberry Pi から UARTとI2CがGroveコネクタにつながっているほか、Raspberry Pi と GrovePi(上のArduino)がSPIとI2Cで接続されいて、GrovePiのSerial, Digital IO(PWMも), Analog入力を利用できるようになっています。自分がよく使う Raspberry Pi と Arduino (Micro) をUSBかUARTで接続して組み合わせるパターンに似ていますが、GrovePIではI2CでArduinoを制御して、SPI接続でRasperyy PI側からAVRのファームの書き換えも行えるようになっているようです。
 もともと、Grove のセンサやLCD等をいくつか持っているので、このGrovePi も試してみようと思っていました。


 以下、開封したところ。


 裏側。


  Raspberry Pi B+ にスタックしたところ。



 以下、Grove RGB LCD をサンプルソースで動かしてみたところです。GrovePi を利用するためのライブラリは Python で提供されていますので、コードは Python で記述することになりますが、適用されているPythonのサンプルとライブラリのソースを見れば、各GroveモジュールやAVRとのI2Cでのやりとりは解析できそうなので、C/C++などでも利用することは可能ではないでしょうか。
 Grove はハンダ付け無しでブロック感覚で色々遊べるのが楽しいですが、ブレッドボードと併用して、ちょっとした試作にも便利だと思います。









2015年2月16日月曜日

Galileo で Windows for IoT その2

 今回のガラクタは、前回に引き続き Windows for IoT with Galileo です。Windows for IoT の良いところは、やはり、Visual Studio で Windows (のコンソール)アプリとして、開発・デバッグが出来るところではないかと思います。ただ、Realtime OS や Arduino のようなOSなしマイコン直接操作 みたいのに比べるとリアルタイム性は無いので、そういった必要性があるところには使えません。逆に言うと、じゃあ、どんなところに使えるんだ?って話で、Raspberry Pi を使うようなネットワークやら、計算・画像処理なんかの重めのところをやらせるのがいいんじゃないでしょうか?まあ、自分の中では、その手の用途は Raspberry Pi + Arduino (Micro) のコンビがデフォルトになっているわけですが、今回は、Windows for IoT で遊ぶということで、Galileo で WinSock (Socket) 通信を試してみようと思います。
 基本的には、こちらにあるサンプルの流用となりますが、Galileo側で WinSock Server プログラムを動かして、Windows PC からWinSock Client プログラムで接続して、文字を送信、Galileo 側が受信文字によってAnalogRead()の値をClient側に返すというシンプルなものです。また、ついでに、前回のLCDシールドも使って、応答文字列をLCDにも表示しています。
 今回は GroveシールドとLCDシールドをスタックしています。Grove も DigitalWrite() や DigitalRead() などで使える簡単なものは動きますが、超音波距離センサを使おうと思ったところ pulseIn()関数が使えないようでした。


 PCのクライアントソフトで接続して、x とか y とか送信すると、AnalogRead() でジョイスティックの値を読み込んで、LCDに表示しつつ、クライアント側に応答送信します。



  Galileo側の WinSock Server のソースはこちらPC側のテスト用クライアントのソースはこちら にあります。
 一応、Galileo側のコードだけ以下に掲載。


#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include "stdafx.h"
#include "arduino.h"
#include "LiquidCrystal.h"
// Ws2_32.lib のリンクが必要。
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
// LCD pin <=> Arduino pin
int RS = 12;
int ENABLE = 11;
int DB4 = 5, DB5 = 4, DB6 = 3, DB7 = 2;
LiquidCrystal lcd = LiquidCrystal(RS, ENABLE, DB4, DB5, DB6, DB7);
int __cdecl main(void)
{
WSADATA wsaData;
int iResult;
SOCKET listenSocket = INVALID_SOCKET;
SOCKET clientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char rcvBuf[DEFAULT_BUFLEN];
int rcvBufLen = DEFAULT_BUFLEN;
// LCDの初期化。16文字×2行。
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print("Hello,WinIoT !");
// WinSockの初期化。WinSock Ver.2.2、MAKEWORD(メジャVer, マイナVer)。
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
// 変数の初期化。
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Serverのアドレスとポートの解決。
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0)
{
printf("getaddrinfo failed with error: %d\n", iResult);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
// Server接続のためのSocketの生成。
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (listenSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
// getaddrinfo()で確保したメモリの解放。
freeaddrinfo(result);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
// TCP リスナソケットの設定。ソケットをアドレス・ポートに結びつける。
iResult = bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
// getaddrinfo()で確保したメモリの解放。
freeaddrinfo(result);
// ソケットを閉じる。
closesocket(listenSocket);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
// getaddrinfo()で確保したメモリの解放。
freeaddrinfo(result);
// ソケットリスナを接続待ちにする。
iResult = listen(listenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
printf("listen failed with error: %d\n", WSAGetLastError());
// ソケットを閉じる。
closesocket(listenSocket);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
// クライアントソケット受け入れ。
clientSocket = accept(listenSocket, NULL, NULL);
if (clientSocket == INVALID_SOCKET)
{
printf("accept failed with error: %d\n", WSAGetLastError());
// ソケットを閉じる。
closesocket(listenSocket);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
// 不要なソケットを閉じる。
closesocket(listenSocket);
// 相手が接続を閉じるまで、受信する。
do
{
// ソケット受信。
iResult = recv(clientSocket, rcvBuf, rcvBufLen, 0);
if (iResult > 0)
{
printf("Bytes received: %d\n", iResult);
// 受信文字によって、バッファをAnalogRead()値で書き換え。
switch (rcvBuf[0])
{
case 'x':
case 'X':
{
int val = analogRead(A0);
iResult = sprintf(rcvBuf, "X: %d\n", val);
break;
}
case 'y':
case 'Y':
{
int val = analogRead(A1);
iResult = sprintf(rcvBuf, "Y: %d\n", val);
break;
}
default:
break;
}
// 送信側に受信したバッファの内容を返す。
iSendResult = send(clientSocket, rcvBuf, iResult, 0);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
// ソケットを閉じる。
closesocket(clientSocket);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
// LCDに表示。
if (iResult <= 16)
{
rcvBuf[iResult] = '\0';
}
else
{
rcvBuf[16] = '\0';
}
lcd.setCursor(0, 1);
lcd.print(rcvBuf);
}
else if (iResult == 0)
printf("Connection closeing...\n");
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
// ソケットを閉じる。
closesocket(clientSocket);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
} while (iResult > 0);
// ソケット送受信の無効化。
iResult = shutdown(clientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
// ソケットを閉じる。
closesocket(clientSocket);
// Winsockのリソース解放。
WSACleanup();
return 1;
}
// ソケットを閉じる。
closesocket(clientSocket);
// Winsockのリソース解放。
WSACleanup();
return 0;
}
view raw gistfile1.cpp hosted with ❤ by GitHub

2015年2月7日土曜日

Raspberry Pi 2 が届きました。 & Galileo で Windows for IoT 。

 今回のガラクタは、先日発表された Raspberry Pi 2 Type B です。お値段据え置きでパフォーマンス6倍らしいです。


 外観、IOのレイアウトは Raspberry Pi B+ を踏襲しています。

 パフォーマンスが6倍になっているかはわかりませんが、体感速度はかなり向上しています。従来モデルでは、Chromiusを立ち上げるとしばらくCPUが100%に張り付いて戻ってこなかったのが、Chromiusと同時に複数アプリを起動しても以前よりレスポンスがいいです。


 これは、やはり、CPUの4コア化とメモリの倍増が効いていますね。
 Raspberry Pi の公式サイトに 他プラットフォーム との比較表が掲載されていました。


 色々と使い道が広がりそう、特にOpenCVなんかは、色抽出とか顔検出とか、今まで処理的にきつかったのが、今後は期待できるんじゃないでしょうか。そのうち、試してみたいところです。ちなみに OpenCVのソースからのビルドを行ったところ、3時間くらいで終わりました。B、B+では半日(寝る前にmakeして、朝まで放置させて6~8時間かかっていたんじゃないでしょうか?)

 また、Raspberry Pi 2 に対しては、Microsoft が Windows 10 (Windows IoT)  for Raspberry Pi 2 の対応を発表しています。Windows for IoT は、通常の Windows のようなGUIベースのデスクトップOSではなく、コマンドラインベースの組み込み向けOSです。今回(今年後半予定)のRaspberry Pi 2用のWindows for IoT がどのようなもの(GUI付き?)になるかわかりませんが、現状、Galileo に提供されている Windows for IoT を考えると、Visual Studio で組み込み開発ができるOSというイメージではないかという想像でいます。

 と、いうわけで、Raspberry Pi 2 → Windows for IoT という話の流れで、以前に入手して、使い道がなく 活用できずに、ホコリをかぶっていた Galileo を引っ張り出してきて、Windows for IoT のお試しをしてみることにしました。

 Galileo 用の Windows for IoT のセットアップに関しては、 こちら(KEI SAKAKI'S PAGE) を参考にさせていただきました。Windows Developer Program for IoTへの登録とツールやイメージのダウンロード、Visual Studio 2013 (Express や Communities でもOKなはず) の開発環境が必要になります。
 各種準備やセットアップに関しては公式サイトにもありますが、先のこちら(KEI SAKAKI's PAGE さん) が日本語かつ画面入りの丁寧な説明を掲載されているので、こちら を参考にする方が良いです。感謝です。
 また、色々試してみた後に見つけたものですが、Microsoftの中の人っぽい方が説明資料を公開してくれています。

 上記の2つの日本語サイトの情報を見てもわかるのですが、基本的にはArduinoベースのプログラミングがC++でできます。だったら、Arduinoでいいじゃん・・・っていう話ですが、(Galileoを使うにしたって、元のGalileoのままでArduino IDE使えるし)、しかし、なんと、Visual Studioで開発ができます・・・って、どうでもいいですか?Visual Studio大好きっ子(子じゃねぇし、ジジィだし・・・)の自分としては、結構うれしいし、ただ、Visual Studioでコードが入力出来るだけではありません。通常のVisual Studioで行うWindowsプログラミング(コンソールプログラミングかな?どちらかというと)同様にブレークポイントを設定して、ステップ実行&デバッグができます。これは、嬉しい!Arduino IDEも嫌いじゃないですが、やっぱり、Visual Studioが好き。Raspberry Pi のプログラミングもわざわざお金払ってVisualGDBっていうVisual StudioからRaspberry PiのGDBにリモートデバッグできる有償プラグイン買ったりして、Visual Studio使ってるし。

 で、まずは、Windows for IoT をセットアップした Galileo に試しに Telnet 接続してみます。SSHじゃないところが気になりますが、もともとWindowsなのでtelnetサービス(しか)が標準で装備されている(通常のOS利用ではサービスが停めてあるはずですが)ので、Telnet ということなんでしょう。ユーザ:administrator、パスワードはイメージ作成時に指定したパスワードで接続すると、見慣れたコマンドプロンプトが C:\Windows\Sytem32\ みたいに表示されるので、ああ、Windowsなんだなって思います。



 実際にはtelnet接続は何かの設定を行う以外は、プログラムを動かす上ではあまり関係なく、開発を行うには、Visual Studio で C++→Windows for IoTプロジェクトを作成して、デバッグの構成で、デバッグ対象のGalileoをネットワーク名かまたはIPアドレスで指定して、Visual Studioから接続できるようにしておきます。
 今回は、公式サイトにあったLCDへの表示のプロジェクトを参考に、スイッチサイエンスさんでずっと前に入手したPrototyping Labという書籍に出てくるLCD Shieldの配線に合わせてコードを少し変えたものを作成してみました。


 上の写真は「Hello,WinIoT!」を表示した後、1行毎に2行目の数字をカウントアップするスケッチを動かして、途中でブレークポイントを設定して、一時停止させたところです。メインのソースは以下の様な感じ。プロジェクトはこちらにあります。

// Main.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
// LCD pin <=> Arduino pin
int RS = 12;
int ENABLE = 11;
int DB4 = 5, DB5 = 4, DB6 = 3, DB7 = 2;
LiquidCrystal lcd = LiquidCrystal(RS, ENABLE, DB4, DB5, DB6, DB7);
int _tmain(int argc, _TCHAR* argv[])
{
return RunArduinoSketch();
}
int led = 13; // This is the pin the LED is attached to.
void setup()
{
Log(L"LCD Sample\n");
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print("Hello,WinIoT !");
}
// the loop routine runs over and over again forever:
void loop()
{
lcd.setCursor(0, 1);
lcd.print(millis() / 1000);
}
view raw gistfile1.cpp hosted with ❤ by GitHub