質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

2235閲覧

センサー反応後にモーターを停止、数秒後にセンサーを一旦切ってモーターを再稼働させたいです

ryu-12

総合スコア2

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/12/07 14:30

編集2021/12/09 07:40

実現したいこと

プログラミング初心者です。
前回作成した、センサーでモーターを制御するというプログラムの延長です。前回のプログラムの内容を簡単に説明すると、
センサーに反応がない場合はモーターを稼働、反応があった場合はモーターを停止、反応が無くなった場合はモーターを再稼働させるといったものです。
今回は、「反応があって停止した時点から数秒後にセンサーを切って、モーターを再稼働させる」ということを目標にしています。「GPIO.output(〇, 〇)」とは使い勝手が違うので苦戦しています。どなたか解決策を教えていただけないでしょうか。
もし、センサーを切らずに停止後、再稼働させる方法があればそちらも教えていただきたいです。よろしくお願いします。下記は現在のプログラムです。

Python3

1import RPi.GPIO as GPIO 2import time 3import sys 4import datetime 5GPIO.setwarnings(False) 6GPIO.setmode(GPIO.BOARD) 7 8motor1speed=15 9motor1Direction=21 10SENSOR_PORT = 24 11LED = 35 12 13 14GPIO.setup(19,GPIO.OUT) 15GPIO.setup(motor1speed,GPIO.OUT) 16GPIO.setup(motor1Direction,GPIO.OUT) 17GPIO.setup(SENSOR_PORT, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 18GPIO.setup(LED, GPIO.OUT) 19 20#モーター制御 21def motorstart(): 22 pwm = GPIO.PWM(19, 100) 23 pwm.start(0) 24 GPIO.output(motor1Direction, 0) 25 pwm.ChangeDutyCycle(40) 26 pwmR = GPIO.PWM(motor1speed, 100) 27 pwmR.start(0) 28 GPIO.output(motor1speed, 1) 29 pwmR.ChangeDutyCycle(23) 30 31motorstart() 32 33while True: 34 try: 35 if(GPIO.input(SENSOR_PORT) == 0): 36 motorstart() 37 GPIO.output(LED, GPIO.LOW) 38 39 else: 40 GPIO.output(LED, GPIO.HIGH) 41 42 except KeyboardInterrupt: 43 GPIO.cleanup() 44 sys.exit()

追記

回答者様から頂いたプログラムを付け加えてみました。問題視していた「センサーの状態を無視する」という点は解決しましたが、停止から3秒後のモーターの再始動がうまくいかず、再始動時に本来なら回転させたいところですが一瞬だけ(1~5°程度)動いて、その後は停止した状態になってしまいます。
間違っている部分があれば、ご指摘よろしくお願いします。

Python3

1import RPi.GPIO as GPIO 2import time 3import sys 4import datetime 5GPIO.setwarnings(False) 6GPIO.setmode(GPIO.BOARD) 7 8motor1speed=15 9motor1Direction=21 10SENSOR_PORT = 24 11LED = 35 12 13 14GPIO.setup(19,GPIO.OUT) 15GPIO.setup(motor1speed,GPIO.OUT) 16GPIO.setup(motor1Direction,GPIO.OUT) 17GPIO.setup(SENSOR_PORT, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 18GPIO.setup(LED, GPIO.OUT) 19 20#モーター制御 21def motorstart(): 22 pwm = GPIO.PWM(19, 100) 23 pwm.start(0) 24 GPIO.output(motor1Direction, 0) 25 pwm.ChangeDutyCycle(40) 26 pwmR = GPIO.PWM(motor1speed, 100) 27 pwmR.start(0) 28 GPIO.output(motor1speed, 1) 29 pwmR.ChangeDutyCycle(23) 30 31def motorstop(): 32 GPIO.output(motor1speed, 0) 33 GPIO.output(motor1Direction, 0) 34 35motorstart() 36 37restart_flag = False 38while True: 39 try: 40 if restart_flag: 41 continue 42 if(GPIO.input(SENSOR_PORT) == 0): 43 motorstart() 44 GPIO.output(LED, GPIO.LOW) 45 46 else: 47 GPIO.output(LED, GPIO.HIGH) 48 motorstop() 49 time.sleep(3) 50 motorstart() 51 restart_flag = True 52 53 except KeyboardInterrupt: 54 GPIO.cleanup() 55 sys.exit()

補足情報(FW/ツールのバージョンなど)

Python 3.7.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2021/12/07 22:55

あなたにとっては「前回」で自明なのでしょうが、普通の回答者のためには「前回」のURL https://teratail.com/questions/372271 を示しておくのが親切というものかと思います。
thkana

2021/12/07 22:55

> 数秒後にセンサーを切って センサーを切る、とはどうなることですか?
ryu-12

2021/12/08 01:02

thkana様 前回に引き続き、ご指摘ありがとうございます。 >数秒後にセンサーを切って ここでの「センサーを切る」とは、「SENSOR_PORT」に来る入力信号を一旦止めたいという意味です。現状、物体を検知している間は当然ですが、永遠に入力信号が来てしまうのでモーターが止まったままになってしまっています。 一度、「GPIO.output(○○, 0)」のような原理でセンサーからの入力信号を止めようと考えましたが、うまくいきませんでした。どのようにプログラムを作成すれば良いか、教えていただけないでしょうか。
irognodyci

2021/12/08 01:23

一度検知してモーターを止めた後、センサーが検知していようがいまいが関係なくモーターを再始動させるんですよね?再始動させた後はセンサーを使わずに回し続けるという認識で合っていますか?
ryu-12

2021/12/08 01:45

irognodyci様 はい。その認識で会っています。欲を言えば、 「センサーが物体検知でモーターを停止→停止から数秒後に検知していようがいまいが関係なくモーターを再始動」この動作の流れを繰り返し行いたいのですが、できるでしょうか?
irognodyci

2021/12/08 05:32 編集

モータを再始動したタイミングで、すでに物体検知していた場合はどうするんですか?センサーの状態によらず(=センサーを無視して)再始動させるのはいいですが、繰り返したいとなると再びセンサーを有効にしないといけませんが、センサーを再び有効にするトリガーは何になるのでしょうか?
ryu-12

2021/12/08 07:36

irognodyci様 >モータを再始動したタイミングで、すでに物体検知していた場合はどうするんですか? これに関しては私も問題視していました。現在のプログラムの、 else: GPIO.output(LED, GPIO.HIGH) の部分に、 else: GPIO.output(LED, GPIO.HIGH) time.sleep(3) motorstart() というように付け加えて実験してみましたが、やはりセンサーが物体検知している状態なのでモーターの再始動が強制的に止められていました。センサーを無視するプログラムがわかればできそうなのですが… >センサーを再び有効にするトリガー これに関してはまだ思いついてないので、繰り返しの部分は後々考えたいと思います。現在はセンサーを無視するプログラムに専念しようと思います。どうかご協力お願いいたします。
thkana

2021/12/08 11:58

センサーをソフト的に「切る」手段は(これまであなたが提示した範囲では)用意されていません。 しかし、センサーを読みに行かなければ、あるいは読み取った結果をモーターの駆動条件に組み入れなければセンサーは「無視」されます。 「どのように動いてほしいのか」がちゃんと練れていないからそういう話になるのだと思います。 ・センサーが発報中はモーターが停止 ・モーターが停止してからN秒後にモーターの回転を開始 だけが条件では、当然センサーが発報していればN秒後に回り始めたモーターは即時停止します(事実上回らない)。 例えば、 ・一度センサーが発報したら以降はセンサーの状態は無視 という条件が付け加えられたなら、モーターはN秒後に再び回りだして二度と(電源を切るまで)止まらない、という動作をすることになります。 これはあくまで例で、これがあなたの希望する動作なのかは私には知る由もありません。 あなたの起こって欲しい動作をちゃんと記述してください。
ryu-12

2021/12/09 08:03

thkana様 ご指摘ありがとうございます。 現在、私が起こってほしい動作は、 1.モーターが始動、対象の物体を運搬 2.センサーが物体を検知、モーターを3秒間停止 3.3秒後センサーの状態を無視してモーターが再始動、物体の運搬を再開 4.物体の運搬後センサーの状態を無視するという動作をリセット、以後1,2,3の繰り返し です。現在は「3」の部分で問題が起きているので「4」に関しては後々考えていきます。
thkana

2021/12/09 14:48

4で、いつ(あるいはどのような条件で)センサーの無視をやめるのか、ということを決めないと 3での「無視」を成立させられないので今の事態になっている、といえるでしょう。 先送りしないで決めてください。暫定でもいいですれど、少なくとも「言われた通り」にしたらまともに動くだけの指示が必要です。 コンピュータは「この通りにやれ」と言われたことをその通りにやるだけです。「良きにはからえ」は通用しないので、言われた「この通り」の手順が破綻していれば当然コンピュータの動作結果も破綻します。コンピュータに何をやらせるか、ちゃんと考えてください。
ozwk

2021/12/10 02:23 編集

(すでにコメントで解決済みでした)
ryu-12

2021/12/10 03:15

thkana様 3での「無視」という点に関しては他の回答者様の回答をもとに解決させることができました。 あとはセンサーの無視をやめさせるための条件を作りたいという状態です。条件として、 「GPIO.output(○○, GPIO.HIGH)」のようなものでも条件として扱うことは可能でしょうか? できるのであれば、 「モーターを再始動」→「再始動から数秒後に(GPIO.○○をHIGHもしくはLOW)[条件]」→ 「センサーを再び有効化」。以後繰り返しにしようと考えています。
ryu-12

2021/12/10 05:39

ozwk様 閲覧していただき、ありがとうございます。 まだいくつかやるべき要素が残っているので、もし何かお気づきになられた点や、間違いなどがあった場合はご指摘いただけると幸いです。
guest

回答3

0

センサーを「切る」とか「始動」とか「有効化」とかいう、実際にはない動作を考えるのは止めましょう。

1.モーターが始動、対象の物体を運搬
2.センサーが物体を検知、モーターを3秒間停止
3.3秒後センサーの状態を無視してモーターが再始動、物体の運搬を再開
4.モーターを再始動。再始動からN秒間はセンサー状態を無視

[擬似コード] 停止履歴フラグをクリア モーター回転フラグをセット 無限ループ (現在時刻-停止時刻)が3秒以上? ならば モーター回転フラグをセット 停止履歴フラグがクリアされている? または (現在時刻-停止時刻)が3+N秒以上? ならば センサー値を得る センサー反応あり? 現在時刻を取得、停止時刻に保存 停止履歴フラグをセット モーター回転フラグをリセット モーター回転フラグがセットされていればモーター回転、そうでなければモーター停止

とか。

[擬似コード] カウントダウンタイマーに0を代入 モーター回転フラグをセット 無限ループ カウントダウンタイマーが0でない? カウントダウンタイマーがN*100以下? モーター回転フラグをセット そうでなければ #カウントダウンタイマーがN*100を超える モーター回転フラグをリセット カウントダウンタイマーを1減少 さもなければ #カウントダウンタイマーが0 センサー値を得る センサー反応あり? カウントダウンタイマーに(3+N)*100を代入 モーター回転フラグがセットされていればモーター回転、そうでなければモーター停止 0.01秒スリープ

とか。


一番「普通」かも知れない状態マシンをやっていなかったか

[擬似コード] 状態変数に'通常回転'を代入 無限ループ 状態変数が'通常回転'? #センサーを見る モーター回転フラグをセット センサー値を得る センサー反応有り? カウントダウンタイマーに300を代入 状態変数に'停止'を代入 else 状態変数が'停止'? #時間を測る モーター回転フラグをリセット     カウントダウンタイマーを1減少     カウントダウンタイマーが0? #3秒経った? カウントダウンタイマーにN*100を代入 状態変数に'強制回転'を代入 else 状態変数が'強制回転'? #時間を測る モーター回転フラグをセット     カウントダウンタイマーを1減少     カウントダウンタイマーが0? #N秒経った? カウントダウンタイマーにN*100を代入 状態変数に'通常回転'を代入 モーター回転フラグがセットされていればモーター回転、そうでなければモーター停止 0.01秒スリープ

状態変数によって「やること」をバッサリ切り替えるから多分考えるのが楽。センサーを見たくないならセンサーを見ずにただ時間を測ればいい,とか。

投稿2021/12/10 13:33

編集2021/12/11 01:07
thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryu-12

2021/12/14 01:21

thkana様 返信が遅くなってしまい申し訳ございません。 わかりました。参考にさせていただきます。
guest

0

ベストアンサー

とりあえず一度検知したらセンサーを無視し続ける前提で作成します。
再始動時にフラグを立てて、そのフラグがTrueであれば強制的に次のループへ行くようにします。
motorstopなる関数があるかはわかりませんが。

python

1restart_flag = False 2while True: 3 try: 4 if restart_flag: 5 continue 6 if(GPIO.input(SENSOR_PORT) == 0): 7 motorstart() 8 GPIO.output(LED, GPIO.LOW) 9 10 else: 11 GPIO.output(LED, GPIO.HIGH) 12 motorstop() 13 time.sleep(3) 14 motorstart() 15 restart_flag = True 16 17 except KeyboardInterrupt: 18 GPIO.cleanup() 19 sys.exit() 20

投稿2021/12/08 08:11

irognodyci

総合スコア227

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryu-12

2021/12/09 07:30

irognodyci様 ご回答ありがとうございます。 irognodyci様のプログラムを現在のプログラムに付け加えて、試してみました。 狙い通りに一度反応した後はセンサーの状態を無視することはできました。ですが、モーターの再始動がうまくいきません。センサー反応後にモーターを停止、停止から3秒後にセンサーの反応を無視し、モーターを再始動という内容ですが、「モーターを再始動」の時に問題が起きます。本来ならそのまま回転してほしいのですが、一瞬だけ(1~5°程度)動き、停止してしまいます。 質問欄に追記として現在のプログラムを貼っておきますので、もし間違いなどがあった場合は、ご指摘よろしくお願いします。
irognodyci

2021/12/09 13:06

モーター制御をしたことがないのでわからないですが、 if restart_flag: motorstart() continue こんな風に毎回スタートをかけたら動いたりしますか?
ryu-12

2021/12/10 01:51

irognodyci様 ご回答ありがとうございます。 irognodyci様の回答通りにプログラムを修正したところ、停止から3秒後にモーターを再始動させることができました。教えて下さりありがとうございます。 以前おっしゃっていた「センサーを再び有効にするためのトリガー」に関しての質問なのですが、 「GPIO.output(○○,GPIO.HIGH)」のようなものでもトリガーとして扱えますか?使えるとしたらどの部分に入れるのがベストか、教えていただけないでしょうか。何度も質問するようで申し訳ございませんが、よろしくお願いします。
irognodyci

2021/12/11 00:49

今の状態は、フラグをたててその状態を見て処理を変えてます。フラグがTrueのときは、一切センサーを見ずにモーターに回転指令を出し続けています。フラグがFalseのときは、センサーの値によって処理を変えています。 なので、フラグをTrue→Falseに変えるとセンサーの値を見て判断するようになります。 フラグがTrueの時の処理に、何かが起きたらフラグをFalseにする処理を入れるとまたセンサーによって判断するようになりますよ。この何か、をトリガーと呼んでいます。例えばセンサー2があってその値がこうなったら。とか、時間が〇秒経ったら。とか。
ryu-12

2021/12/13 06:11

irognodyci様 返信が遅くなってしまい申し訳ございません。 ご丁寧に説明してくださってありがとうございます。前々からフラグの「True」と「False」についてわからない点があったのでとても参考になりました。 自分としては、「時間が〇秒経ったら」をトリガーとして使用したいと考えています。 >フラグがTrueの時の処理に、何かが起きたらフラグをFalseにする処理を入れる これを行う際にどこにトリガーを入れればいいのかが現在わかりません。 if restart_flag: GPIO.output(LED1, GPIO.HIGH) motorstart() continue の部分に「モーターが再始動してから3秒後にフラグをFalseにする」というようなプログラムを加えてみました。(LED用のGPIOが増えていますが気にしなくても大丈夫だと思います) if restart_flag: GPIO.output(LED1, GPIO.HIGH) motorstart() time.sleep(3) restart_flag = False continue ですが、うまくいかずにセンサーの状態を無視できなくなり、強制停止してしまいます。(物体が無くなると動きだす)また、フラグがTrueになったときの部分(下記) else: GPIO.output(LED1, GPIO.LOW) GPIO.output(LED2, GPIO.HIGH) motorstop() time.sleep(3) restart_flag = True GPIO.output(LED2, GPIO.LOW) ここにも最初に試したようなプログラムを入れてみましたが、同様に強制停止していました。 もし組み方を間違っていれば、アドバイスを頂けると幸いです。よろしくお願いします。
irognodyci

2021/12/13 08:55 編集

>うまくいかずにセンサーの状態を無視できなくなり、強制停止してしまいます。 ここは、①検知するまでモーターを回し続ける→②検知→③モーターストップ(3秒)→④モータースタート(3秒間センサーを無視)→⑤ ①に戻る の③の部分で止まってしまうという感じでしょうか? とりあえずそれ前提で話を進めます。モーターを回すには常にmotorstartを呼び出し続けなければいけないのかな?と今までの挙動を見てて思っていて、だとするとtime.sleep(3)で止まっている3秒間の間はmotorstartを呼び出せないので止まっていると推測します。 そこで、別の方法で時間を測ります。 time.time()で今の時間を秒で取得できるのですが、restart_flag=Trueにしたときに取得するようにして、if restart_flag の中で今の時間と比較して3秒経っていたらrestart_flagをfalseに変えるようにします。 if restart_flag: ----GPIO.output(LED1, GPIO.HIGH) ----motorstart() ----if time.time() - s_t >= 3: --------restart_flag = False ----else: --------continue if(GPIO.input(SENSOR_PORT) == 0): ----motorstart() ----GPIO.output(LED, GPIO.LOW) else: ----GPIO.output(LED, GPIO.HIGH) ----motorstop() ----time.sleep(3) ----motorstart() ----restart_flag = True ----s_t = time.time() インデントが見えなくなるので----でインデントみたくしました。 エディタに貼り付ける時に----をスペースに置換してください
ryu-12

2021/12/14 02:00

irognodyci様 ご回答ありがとうございます。 irognodyci様のおっしゃったプログラムを使用して修正したところ、成功させることができました。 time.time()を使用するという点は自分も考えてはいましたが、組み方や使い方がわからなかったので、とても参考になりました。 ほとんどの修正点を頼ってしまう形になってしまい申し訳ございません。これからもプログラムの作成や修正などをおこなっていくので、その際にもし何かアドバイス等があった場合は教えていただけると幸いです。修正後のプログラムは「解決方法」の欄に貼っておきます。 お付き合いいただき、本当にありがとうございます。
guest

0

回答者の方々のアドバイスをもとに修正してみました。

Python3

1import RPi.GPIO as GPIO 2import time 3import sys 4import datetime 5import numpy as np 6GPIO.setwarnings(False) 7GPIO.setmode(GPIO.BOARD) 8 9motor1speed = 15 10motor1Direction = 21 11SENSOR_PORT = 24 12LED1 = 35 13LED2 = 37 14 15 16GPIO.setup(19,GPIO.OUT) 17GPIO.setup(motor1speed,GPIO.OUT) 18GPIO.setup(motor1Direction,GPIO.OUT) 19GPIO.setup(SENSOR_PORT, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 20GPIO.setup(LED1, GPIO.OUT) 21GPIO.setup(LED2, GPIO.OUT) 22 23#モーター制御 24def motorstart(): 25 pwm = GPIO.PWM(19, 100) 26 pwm.start(0) 27 GPIO.output(motor1Direction, 0) 28 pwm.ChangeDutyCycle(40) 29 pwmR = GPIO.PWM(motor1speed, 100) 30 pwmR.start(0) 31 GPIO.output(motor1speed, 1) 32 pwmR.ChangeDutyCycle(23) 33 34def motorstop(): 35 GPIO.output(motor1speed, 0) 36 GPIO.output(motor1Direction, 0) 37 38motorstart() 39 40restart_flag = False 41while True: 42 try: 43 if restart_flag: 44 GPIO.output(LED1, GPIO.HIGH) 45 motorstart() 46 if time.time() - s_t >=3: 47 restart_flag = False 48 else: 49 continue 50 51 if(GPIO.input(SENSOR_PORT) == 0): 52 motorstart() 53 GPIO.output(LED1, GPIO.HIGH) 54 GPIO.output(LED2, GPIO.LOW) 55 56 else: 57 GPIO.output(LED1, GPIO.LOW) 58 GPIO.output(LED2, GPIO.HIGH) 59 motorstop() 60 time.sleep(3) 61 motorstart() 62 restart_flag = True 63 s_t = time.time() 64 GPIO.output(LED2, GPIO.LOW) 65 66 except KeyboardInterrupt: 67 GPIO.cleanup() 68 sys.exit()

教えてくださった方々、本当にありがとうございました。

投稿2021/12/14 02:02

ryu-12

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問