今回遊ぶのは、大宮技研さんの「Groovy-IoT」です。
http://www.omiya-giken.com/?page_id=2262
世の中にたくさん出回っているGroveセンサをつなぐことができます。
ホストPCとはUSBで接続するので、Raspberry-Piなどの一般的なPCやマイコンで制御することができるようになります。
今回は、ホストPCとして、Raspberry-Piを使います。
大宮技研さんの方で、「Kikori」というclojureベースのツールを用意していただいているのですが、もっと気軽に扱いたかったので、Node.jsから扱えるようにネイティブ拡張モジュールを作ってみました。
(参考) Kikori
https://gitlab.com/myst3m/kikori
それから、Groveセンサを操作するためのライブラリは、Arduinoが多いので、ネイティブ拡張モジュールのAPIは、ArduinoのGPIOとI2CとSerialのそれに似た形してみました。
今回サンプルとして動かしてみるのは、「Grove - LED Bar」です。
https://www.seeedstudio.com/Grove-LED-Bar-v2-0.html
ソースコードもろもろをGithubに上げておきました。
https://github.com/poruruba/node-groovy-iot
[2019/8/4 追記]
アナログ入出力に対応させました。ちょっと動きが怪しいかも。
この続編です。
Groovy-IoTをNode.jsから操ってみた:もう少しArduinoっぽいAPI
Groovy-IoT をC言語で触ってみる
Groovy-IoT には、Microchip製のMCP2221Aというチップが乗っています。
そこにI2C、GPIO、UARTのペリフェラルがありGroveモジュールの接続端子に接続されています。
USBでGroovy-IoTとホストPCを接続するのですが、操作はHIDで行うので、ホストPC側はHIDさえ扱えればよいです。
ちょうど、MPC2221用にライブラリを提供していただいている方がいましたので、ありがたく使わせていただきました。
libmcp2221
https://github.com/zkemble/libmcp2221
コンパイルに外部ライブラリが必要ですので、インストールしておきます。
> apt-get install libudev-dev libusb-1.0-0-dev
以下のファイルを使いますので、libmcp2221のWebページを参考にダウンロードしておきます。
- libmcp2221.c
- libmcp2221.h
- hid.c
- hidapi.h
もう一つ補足しておきます。
ホストPCに接続すると、HIDのほかに、仮想COMポートも割り当たります。
MCP2221AのペリフェラルとしてUARTがあり、Grove端子に割り当てられていますが、それにアクセスするには、ホストPC側に現れた仮想COMポートを使うのです。
dmesgを載せておきます。
[164546.769340] Indeed it is in host mode hprt0 = 00021501
[164546.979214] usb 1-1: new full-speed USB device number 13 using dwc_otg
[164546.979575] Indeed it is in host mode hprt0 = 00021501
[164547.222987] usb 1-1: New USB device found, idVendor=04d8, idProduct=00dd, bcdDevice= 1.00
[164547.223008] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[164547.223017] usb 1-1: Product: MCP2221 USB-I2C/UART Combo
[164547.223026] usb 1-1: Manufacturer: Microchip Technology Inc.
[164547.240438] cdc_acm 1-1:1.0: ttyACM0: USB ACM device
[164547.250507] hid-generic 0003:04D8:00DD.000C: hiddev96,hidraw0: USB HID v1.11 Device [Microchip Technology Inc. MCP2221 USB-I2C/UART Combo] on usb-20980000.usb-1/input2
Groovy-IoT を一般ユーザで触る
Groovy-IoTをRaspberry-Piにつなぐと、特に追加のデバイスドライバのインストールをせずとも、自動的に認識してくれるので楽ちんです。
ですが、そのままではルート権限を持ったユーザしかアクセスできませんので、一般ユーザでもアクセスできるようにします。
まず、HIDアクセスです。
/etc/udev/rules.d 配下に、以下のファイルを作成して配置します。
KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00dd", MODE="0666"
次に、仮想COMポートです。
仮想COMポートは、/dev/ttyACM0 として見えますが、この所有者groupはdialoutです。ですので、そのgroupに、アクセスしたい一般ユーザを追加すればよいです。
> sudo gpasswd -a ユーザ名 dialout
念のため、設定後、Raspberry Piを再起動しましょう。
Arduino っぽく扱う
以下、こんな感じのC言語の関数にしてみました。
Arduinoっぽくないですか?ソースコードは割愛します。Githubを参照して下さい。
# ifndef _MCP2221_H_
# define _MCP2221_H_
# ifdef __cplusplus
extern "C" {
# endif // __cplusplus
long MCP2221_initialize(void);
long Wire_initialize(void);
long Wire_dispose(void);
void Wire_beginTransmission(unsigned char address);
int Wire_write_byte(unsigned char value);
int Wire_write_str(const char *p_str);
int Wire_write_array(const unsigned char *p_data, int length);
void Wire_endTransmission(void);
int Wire_requestFrom(unsigned char address, int count);
int Wire_available(void);
unsigned char Wire_read(void);
# define HIGH 1
# define LOW 0
# define INPUT 0
# define OUTPUT 1
# define INPUT_PULLUP 2
# define DEFAULT 0
long GPIO_initialize(void);
void pinMode(unsigned char pin, unsigned char mode);
void digitalWrite(unsigned char pin, unsigned char value);
unsigned char digitalRead(unsigned char pin);
unsigned short analogRead(unsigned char pin);
void analogWrite(unsigned char pin, unsigned short value);
void analogReference(unsigned char type);
void analogReadResolution(unsigned char bits);
void analogWriteResolution(unsigned char bits);
void Serial_initialize(unsigned char sport);
long Serial_begin(unsigned long speed);
void Serial_end(void);
int Serial_available(void);
int Serial_read(void);
int Serial_peek(void);
void Serial_flush(void);
int Serial_write_byte(unsigned char val);
int Serial_write_str(const char *p_str);
int Serial_write_array(const unsigned char *p_data, int len);
int Serial_print(const char *data);
int Serial_println(const char *data);
# ifdef __cplusplus
}
# endif // __cplusplus
# endif
Node.jsネイティブ拡張モジュールを作成する
ネイティブ拡張モジュールを作成するために、node-gypを使います。
> npm install -g node-gyp
まずは適当なフォルダを作成しましょう
> mkdir mcp2221native
> cd mcp2221native
binding.gypを作成します。
{
"targets": [
{
"target_name": "mcp2221native",
"sources": [ "mcp2221native.cc", "mcp2221.c", "hid.c", "libmcp2221.c", "utility.cc"],
"libraries": [
"-ludev"
]
}
]
}
上記gypファイル見てわかる通り、以下のファイルを使います。
- mcp2221native.cc:これがネイティブ拡張モジュールの肝となるファイルです。
- mcp2221.c:先ほど作成しました。
- hid.c:ダウンロードしておいたファイルです。
- libmcp2221.c:ダウンロードしておいたファイルです。
- utility.cc:ユーティリティを集めたものです。作成しておきました。
mcp2221native.cc がネイティブ拡張の中心的な役割を果たしているのですが、やっていることは、Node.jsから呼ばれるI/Fとそれをmcp2221.cで作成した関数に橋渡ししているだけです。
ちなみに、"-ludev" は、内部でudevを使っており、このライブラリをリンクする必要があるためです。
まずは、以下。コンパイルの下準備だそうです。フォルダやMakefileを作ってくれます。
> node-gyp configure
以下で、ソースコードをコンパイルします。
> node-gyp build
これで、フォルダ「mcp2221native\build\Release」に、「mcp2221native.node」ができあがりました。
つぎに、このnodeファイルを、Nodeから、require('mcp2221native') って感じで使えるようにします。
どこか適当なフォルダを作成し、そこにコピー(もしくはシンボリックリンク)します。
例えば、以下の通りです。
> mkdir ~/node_native
> cp mcp2221native/build/Release/mcp2221native.node ~/node_native/
次に、Nodeがこれを検索できるようにします。
.bashrcの最後に以下を追記します。
export NODE_PATH=~/node_native
これでOKです。.bashrcを反映するために以下を実行しておきます。
source ~/.bashrc
Groove LED Barを使ってみる
さっそく、Groovy-IoTとそれにつないだGroveセンサを操作するNode.jsのソースを作成ましょう。
以下のような感じでGroovy-IoTにアクセスできます。
詳細は、Githubのmcp2221_test/index.jsを参考にしてください。
// まずはrequreして。。。
const mcp2221 = require('mcp2221native');
// Groovy-IoTに接続して。。。
var ret = mcp2221.initialize(0);
// ペリフェラルを初期化して。。。
ret = mcp2221.GPIO_initialize();
ret = mcp2221.Wire_initialize();
ret = mcp2221.Serial_initialize();
ret = mcp2221.Serial_begin(115200);
// 例えばこんな感じ。。。
mcp2221.GPIO_pinMode(__pinClock, OUTPUT);
mcp2221.GPIO_pinMode(__pinData, OUTPUT);
以上