LoginSignup
19
23

More than 5 years have passed since last update.

Modbus機器とRaspberry PI/PowerBIを使ったIoT

Last updated at Posted at 2017-04-24

zu2.png

概要

 生産設備や、ビル管理機器等で広く使われているModbusという規格があります。TCP/IP上からRS485のようなシリアル通信まで、色々な局面で利用されてきました。IoTを考える時、このModbus機器をどのように接続するかが課題となることも多いでしょう。
RS485はシリアル接続ですが、電圧の差動で動作し、ノイズに強く1km以上ケーブルを伸ばせることから、無線が使えない場合でも長距離の通信を行うことができます。

方法

 温湿度計⇔Modbus⇔Raspberry Pi⇔インターネット⇔Power BIリアルタイムダッシュボードという構成で試作してみたいと思います。RaspberryPIがIot Gatewayの役割を実施します。
温湿度計を準備して、Rasberry Piに接続できるusb⇔RS485のインターフェイスを準備します。
zu3.png
zu4.png
AzureのIoT Hubに接続してもいいのですが、ダッシュボードに若干のタイムラグが発生しリアルタイムという雰囲気にはならないので直接Power BIに接続することにします。温湿度計への電源はRaspberry Piから供給し、RS485のケーブルは少し高価なので、2本の配線をツイストして代用することにします。Modbus通信は単純なので自作しても問題ないですが、オープンソースのライブラリが存在しますので下記からダウンロードして利用しますhttp://libmodbus.org/releases/libmodbus-3.0.6.tar.gz

 libmodbus-3.0.6.tar.gzをダウンロードし、Raspberry Pi上で展開してConfigure/Makeします。特段問題なくMakeできると思います。
このlibmodbusを利用して温湿度計に接続します。C言語で作成します。実際は、インターネット上に公開されていたプログラムを若干修正しただけのものです。小さなプログラムです。

コード例

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <modbus.h>
#include <time.h>

#define SLAVE_ID 0x11
#define REGISTER_ADDRESS_H 0
#define REGISTER_ADDRESS_T 1
#define SERIAL_SPEED 9600
#define SERIAL_PARITY 'N'
#define SERIAL_DATABIT 8
#define SERIAL_STOPBIT 1

int main(int argc, char *argv[])
{
    time_t timer;
    modbus_t *ctx;
    int rc;
    int ret = EXIT_SUCCESS;
    uint16_t  tab_rp_registers_h,tab_rp_registers_t;
    if (argc < 2) {
        printf("Usage: %s <device>\n\n", argv[0]);
        return EXIT_SUCCESS;
    }
    ctx = modbus_new_rtu(argv[1], SERIAL_SPEED, SERIAL_PARITY,
                 SERIAL_DATABIT, SERIAL_STOPBIT);

    if (ctx == NULL) {
        fprintf(stderr, "Unable to allocate libmodbus context\n"
                "modbus error\n");
        return EXIT_FAILURE;
    }
    modbus_set_debug(ctx, FALSE);
    modbus_set_error_recovery(ctx,
                  MODBUS_ERROR_RECOVERY_LINK |
                  MODBUS_ERROR_RECOVERY_PROTOCOL );
    if (modbus_set_slave(ctx, SLAVE_ID) == -1) {
        fprintf(stderr, "set slave failed: %s\n"
                "modbus error\n",
                modbus_strerror(errno));
        modbus_free(ctx);
        return EXIT_FAILURE;
    }
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connection failed: %s\n"
                "modbus error\n",
                    modbus_strerror(errno));

        modbus_free(ctx);
        return EXIT_FAILURE;
    }
    sleep(1);
    time(&timer);

    rc = modbus_read_input_registers(ctx, REGISTER_ADDRESS_T,
                             1, &tab_rp_registers_t);


    if ( rc < 0 ) {
            fprintf(stderr, "faild: %s\n"
                    "modbus error\n",
                    modbus_strerror(errno));
            ret = EXIT_FAILURE;
     }

     rc = modbus_read_input_registers(ctx, REGISTER_ADDRESS_H,
                             1, &tab_rp_registers_h);

     if ( rc < 0 ) {
            fprintf(stderr, "faild: %s\n"
                    "modbus error\n",
                    modbus_strerror(errno));
            ret = EXIT_FAILURE;
      }

      printf("%d,%d\n", tab_rp_registers_t, tab_rp_registers_h);


    modbus_close(ctx);

    modbus_free(ctx);
   return ret;
}

さらにPower BIとの接続部分をPythonで作成します。PowerBI側の設定は以下を参照くださいURLはキー取得して確認ください。
https://powerbi.microsoft.com/ja-jp/documentation/powerbi-service-real-time-streaming/

REST_API_URL = "https://api.powerbi.com/beta/**************************"
try:
        input_line2=sys.stdin.readline()
        str1=input_line2.strip()
        str2=str1.split(',')
        temparature=float(str2[0])/10;
        humidity=float(str2[1])/10;
        print 'Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(temparature, humidity)
        now = datetime.strftime(datetime.now(), "%Y-%m-%dT%H:%M:%S%Z")
        data = '[{{ "Date": "{0}", "T": "{1:0.1f}", "H": "{2:0.1f}" }}]'.format(now, temparature, humidity)
        req = urllib2.Request(REST_API_URL, data)
        response = urllib2.urlopen(req)
        print("POST request to Power BI with data:{0}".format(data))
        print("Response: HTTP {0} {1}\n".format(response.getcode(), response.read()))
 time.sleep(1)

except urllib2.HTTPError as e:
        print("HTTP Error: {0} - {1}".format(e.code, e.reason))
except urllib2.URLError as e:
        print("URL Error: {0}".format(e.reason))
except Exception as e:
        print("General Exception: {0}".format(e))
19
23
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
19
23