.. note:: こんにちは!SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Communityへようこそ!Raspberry Pi、Arduino、ESP32について、他の愛好者と一緒にさらに深く学んでいきましょう。 **参加する理由** - **専門家のサポート**: 購入後の問題や技術的な課題を、コミュニティやチームのサポートを通じて解決できます。 - **学びと共有**: ヒントやチュートリアルを交換し、スキルを向上させましょう。 - **特別なプレビュー**: 新製品の発表や先行公開に早期アクセスできます。 - **特別割引**: 新しい製品に対して限定割引をお楽しみください。 - **祝祭プロモーションとプレゼント**: プレゼントや祝祭プロモーションに参加できます。 👉 私たちと一緒に探求し、創造する準備はできましたか?[|link_sf_facebook|]をクリックして、今すぐ参加しましょう! .. _py_avoid: 4. 障害物回避 ===================== このプロジェクトでは、PiCrawlerが超音波モジュールを使用して前方の障害物を検出します。 PiCrawlerが障害物を検出すると、信号を送信し、別の方向に進むために方向転換を行います。 .. .. image:: img/avoid1.png **コードを実行する** .. raw:: html .. code-block:: cd ~/picrawler/examples sudo python3 4_avoid.py プログラムが開始されると、PiCrawler は立ち上がります。 超音波センサーを使用して距離を継続的に測定し、 その値をターミナルに表示します。 15 cm以内に障害物が検出された場合: - 警告音が再生されます。 - ロボットは小さく左に旋回します。 進行方向に障害物がない場合: - ロボットは前進します。 Ctrl+C を押すまで、ロボットは自動的に障害物回避を続けます。 終了する前に、安全に座る姿勢に戻ります。 **コード** .. note:: 下記のコードは **修正/リセット/コピー/実行/停止** できます。ただし、まずはソースコードのパス(例えば ``picrawler\examples`` )に移動してください。コードを修正した後、直接実行して効果を確認できます。 .. raw:: html .. code-block:: python from picrawler import Picrawler from robot_hat import Music, Ultrasonic, Pin import time import signal music = Music() crawler = Picrawler() sonar = Ultrasonic(Pin("D2"), Pin("D3")) # Ultrasonic trigger/echo pins music.music_set_volume(100) # Set speaker volume alert_distance = 15 # Obstacle warning distance (cm) speed = 80 # Movement speed # ---------------------------- # Add hardware timeout to sonar.read() # Prevent program from freezing # ---------------------------- class Timeout(Exception): pass def _alarm_handler(signum, frame): raise Timeout() signal.signal(signal.SIGALRM, _alarm_handler) # Read distance once with timeout protection def safe_read_once(timeout_s=1): try: signal.alarm(timeout_s) d = sonar.read() signal.alarm(0) return d except Timeout: signal.alarm(0) return None except Exception: signal.alarm(0) return None # Read multiple times and return median value (anti-noise) def read_distance_filtered(n=5, gap=0.03, timeout_s=1): vals = [] for _ in range(n): d = safe_read_once(timeout_s=timeout_s) if d is not None and d > 0: vals.append(d) time.sleep(gap) if not vals: return None vals.sort() return vals[len(vals)//2] # Median filter def main(): distance = read_distance_filtered(n=5, gap=0.03, timeout_s=1) print("distance:", distance) if distance is None: time.sleep(0.15) # Wait if read failed return if distance <= alert_distance: # Obstacle detected → play sound and turn try: music.sound_play_threading('./sounds/sign.wav', volume=100) except Exception as e: print("sound error:", e) crawler.do_action('turn left angle', 1, speed) time.sleep(0.5) # Quiet window after movement else: # Path clear → move forward crawler.do_action('forward', 1, speed) time.sleep(0.4) if __name__ == "__main__": try: crawler.do_step('stand', 40) # Stand before starting time.sleep(1.0) while True: main() except KeyboardInterrupt: print("\nStop.") finally: try: crawler.do_step('sit', 40) # Sit before exit time.sleep(1.0) except Exception: pass **どのように動作するのか?** #. 初期化ブロック .. code-block:: python music = Music() crawler = Picrawler() sonar = Ultrasonic(Pin("D2"), Pin("D3")) music.music_set_volume(100) alert_distance = 15 speed = 80 このブロックでは、3つの主要モジュールを初期化します: - ``music``:音声の再生を制御します。 - ``crawler``:PiCrawler の動作を制御します。 - ``sonar``:超音波センサーを使用して距離を読み取ります。 また、スピーカーの音量、障害物検出のしきい値(cm)、 および移動速度を設定します。 #. タイムアウト設定ブロック(``sonar.read()`` が停止するのを防ぐ) .. code-block:: python class Timeout(Exception): pass def _alarm_handler(signum, frame): raise Timeout() signal.signal(signal.SIGALRM, _alarm_handler) 超音波センサーのドライバは、エコー信号を待つ間に 処理がブロックされる可能性があります。 このブロックではシグナルハンドラを設定し、停止した ``sonar.read()`` の呼び出しをプログラム側で中断できるようにします。 #. 関数:safe_read_once() .. code-block:: python def safe_read_once(timeout_s=1): try: signal.alarm(timeout_s) d = sonar.read() signal.alarm(0) return d except Timeout: signal.alarm(0) return None except Exception: signal.alarm(0) return None この関数は、タイムアウト保護付きで超音波センサーを1回読み取ります。 - 読み取りが成功した場合は、距離の値を返します。 - タイムアウトまたはエラーが発生した場合は、処理が停止する代わりに ``None`` を返します。 #. 関数:read_distance_filtered() .. code-block:: python def read_distance_filtered(n=5, gap=0.03, timeout_s=1): vals = [] for _ in range(n): d = safe_read_once(timeout_s=timeout_s) if d is not None and d > 0: vals.append(d) time.sleep(gap) if not vals: return None vals.sort() return vals[len(vals)//2] この関数は、複数回のサンプルを取得することで信頼性を向上させます: - 無効な値(``None`` または ``<= 0``)は無視されます。 - 残った値をソートします。 - ノイズの影響を減らすために中央値を返します。 #. 関数:main()(主要な判断と動作) .. code-block:: python def main(): distance = read_distance_filtered(...) if distance is None: return if distance <= alert_distance: music.sound_play_threading(...) crawler.do_action('turn left angle', 1, speed) else: crawler.do_action('forward', 1, speed) これはメインの制御ロジックです: - フィルタ処理された距離値を読み取ります。 - 読み取りに失敗した場合、このサイクルはスキップされます。 - 障害物が ``alert_distance`` より近い場合、警告音を再生し、左に旋回します。 - それ以外の場合は前進します。 #. プログラムエントリーブロック(連続ループ + 安全終了) .. code-block:: python if __name__ == "__main__": try: crawler.do_step('stand', 40) while True: main() except KeyboardInterrupt: print("\nStop.") finally: crawler.do_step('sit', 40) このブロックは、プログラム全体の動作フローを制御します: - 開始前に PiCrawler を立ち上がらせます。 - プログラムは無限ループで ``main()`` を繰り返し実行します。 - Ctrl+C を押すとループが停止します。 - プログラム終了前に、PiCrawler は座る姿勢に戻ります。