Modbus通信でオリエンタルモーターROSパッケージをPythonで動かす


はじめに

株式会社Ristのロボットチームの原山です。
Ristは画像認識AIの会社ですが、その他にも色々とやっております。

今回は、社内のプロジェクトにおいてAGVに昇降機を付けて動かしています。
昇降機は、オリエンタルモーター株式会社のEASシリーズEAS6RY-E085-ARMK-2Modubus-RS485(COM-1PD)を使ってPythonで動かします。

環境

モーターについて

EASシリーズEAS6RY-E085-ARMK-2とその付属品の組み立てや設定に関しては、マニュアルがありますが、メカ担当におまかせしているのでよくわかりません。私はPCとModbus(RS-485)を繋ぐだけで通信することができました。

Modbus(RS-485)について

Modbus(モドバス)とは

Modbus(モドバス) とは、米Modicon社が自社PLC用に1979年に開発した通信プロトコルで、PLCのみならず電子機器間においてもデータ受け渡しの目的で使用されていて、一般的にModbusというとRS-232C、RS-422、RS-485通信のことを言うようです。

  • 通信モードにはいくつかあって、今回のモーターはRTU(Remote Terminal Unit)モードで動かします。 USB接続なので下記必要です。
$ sudo su
# modprobe ftdi_sio vendor=0x06ce product=0x8331
# echo 06ce 8331 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id
# exit

PCを再起動等すると毎回必要です。うまいことやってください。

ドキュメント等

  • マニュアル

  • 動作環境

    • 対象OS:Ubuntu16.04(Linux) -> Ubuntu18.04(Linux)でも動作確認できました。
    • ROSディストリビューション:Kinetic Kame -> Melodic Moreniaでも動作確認できました。

om_modbus_master

  • こちらから"om_modbus_master"というROSパッケージを入手してください。

  • om_modbus_masterをビルドしてください。

ROSノードを起動

$ source devel/setup.bash # ビルド直後なら必要
$ roslaunch om_modbus_master om_modbusRTU.launch com:="/dev/ttyUSB0" topicID:=1 baudrate:=115200 updateRate:=10 firstGen:="1,2," secondGen:="3,4,"
  • connectedと表示されれば問題ありません。

ROSメッセージ

プロジェクト直下のsampleフォルダにいくつかのサンプルコードがありますが、実際にモーターを動かすことはできませんでした。

  • モーターへ運転データは、om_modbus_master/msg/om_query.msgを使用します。

また今回は、ダイレクト運転データモードかつ絶対位置決め方式です。メッセージの中身が変わります。
専用ソフトを使って、ソフトリミット設定済みです。

om_query.msg
メンバ名 用途 備考
slave_id int8 号機番号 モーターID
func_code int8 ファンクションコード (0:read, 1:write, 2:read&write)
write_addr int32 書き込みアドレス 88ダイレクトデータ運転アドレス
read_addr int32 読み込みアドレス 88ダイレクトデータ運転アドレス
write_num int8 書き込みのバイト数 8
read_num int8 読み込みのバイト数 8
data int32[32] 下記参照

data変数の内容

メンバ名 用途
data[0] 0 運転データナンバー
data[1] 1 方式は絶対位置決め方式 の番号
data[2] MIN~MAX ソフトリミットで設定した値がMINMAXの値を指定できる
data[3] 2000 速度Hz
data[4] 1500 起動変化レート kHz/s
data[5] 1500 指定レートkHz/s
data[6] 100   電流
data[7] 1     反映トリガ 1:全データ反映
data[8] 7176 エラー(固定)

サンプルを改良して動かす

Python

#!/usr/bin/python
# -*- coding: utf-8 -*-

import rospy
import time
from om_modbus_master.msg import om_query
from om_modbus_master.msg import om_response
from om_modbus_master.msg import om_state

# グローバル変数
gState_driver = 0
gMotor_spd = 0

# レスポンス購読
def resCallback(res):
  global gMotor_spd
  if(res.slave_id == 1):
    gMotor_spd = res.data[0]

# ステータス購読
def stateCallback(res):
  global gState_driver
  gState_driver = res.state_driver

# 通信が終わるまで待機
def wait():
  global gState_driver
  time.sleep(0.01)
  while(gState_driver == 1):
    pass

def main():  
  rospy.init_node("sample1", anonymous=True)
  pub = rospy.Publisher("om_query1", om_query, queue_size=1)
  rospy.Subscriber("om_response1", om_response, resCallback)
  rospy.Subscriber("om_state1", om_state, stateCallback)
  msg = om_query()
  time.sleep(1)

  # 書き込み(回転速度No.2)
  msg.slave_id = 1
  msg.func_code = 1
  msg.write_addr = 88
  msg.write_num = 8
  msg.data[0] = 0
  msg.data[1] = 1
  msg.data[2] = 2000
  msg.data[3] = 2000
  msg.data[4] = 1500
  msg.data[5] = 1500
  msg.data[6] = 100
  msg.data[7] = 1
  msg.data[8] = 7176
  pub.publish(msg)
  wait()

  rospy.spin()

if __name__ == '__main__':
    main()

おわりに

わかっていない部分も多いので間違っているところがあるかもしれないです。

参考

Modbus(RS-485)について
https://www.softech.co.jp/mm_110302_plc.htm
https://www.lineeye.co.jp/html/term_modbus.html

オリエンタルモーターのROS
https://www.orientalmotor.co.jp/tech/connect/