LoginSignup
0

More than 3 years have passed since last update.

Groovy-IoTをNode.jsから操ってみた

Last updated at Posted at 2019-07-10

今回遊ぶのは、大宮技研さんの「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 配下に、以下のファイルを作成して配置します。

99-hid.rules
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を参照して下さい。

mcp2221.h
#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を作成します。

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を参考にしてください。

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);

以上

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0