LoginSignup
1
0

More than 3 years have passed since last update.

Groovy-IoTをNode.jsから操ってみた:もう少しArduinoっぽいAPI

Last updated at Posted at 2019-08-04

前回の記事 Groovy-IoTをNode.jsから操ってみた で、Groovy-IoTをNode.jsから扱えるようにしたのですが、Node.js向けのAPIがまだArduinoっぽくなかったので、今回はもう少しArduinoに近づけます。

例えば、
 Serial.println()
とするべきところを、
 Serial_println()
となっていました。これを直します。

これで、Arduinoにより近づいたので、いくつかのGroveのドライバを移植しました。試したのは以下の4つです。すべてマルツ秋葉原本店( https://www.marutsu.co.jp/GoodsListNavi.jsp?path=1100020003 )で購入しました。

  • Grove - LED Bar
  • Grove - PIR Motion Sensor
  • Grove - Digital Light Sensor
  • Grove - Light Sensor(P)

(2つLight Sensorがあるのですが、前者がI2C接続、後者がアナログGPIO接続です)
(ちなみに、Grove - Temperature, Humidity, Pressure and Gas Sensor(BME680)も買ったのですが、C言語すぎて移植を中断中)

ソースコードもろもろはGithubに上げてあります。
 https://github.com/poruruba/node-groovy-iot

ArduinoっぽいAPI

ネイティブ拡張モジュールの実装では、すべてのAPIは横並びでした。
たとえば、Serial_printlnだったりWire_beginTransmissionしました。
一方、Arduinoでは、Serial.println となっていて、「.」で表現しています。これは、世にいうオブジェクト指向のClass/Objectに相当します。
Node.jsにもあるので、横並びのAPIを呼び出すNode.jsのクラスを実装しようと思います。

さっそくソースコードです。

mcp2221lib.js
const mcp2221 = require('mcp2221native');
var mcp2221_initialized = false;

function mcp2221_initialize(){
  var ret = mcp2221.initialize();
  if( ret != 0 )
    throw 'mcp2221.Serial_initialize error';

  mcp2221_initialized = true;
}

class Serial{
  initialize(sport){
    if( !mcp2221_initialized )
      mcp2221_initialize();

    var ret = mcp2221.Serial_initialize(sport);
    if( ret != 0 )
      throw 'mcp2221.Serial_initialize error';

    this.DEC = -1;
    this.BIN = -2;
    this.OCT = -3;
    this.HEX = -4;
  }

  begin(speed){
    return mcp2221.Serial_begin(speed);
  }

  end(){
    mcp2221.Serial_end();
  }

  available(){
    return mcp2221.Serial_available();
  }

  read(){
    return mcp2221.Serial_read();
  }

  peek(){
    return mcp2221.Serial_peek();
  }

  flush(){
    mcp2221.Serial_flush();
  }

  write(param, len){
    if( len === undefined)
      return mcp2221.Serial_write(param);
    else
      return mcp2221.Serial_write(param, len);
  }

  write(buf, len){
  }

  convert(data, format){
    var str;

    if( typeof data == 'string'){
      str = data;
    }else{
      if( format >= 0 ){
        str = data.toFixed(format);
      }else{
        switch(format){
          case this.BIN:
            str = data.toString(2);
            break;
          case this.OCT:
            str = data.toString(8);
            break;
          case this.HEX:
            str = data.toString(16);
            break;
          default:
            str = data.toString(10);
            break;
        }
      }
    }

    return str;
  }

  print(data, format){
    var str = this.convert(data, format);
    return mcp2221.Serial_print(str);
  }

  println(data, format){
    var str = this.convert(data, format);
    return mcp2221.Serial_println(str);
  }
}

class GPIO{
  initialize(){
    if( !mcp2221_initialized )
      mcp2221_initialize();

    var ret = mcp2221.GPIO_initialize();
    if( ret != 0 )
      throw 'mcp2221.GPIO_initialize error';

    this.INPUT = 0;
    this.OUTPUT = 1;

    this.LOW = 0;
    this.HIGH = 1;

    this.DEFAULT = 0;
  }

  pinMode(pin, mode){
    mcp2221.GPIO_pinMode(pin, mode);
  }

  digitalWrite(pin, value){
    mcp2221.GPIO_digitalWrite(pin, value);
  }

  digitalRead(pin){
    return mcp2221.GPIO_digitalRead(pin);
  }

  analogRead(pin){
    return mcp2221.GPIO_analogRead(pin);
  }

  analogWrite(pin, value){
    mcp2221.GPIO_analogWrite(pin, value);
  }

  analogReference(type){
    mcp2221.GPIO_analogReference(type);
  }

  analogReadResolution(bits){
    mcp2221.GPIO_analogReadResolution(bits);
  }

  analogWriteResolution(bits){
    mcp2221.GPIO_analogWriteResolution(bits);
  }
}

class Wire{
  initialize(){
    if( !mcp2221_initialized )
      mcp2221_initialize();

    var ret = mcp2221.Wire_initialize();
    if( ret != 0 )
      throw 'mcp2221.Wire_initialize error';
  }

  beginTransmission(address){
    mcp2221.Wire_beginTransmission(address);
  }

  endTransmission(){
    mcp2221.Wire_endTransmission();
  }

  requestFrom(address, count){
    return mcp2221.Wire_requestFrom(address, count);
  }

  available(){
    return mcp2221.Wire_available();
  }

  read(){
    return mcp2221.Wire_read();
  }

  write(param, len){
    if( len === undefined )
      return mcp2221.Wire_write(param);
    else
      return mcp2221.Wire_write(param, len);
  }
}

var gpio = new GPIO();

module.exports = {
  initialize : mcp2221_initialize,
  Serial : new Serial(),
  GPIO: gpio,
  Wire: new Wire(),
  pinMode : gpio.pinMode,
  digitalWrite: gpio.digitalWrite,
  digitalRead: gpio.digitalRead,
  analogRead: gpio.analogRead,
  analogWrite: gpio.analogWrite,
  analogReference: gpio.analogReference,
  analogReadResolution: gpio.analogReadResolution,
  analogWriteResolution: gpio.analogWriteResolution
}

使い方

まずは、先ほど作成したNode.jsのソースコードをrequireします。

const { Serial, GPIO, Wire, pinMode, digitalRead, analogRead } = require('./mcp2221lib');

ここで、利用したいクラスと、利用したいGPIO関係の関数を指定します。
次に、初期化します。

    Serial.initialize(0);
    GPIO.initialize();
    Wire.initialize();

Serial.initializeに指定している数字は/dev/ttyACM0 の数字です。複数の仮想COMポートを持ったデバイスをマイコンに接続していると、Groovy-IoTに割り当たる数字が変わってきますので、確認して指定してください。

あとは、Arduinoでよく見るAPI呼び出しができるようになります。Serial.printlnやWire.beginTransactionなど。
以下を参考にさせていただいて真似ました。

Arduino 日本語リファレンス
 http://www.musashinodenpa.com/arduino/ref/

ドライバの移植

ドライバが必要なのは、以下の2つです。

  • Grove - LED Bar
  • Grove - Digital Light Sensor

それぞれ、Grove_LED_Bar.js、Digital_Light_TSL2561.js というファイル名で作成しました。
Arduinoにライブラリインストールされたcまたはcpp言語ファイルを移植したものです。
ソースコードは、GitHubを参照してください。

以下の2つは、Digital InputとAnalog Inputですので、ドライバは不要です。

  • Grove - PIR Motion Sensor
  • Grove - Light Sensor(P)

使い方はこんな感じです。

index.js
const { Serial, GPIO, Wire, pinMode, digitalRead, analogRead } = require('./mcp2221lib');
const ledbar = require('./Grove_LED_Bar');
const TSL2561 = require('./Digital_Light_TSL2561');

async function test(){
    Serial.initialize(0);
    GPIO.initialize();
    Wire.initialize();

/* UART */
/*
    Serial.begin(9600);

    var ret = Serial.println("Hello World");
    console.log(ret);
*/

/* Grove - PIR Motion Sensor */
/*  
    pinMode(2, GPIO.INPUT);
    while(true){
        if( digitalRead(2) )
            console.log("Hi, people is comming");
    }
*/

/* Grove - Digital Light Sensor */
/*
    TSL2561.init();
    console.log(await TSL2561.readVisibleLux());
*/

/* Grove - LED Bar */
/*
    var Grove_LED_Bar = new ledbar(1, 0, 0, 10);
    Grove_LED_Bar.setLevel(3);
*/

/* Grove - Light Sensor(P) */
/*
    console.log( analogRead(2) );
*/

    return;
}

test();

ちょっと、補足すると、digitalReadやanalogReadで指定している番号は、PIN番号になります。
どのPIN番号が、Groovy-IoTのどのポートに割り当たっているかは、以下の方のページが非常に参考になります。

 Groovy-IoT + kikori (2. 標準ハードウェア)

結局、以下の通りです。

・GPIO1(GPIO/ADC/CLKR)
 Pin1:GP0 ★これがPIN番号0
 Pin2:GP1/ADC1/CLKR ★これがPIN番号1

・GPIO2(GPIO/ADC/DAC)
 Pin1:GP2/ADC2/DAC1 ★これがPIN番号2
 Pin2:GP3/ADC3/DAC2 ★これがPIN番号3

digitalRead(2) や analogRead(2) では2を指定しているので、GPIO2のGrove端子のPin1に対応します。(GPIO1のPin1も使いたかったのですが、DACやADCとしては使えないようです。)

以上

1
0
0

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
1
0