#author("2020-04-19T01:18:49+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) #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