はじめに
KONDOのサーボモータをRaspberry Pi のpythonで制御しています。そのときに行った作業の一部を記録したいと思います。
ドライバのインストール
Raspberry Pi からRCB4をUSB-UART経由で使うにはRaspberry Pi にドライバをインストールする必要があります。ほぼ、以下のページに書いてあることに従うことでドライバがインストールできたのですが、ちょっと躓いたところがありました。
Raspberry Pi と Rcb4(mini)との接続
Raspberry Pi と Rcb4(mini)の間は Dual USBアダプターHSを介して接続します。このとき、Dual USBアダプタのスイッチを「シリアルモード」にする必要があります。
ベンダIDとプロダクトIDのnew_id への書き込み
上のページの説明の中に、
$ sudo su
modprobe ftdi-sio
echo 165C pppp > /sys/bus/usb-serial/drivers/ftdi_sio/new_id
exit
を実行するところがあります。まず、ppppのところですが、
sudo dmesg|grep usb
を実行したところ、
[ 6.650581] usb 1-1: New USB device found, idVendor=165c, idProduct=0008, bcdDevice=10.00
という行があるので、pppp(idProduct)は、0008であることがわかります。
ところが、
$ sudo su
modprobe ftdi-sio
echo 165C pppp > /sys/bus/usb-serial/drivers/ftdi_sio/new_id
exit
を実行したところ、最後のexitの影響か、terminalが終了してしまいました。
今度は、
sudo modprobe ftdi-sio
sudo echo 165C 0008 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id
のように、1行ずつ順番にsudo をつけて実行したのですが、2番目のecho ... のところで
-bash: /sys/bus/usb-serial/drivers/ftdi_sio/new_id: Permission denied
と、怒られてしまいました。 sudo をつけてもダメなのですね。
なお、'sudo modprobe ftdi-sio'を実行した後でないと、
'/sys/bus/usb-serial/drivers/ftdi_sio/'は存在しないみたいです。
それで、
sudo emacs /sys/bus/usb-serial/drivers/ftdi_sio/new_id
を実行し、emacsでnew_id の中身を、'165C 0008' にしてみました。
この後、sudo dmesg|grep usb を実行したところ、本来、
usb 1-1.2: FTDI USB Serial Device converter now attached to ttyUSB0
のように、tty*** が表示されるはずの行が見つからず、それっぽい行でも
[ 711.615431] usbserial: USB Serial support registered for FTDI USB Serial Device
となっていて、何かおかしいです。
それで、'/sys/bus/usb-serial/drivers/ftdi_sio/new_id'のpermission が、644になっているところを、
sudo chmod 666 /sys/bus/usb-serial/drivers/ftdi_sio/new_id
を実行し、一旦、666にして、
sudo echo 165C 0008 > /sys/bus/usb-seri
al/drivers/ftdi_sio/new_id
を実行し、cat コマンドで中身が書き込まれていることを確認し、
cat /sys/bus/usb-serial/drivers/ftdi_sio/new_id
165c 0008
new_idのpermissionを
sudo chmod 644 /sys/bus/usb-serial/driv
ers/ftdi_sio/new_id
で元に戻し、
ls /dev/tty*
を実行したところ、
/dev/tty /dev/tty19 /dev/tty3 /dev/tty40 /dev/tty51 /dev/tty62
/dev/tty0 /dev/tty2 /dev/tty30 /dev/tty41 /dev/tty52 /dev/tty63
/dev/tty1 /dev/tty20 /dev/tty31 /dev/tty42 /dev/tty53 /dev/tty7
/dev/tty10 /dev/tty21 /dev/tty32 /dev/tty43 /dev/tty54 /dev/tty8
/dev/tty11 /dev/tty22 /dev/tty33 /dev/tty44 /dev/tty55 /dev/tty9
/dev/tty12 /dev/tty23 /dev/tty34 /dev/tty45 /dev/tty56 /dev/ttyprintk
/dev/tty13 /dev/tty24 /dev/tty35 /dev/tty46 /dev/tty57 /dev/ttyS0
/dev/tty14 /dev/tty25 /dev/tty36 /dev/tty47 /dev/tty58 /dev/ttyUSB0
/dev/tty15 /dev/tty26 /dev/tty37 /dev/tty48 /dev/tty59
/dev/tty16 /dev/tty27 /dev/tty38 /dev/tty49 /dev/tty6
/dev/tty17 /dev/tty28 /dev/tty39 /dev/tty5 /dev/tty60
/dev/tty18 /dev/tty29 /dev/tty4 /dev/tty50 /dev/tty61
のようになり、やっと、ttyUSB0が出てきました。sudo dmesg|grep usb を実行したところ
[ 1788.887875] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0
のように、こちらでもちゃんと ttyUSB0が出てきました。
でも。
/dev/ttyUSB0 は再起動すると消えてしまうようです。サーボモータを使うプログラムの起動時または、再起動の直後に、「ベンダIDとプロダクトIDのnew_id への書き込み」を行う必要があるみたいです。
RCBLib_for_Python_V100B の修正
KONDO科学さんが、サーボモータをPythonで制御するためのライブラリ RCB4Lib_for_Python を公開されています。
このライブラリを解凍(unzip)した場所に sample というディレクトリがあり、その中に、sample プログラムが置いてあるのですが、そ中の、Rcb4AckTest.py を実行しようとしても、以下のようなエラーが発生しました。
(testpip) pi@rpi-202603261445:~/python/RCB4Lib_for_Python_V100B/sample $ python3 Rcb4AckTest.py
Traceback (most recent call last):
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/Rcb4AckTest.py", line 16, in <module>
if rcb4.checkAcknowledge() == True:
~~~~~~~~~~~~~~~~~~~~~^^
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 452, in checkAcknowledge
rxbuf = self.synchronize(txbuf,reSize)
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 341, in synchronize
self.com.flushInput()#buff clr
^^^^^^^^^^^^^^^^^^^
AttributeError: 'int' object has no attribute 'flushInput'
どうも、Object self.com がint型になってしまっていて、 flushInput というオブジェクトがないということのようです。このエラーが発生した Rdb4BaseLib.py の中身を探ることにします。
Rcb4BaseLib.py の com
self.com は、きっとUARTのSerialインターフェースのオブジェクトであろうと推定しました。それであるなら、open(...) というような関数があるはずです。それをまず探してみます。
370行目付近に、
def open(self,comName,bundrate,timOut):
if self.com == 0:
...
が見つかりました。この部分を
def open(self,comName,bundrate,timOut):
if self.com == None:
...
に修正しました。他にself.comがないか検索を続けると、400行目付近に
def close(self):
try:
self.com.close()
self.com = 0
return 0
というのがあったので、これを、
def close(self):
try:
self.com.close()
self.com = None
return 0
に修正します。
ここでもう一度、Rcb4AckTest.py を実行してみましたが、同じエラーが発生します。
その直前まで実行できているか、確認するため、339行目にコメントアウトされていた、
#print('sendData-->',sendbuf)
のコメントを外して実行してみたところ、
(testpip) pi@rpi-202603261445:~/python/RCB4Lib_for_Python_V100B/sample $ python3 Rcb4AckTest.py
sendData--> [4, 254, 6, 8]
Traceback (most recent call last):
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/Rcb4AckTest.py", line 16, in <module>
if rcb4.checkAcknowledge() == True:
~~~~~~~~~~~~~~~~~~~~~^^
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 452, in checkAcknowledge
rxbuf = self.synchronize(txbuf,reSize)
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 341, in synchronize
self.com.flushInput()#buff clr
^^^^^^^^^^^^^^^^^^^
AttributeError: 'int' object has no attribute 'flushInput'
となって、コメントをはずしたprint文は実行されていることがわかります。
今度は com だけで検索してみると、236行目付近に、
## @brief COMのデバイス名
com = 0
というところがありました。これを
## @brief COMのデバイス名
com = None
に直しました。
この状態で、Rcb4AckTest.py を実行したところ、今度は、
(testpip) pi@rpi-202603261445:~/python/RCB4Lib_for_Python_V100B/sample $ python3 Rcb4AckTest.py
sendData--> [4, 254, 6, 8]
Traceback (most recent call last):
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/Rcb4AckTest.py", line 16, in <module>
if rcb4.checkAcknowledge() == True:
~~~~~~~~~~~~~~~~~~~~~^^
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 457, in checkAcknowledge
rxbuf = self.synchronize(txbuf,reSize)
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 342, in synchronize
self.com.flushInput()#buff clr
^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'flushInput'
となりました。これはきっと、openを失敗しているのだろう、ということになります。
そこで、370行目付近の 'def open('のすぐ下にprint文を入れたり、あちこちに print('open failed?')を入れたりして、
def open(self,comName,bundrate,timOut):
print('open comName='+comName+' bundrate='+str(bundrate)+' timOut='+str\
(timOut))
#if self.com == 0:
if self.com == None:
try:
self.com = serial.Serial(comName,bundrate,parity='E',stopbits =\
1,timeout=timOut)
print('self.com='+str(self.com))
self.com.flushInput()#
if self.checkAcknowledge() == True:
#ACKが成功した場合Configデータを取得
confData = self.getConfig()
#confDataは0xFFFFの場合はエラー
if(confData == 0xFFFF):
return False
else:
self.__configData = confData
return True
else:
return False
except:
print('open failed?')
return False
else:
print('open false')
return False
のように修正し、実行してみました。
今度は、
(testpip) pi@rpi-202603261445:~/python/RCB4Lib_for_Python_V100B/sample $ python3 Rcb4AckTest.py
open comName=/dev/ttyAMA0 bundrate=115200 timOut=1.3
open failed?
sendData--> [4, 254, 6, 8]
Traceback (most recent call last):
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/Rcb4AckTest.py", line 16, in <module>
if rcb4.checkAcknowledge() == True:
~~~~~~~~~~~~~~~~~~~~~^^
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 459, in checkAcknowledge
rxbuf = self.synchronize(txbuf,reSize)
File "/home/pi/python/RCB4Lib_for_Python_V100B/sample/../Rcb4Lib/Rcb4BaseLib.py", line 342, in synchronize
self.com.flushInput()#buff clr
^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'flushInput'
となりました。
Rcb4のドライバをインストールしたとき、Rcb4と繋がるUARTは、'/dev/ttyUSB0'だったはずです。
そこで、今度は、動かそうとしているsampleのRcb4AckTest.pyの12行目付近を
#ポートをオープン
#rcb4.open('/dev/ttyAMA0',115200,1.3) #(portName,bundrate,timeout(s))
rcb4.open('/dev/ttyUSB0',115200,1.3)
のように修正しました。
これを実行すると、
(testpip) pi@rpi-202603261445:~/python/RCB4Lib_for_Python_V100B/sample $ python3 Rcb4AckTest.py
open comName=/dev/ttyUSB0 bundrate=115200 timOut=1.3
self.com=Serial<id=0xb67307a8, open=True>(port='/dev/ttyUSB0', baudrate=115200, bytesize=8, parity='E', stopbits=1, timeout=1.3, xonxoff=False, rtscts=False, dsrdtr=False)
sendData--> [4, 254, 6, 8]
sendData--> [10, 0, 32, 0, 0, 0, 0, 0, 2, 44]
sendData--> [4, 254, 6, 8]
checkAcknowledge OK
Version --> 220
となり、上手く行きました。