- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2020-05-15T23:18:02+00:00","default:mizutu","mizutu")
[[私的AI研究会]] > AIbot Proj.1
* AI Robot Project [#f0f94bee]
#ref(画像一覧/20200408_142232_001s.jpg,right,around,25%,20200408_142232_001s.jpg)
#contents
#clear
** ハードウェア外観と設計図 [#z273e640]
#ref(画像一覧/20200303_080643_001s.jpg,left,around,25%,20200303_080643_001s.jpg)
#ref(画像一覧/20200303_080517_001s.jpg,left,around,25%,20200303_080517_001s.jpg)
#ref(画像一覧/20200310_160731_001s.jpg,left,around,25%,20200310_160731_001s.jpg)
#ref(画像一覧/20200326_132657_001s.jpg,left,around,25%,20200326_132657_001s.jpg)
#clear
#ref(画像一覧/raspi_box_s.jpg,left,around,54%,raspi_box_s.jpg)
#ref(画像一覧/raspi_case2s.jpg,left,around,30%,raspi_case2s.jpg)
#clear
** GPIO 関連回路図 [#j7d595bf]
#ref(画像一覧/20200308_085842_001s.jpg,left,around,25%,20200308_085842_001s.jpg)
#ref(画像一覧/20200319_081123_001s.jpg,left,around,12.5%,20200319_081123_001s.jpg)
#ref(画像一覧/20200407_164609_001s.jpg,left,around,25%,20200407_164609_001s.jpg)
#ref(画像一覧/20200407_164632_001s.jpg,left,around,25%,20200407_164632_001s.jpg)
#ref(画像一覧/20200504_161759_001m.jpg,left,around,12.5%,20200504_161759_001m.jpg)
#ref(画像一覧/20200504_161843_001m.jpg,left,around,12.5%,20200504_161843_001m.jpg)
#clear
#ref(画像一覧/fig6s.jpg,left,around,25%,fig6s.jpg)
#ref(画像一覧/fig9m.jpg,left,around,25%,fig9m.jpg)
● fig.6~
LED・スイッチ・スピーカー・オーディオアンプ~
→ [[ケースの作成・基板実装・配線>外装ハードウェア]]
~
● fig.9~
LED・DCモーター~
→ [[キャタピラーロボットの組み立て>ハードウェア2]]
#clear
** モーター駆動の基本プログラム [#sf49b649]
- 左右のDCモーター回路の基本動作と正面2個のLEDとタクトスイッチ組み込みのLEDを制御する。~
- GPI制御ライブラリ[[「WiringPi API」>WiringPi API]] をアクセスするクラス基本クラスとしてモータードライバDRV8835 とLED をアクセスするクラスを別々に作成。。~
- LEDの点滅制御をモーターの駆動時間との兼ね合いから基本0.5秒(0.25+0.25)で1回の点滅とする。~
''aibot.py''
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# aibot.py
# AI Robot Controle Library on Raspberry Pi4
#
# DC motor DRV8835 controle
# A-IN1 : GPIO 14 (BCM) B-IN1 : GPIO 15 (BCM)
# A-IN2 : 23 B-IN2 : 24
# LED-S : 16 LED-L : 17
# LED-R : 18
#
# Tact switch
# ext pullup : GPIO 20
#
import wiringpi as pi
import sys
import time
class MotorCtrl_base:
def __init__(self, a_phase, a_enbl, led):
pi.wiringPiSetupGpio()
if a_phase > 0:
self.a_phase = a_phase
pi.pinMode(self.a_phase, pi.OUTPUT)
if a_enbl > 0:
self.a_enbl = a_enbl
pi.pinMode(self.a_enbl, pi.OUTPUT)
if led > 0:
self.led = led
pi.pinMode(self.led, pi.OUTPUT)
def fwd(self): # 回転(正転)
pi.digitalWrite(self.a_phase, 1)
pi.digitalWrite(self.a_enbl, 1)
def back(self): # 回転(逆転)
pi.digitalWrite(self.a_phase, 0)
pi.digitalWrite(self.a_enbl, 1)
def stop(self): # 停止
pi.digitalWrite(self.a_phase, 0)
pi.digitalWrite(self.a_enbl, 0)
def led_on(self): # ON
pi.digitalWrite(self.led, 1)
def led_off(self): # OFF
pi.digitalWrite(self.led, 0)
def reset(self):
pi.digitalWrite(self.a_phase, 0)
pi.digitalWrite(self.b_phase, 0)
pi.digitalWrite(self.led, 0)
class MotorCtrl:
def __init__(self):
self.dcmotor1 = MotorCtrl_base(a_phase=14, a_enbl=23, led=0) # 右モーター
self.dcmotor2 = MotorCtrl_base(a_phase=15, a_enbl=24, led=0) # 左モーター
self.led_sw = MotorCtrl_base(a_phase=0, a_enbl=0, led=16) # switch LED
self.led_right = MotorCtrl_base(a_phase=0, a_enbl=0, led=18) # 右LED
self.led_left = MotorCtrl_base(a_phase=0, a_enbl=0, led=17) # 左LED
def stop(self):
self.dcmotor1.stop()
self.dcmotor2.stop()
self.led_off()
self.led_sw.led_off()
def forword(self):
self.dcmotor1.fwd()
self.dcmotor2.fwd()
def wait_forword(self, cn):
for i in range(cn):
self.fwd_led()
def fwd_led(self):
self.led_right.led_on()
self.led_left.led_on()
time.sleep(0.5)
def back(self):
self.dcmotor1.back()
self.dcmotor2.back()
def wait_back(self, cn):
for i in range(cn):
self.back_led()
def back_led(self):
self.led_right.led_on()
self.led_left.led_on()
time.sleep(0.25)
self.led_right.led_off()
self.led_left.led_off()
time.sleep(0.25)
def turn_left(self):
self.dcmotor1.fwd()
self.dcmotor2.back()
def wait_turn_left(self, cn):
for i in range(cn):
self.turn_left_led()
def turn_left_led(self):
self.led_left.led_on()
self.led_right.led_on()
time.sleep(0.25)
self.led_right.led_off()
time.sleep(0.25)
def turn_right(self):
self.dcmotor1.back()
self.dcmotor2.fwd()
def wait_turn_right(self, cn):
for i in range(cn):
self.turn_right_led()
def turn_right_led(self):
self.led_right.led_on()
self.led_left.led_on()
time.sleep(0.25)
self.led_left.led_off()
time.sleep(0.25)
def left(self):
self.dcmotor1.fwd()
self.dcmotor2.stop()
def wait_left(self, cn):
for i in range(cn):
self.left_led()
def left_led(self):
self.led_left.led_off()
self.led_right.led_on()
time.sleep(0.25)
self.led_right.led_off()
time.sleep(0.25)
def right(self):
self.dcmotor1.stop()
self.dcmotor2.fwd()
def wait_right(self, cn):
for i in range(cn):
self.right_led()
def right_led(self):
self.led_right.led_off()
self.led_left.led_on()
time.sleep(0.25)
self.led_left.led_off()
time.sleep(0.25)
def led_off(self):
self.led_left.led_off()
self.led_right.led_off()
if __name__ == '__main__':
motor = MotorCtrl()
motor.stop()
motor.led_off()
args = sys.argv
if 2 <= len(args):
duration = sys.argv[2]
if sys.argv[1] in {"stop"}:
motor.stop()
elif sys.argv[1] in {"forword"}:
motor.forword()
motor.wait_forword(int(duration))
motor.stop()
elif sys.argv[1] in {"back"}:
motor.back()
motor.wait_back(int(duration))
motor.stop()
elif sys.argv[1] in {"turn-left"}:
motor.turn_left()
motor.wait_turn_left(int(duration))
motor.stop()
elif sys.argv[1] in {"turn-right"}:
motor.turn_right()
motor.wait_turn_right(int(duration))
motor.stop()
elif sys.argv[1] in {"left"}:
motor.left()
motor.wait_left(int(duration))
motor.stop()
elif sys.argv[1] in {"right"}:
motor.right()
motor.wait_right(int(duration))
motor.stop()
else:
print("Need Argument;forword, right, left, turn-right, turn-left, back or stop")
else:
print("Command Format: aibot [forword|right|left|turn-right|turn-left|back|stop] [count(0.5sec)]")
- コマンドラインからの起動時は引数により各駆動動作を実行する。~
''python aibot.py [forword|right|left|turn-right|turn-left|back|stop] [count(0.5sec)]''~
-- 前進:
$ python aibot.py forword 6
-- 後退:
$ python aibot.py back 6
** 端末ターミナルからリモートコントロール [#jf4cd9bc]
#ref(画像一覧/key_setm.jpg,right,around,25%,key_setm.jpg)
- 端末ターミナルから起動しキーボード入力でキャタピラーロボットをリモート制御する。
- キーを1度押すと次のキー入力まで現在の動作を継続する。
- なお、このソフトウェアは原理上端末ターミナルからIDEデバッグはできない。
-- 前進 : 'i','A'
-- 後退 : 'm','B'
-- 左 : 'j','C'
-- 右 : 'l','D'
-- 左に回転: 'u','1'
-- 右に回転: 'o','2'
-- 停止 : 'space','s','k'
-- 終了 : 'q'
#clear
''aibotrm.py''
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# aibotrm.py <<このソースコードは IDE デバッグはできない>>
# AI Robot Remort Program on Raspberry Pi4
#
# DC motor DRV8835 controle
# A-IN1 : GPIO 14 (BCM) B-IN1 : GPIO 15 (BCM)
# A-IN2 : 23 B-IN2 : 24
# LED-S : 16 LED-L : 17
# LED-R : 18
#
# Tact switch
# ext pullup : GPIO 20
#
import wiringpi as pi
from kbhit import *
import aibot
import sys
if __name__ == '__main__':
atexit.register(set_normal_term)
set_curses_term()
motor = aibot.MotorCtrl()
motor.stop()
motor.led_off()
ledmod = 0
kb = ' '
print("AIbot Control Ok! 'i,m,j,l,k,,u,o' or 'q'")
while 1:
# key push check & Motor control
if kbhit():
kb = getch()
if kb == 'q':
print(" ## Break ##")
motor.stop()
motor.led_off()
ledmod = 9
elif kb == 'A' or kb == 'i':
print(" ** Forword **")
motor.forword()
ledmod = 1
elif kb == 'B' or kb == 'm':
print(" ** Bsck **")
motor.back()
ledmod = 2
elif kb == 'C' or kb == 'j':
print(" ** Left **")
motor.left()
ledmod = 3
elif kb == 'D' or kb == 'l':
print(" ** Right **")
motor.right()
ledmod = 4
elif kb == '2' or kb == 'o':
print(" ** Right turn **")
motor.turn_right()
ledmod = 5
elif kb == '1' or kb == 'u':
print(" ** Left turn **")
motor.turn_left()
ledmod = 6
elif kb == 's' or kb == 'k' or kb == ' ':
print(" !! Stop !!")
motor.stop()
ledmod = 0
else:
print("AiBot Standby OK !!!!")
# LED mode set & wait 0.5sec
if ledmod == 0:
motor.led_off()
elif ledmod == 1:
motor.fwd_led()
elif ledmod == 2:
motor.back_led()
elif ledmod == 3:
motor.left_led()
elif ledmod == 4:
motor.right_led()
elif ledmod == 5:
motor.turn_right_led()
elif ledmod == 6:
motor.turn_left_led()
elif ledmod == 9:
break
else:
pass
ledmod = 0
print("Program Finished !!!")
** 自立走行の準備 [#m3601fab]
*** タクトスイッチの入力待ちプログラム [#dcd2e42a]
- 付属のタクトスイッチの入力待ちで停止し、LEDを点滅する。
- スイッチが押されたらLED を消してプログラム終了。
''wait.py''
# -*- cording: utf-8 -*-
import time
import RPi.GPIO as GPIO
LED = 16
BUTTON = 20
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED, GPIO.OUT)
GPIO.setup(BUTTON, GPIO.IN)
GPIO.add_event_detect(BUTTON, GPIO.FALLING)
while True:
if GPIO.event_detected(BUTTON):
print ("Raspberry Pi Switch ON !!")
break
else:
GPIO.output(LED, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(LED, GPIO.LOW)
time.sleep(0.5)
GPIO.cleanup()
print ("Start OK !!!")
*** 自動起動のためのシェルスクリプト [#o4eaef1e]
-「Raspberry Pi」の電源ON で起動し、タクトスイッチの入力待ちとなり、スイッチが押されるとデモアクションを実行し、タクトスイッチの入力待ちに戻る。
- デモアクションは基本ライブラリのコンソール入力機能を利用し、一通りの動作を実行して止まる。
-- 3秒間前進(左右LED点灯)
-- 3秒間後退(左右LED点滅)
-- 2秒間左前進(左LED点滅、右LED点灯)
-- 2秒間右前進(右LED点灯、左LED点滅)
-- 1.5秒間左回転(右LED点灯、左LED消灯)
-- 1.5秒間右回転(右LED消灯、左LED点灯)
''aibot_boot.sh''
#!/bin/bash
cd ~/Programs/aibot
python wait.py
echo "Motor Test Program Start..."
python aibot.py forword 6
python aibot.py back 6
python aibot.py left 4
python aibot.py right 4
python aibot.py turn-left 3
python aibot.py turn-right 3
python motor3.py stop 1
echo "Aibot Start..."
- 実行権限を付加する。
$ chmod u+x aibot_boot,sh
- 実行してみる。
$ ./aibot_boot.sh
*** 自動起動の設定 [#b39d8fe0]
1. 自動起動ファイルを作成する。~
''aibot_boot.service''
Description=Aibot boot
[Service]
ExecStart=/bin/bash /home/pi/Programs/aibot/aibot_boot.sh
WorkingDirectory=/home/pi/Programs/aibot/
Restart=always
User=pi
[Install]
WantedBy=multi-user.target
2. 自動起動用のサービスファイルをコピーする。~
$ sudo cp aibot_boot.service /etc/systemd/system/
3. systemdにユニットファイルを追加・更新したことを通知する~
$ sudo systemctl daemon-reload
4. 自動起動を登録する。~
$ sudo systemctl enable aibot_boot.service
$ sudo systemctl start aibot_boot.service
5. 登録を確認する。~
$ sudo systemctl status aibot_boot.service
active となっていたら登録完了。
*** 自動起動したサービスの停止 [#af148f78]
-「Raspberry Pi」起動後、自動実行ファイルはタクトスイッチの入力待ちで実行中のまま。
- 停止するには
$ sudo systemctl stop aibot_boot.service
- 停止を確認する。~
$ sudo systemctl status aibot_boot.service
*** 自動起動したサービスの削除 [#na3b64ac]
- 自動起動を削除するには
$ sudo systemctl stop aibot_boot.service
$ sudo systemctl disable aibot_boot.service
$ sudo systemctl status aibot_boot.service
** cronを使って起動時にプログラムを走らせる [#j14d5fc2]
- crontabを修正。(初回のみエディタの選択を要求される)
$ crontab -e
no crontab for pi - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano <---- easiest
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
4. /bin/ed
Choose 1-4 [1]: 2
下記を追記する。
@reboot /home/pi/Programs/aibot/aibot_boot.sh
起動時にaibot_boot.sh が実行される。
** Pythonでリアルタイムにキーボード入力を処理する方法 [#zecc8b23]
> Pythonではreadcharというライブラリを使う。
- インストール
$ pip install readchar
- サンプルプログラム
#!/usr/bin/env python
import readchar
import sys
while 1:
kb = readchar.readchar()
# sys.stdout.write(kb)
print(ord(kb))
if kb == 'q':
print("")
break
- IDE環境では実行できない
Python error: (25, 'Inappropriate ioctl for device')
* 参考資料 [#c99761a3]
- [[Python: input from Keyboard without Enter>+http://web.sfc.keio.ac.jp/~yama/nos/archives/comp/soft/5326]]
-[[pythonでコンソールから1文字入力>+https://emotionexplorer.blog.fc2.com/blog-entry-126.html]]
- [[python3にもkbhit()とgetch()が欲しい>+https://westgate-lab.hatenablog.com/entry/2019/12/28/123451]]
- [[【Python】文字列と数値(asciiコード)の変換まとめ>+https://qiita.com/ell/items/6eb48e934a147898d823]]
- [[Python Snippets>+https://python.civic-apps.com/char-ord/]]
- [[Pythonでコマンドライン引数を受け取る>+https://qiita.com/taashi/items/07bf75201a074e208ae5]]
- [[ASCIIコード表>+http://www9.plala.or.jp/sgwr-t/c_sub/ascii.html]]
- [[Raspberry Piでプログラムを自動起動する5種類の方法を比較・解説>+https://qiita.com/karaage0703/items/ed18f318a1775b28eab4]]
#br