はじめに
RaspberryPi Pico・MicroPythonを使って、ビデオの自動録画を行う(イベントドリブンな)プログラムについて質問をいただいたので、解説したいと思います。
これまでの記事は、センサから温度・距離を取得するなどの、「単体の処理」についての解説をしてきました。「処理を組み合わせて目的を達成する」ような「システムの作り方」については解説してこなかったので「ビデオの自動録画」を題材に、システムの作り方について解説してみたいと思います。
- 複数のセンサを組み合わせたシステムを作る
- Picoから外部のセンサを動かす
- 外部センサからの入力(I/O)をPicoで取得する
- PicoからPWM信号を出力する
環境
この記事は以下の環境で作成しています。
環境 | バージョン | 備考 |
開発用PCのOS | Windows11 | Windows10でもOKです |
言語 | MicroPython | |
開発環境 Thonny | 3.3.13 | |
ボード | RaspberryPi Pico |
※ Picoのセットアップ方法については、こちらの記事をご覧ください。
Picoピンアサイン(Pin-Out)
※ Pico公式サイトより引用
使用する機材や部品
この記事では以下の機器や部品を使用します。リンクには同等品や人気・評判がよく、高価(ぼったくり価格)でないものを選んで掲載しています。




ビデオ自動録画のシステム構成
コメントでいただいた自動録画システムの構成は以下の通りです。

※ この記事では入力をタクトスイッチ。出力をLEDに置き換えた回路を使って解説します。
ビデオ自動録画システムの流れ
自動録画システムの動作内容は以下の通りです。
- 人感センサに反応があったら、ソレノイドでビデオカメラの電源ボタンを押す。
- 10秒待機する(ビデオカメラの起動待ち)
- ソレノイドで録画ボタンを押す(録画を開始する)
- 10秒待機する(録画中)
- ソレノイドで録画ボタンを押す(録画を停止する)
- 人感センサに反応があったら③に戻る。そうでない場合は次に進む
- 10秒待機する(録画データの書き込み待ち)
- ソレノイドでビデオカメラの電源ボタンを押す。
- ①に戻る
また、上記の動作に以下の機能も付け加えます。
- 録画ボタン操作時はスピーカーから音を鳴らす。
- スピーカ駆動はPWMを使う(1kHz, Duty50%)
- 録画中に暗い場合は、LED照明をつける ※
※ コメントでは「次回の録画時」となっていますが、簡素化しています。
実行結果
システムを簡易化した回路で、後述するプログラムを実行した際の動画です。
簡易回路
プログラム実行時の動画
実行時の動画です。見やすさのためPWMの周波数を10Hzにしています。
全体コード
全体コードは以下の通りです。
メインの処理をシンプルにするため、センサとのやり取りを「関数」にまとめています。(関数は細かい処理をまとめた部品・ブロックのようなものと考えてください)
前述した自動録画システムの動作内容と合うように、プログラムのメイン処理を記載しています。その他、詳細な内容は後述のコードのポイントをご覧ください。
import machine
import time
from machine import PWM
#
# --- 入力ピンの設定です -----------
#
# 人感センサ
Motion = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN)
# CDS(明るさセンサ)
CDS = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_DOWN)
#
# --- 出力ピンの設定です -----------
#
# ビデオ電源操作用
VideoPwr = machine.Pin(17, machine.Pin.OUT)
# ビデオ録画操作用
VideoRec = machine.Pin(19, machine.Pin.OUT)
# スピーカ(PWM)
Speaker = PWM( machine.Pin(20, machine.Pin.OUT))
# PWMを1kHzに設定
Speaker.freq(1000)
#Speaker.freq(10)
# LED照明
LED = machine.Pin(21, machine.Pin.OUT)
#
# 人感センサ確認用関数
#
def isMotionSensorDetect():
if Motion.value() == 1:
# 人感センサ検知
return True
return False
#
# CDS(明るさセンサ)の確認とLEDを点灯する関数
#
def checkNight():
if CDS.value() == 0:
# CDSが0(暗かったら) LEDを光らせる
LED.value(1)
print("LED照明を点けました")
else:
print("LED照明はいりません")
#
# ビデオの電源用ソレノイドの動作関数
# ソレノイドを「onTime」で指定した時間、Highにして戻します。
#
def videoPowerPush(onTime):
VideoPwr.value(1)
time.sleep(onTime)
VideoPwr.value(0)
#
# ビデオの録画用ソレノイドの動作関数
# ソレノイドを「onTime」で指定した時間、Highにして戻します。
# ピンがHighの間は、スピーカーから音が出ます
#
def videoRecPush(onTime):
VideoRec.value(1)
# スピーカーから音を出します
Sound(True)
time.sleep(onTime)
# スピーカーの音を止めます
Sound(False)
VideoRec.value(0)
#
# スピーカーから音を鳴らす関数
#
def Sound(switch):
if switch == True:
# Duty比を50にセットする。(100は65536)
Speaker.duty_u16(32768)
else:
# Duty比0で出力は止まります
Speaker.duty_u16(0)
#
# LED照明をOFFにする関数
#
def ledOff():
LED.value(0)
# ------------ プログラムのメインの処理内容です -----------
print("メイン開始")
# 無限ループで終了を防止します。
while(True):
# 人感センサの反応確認
if( isMotionSensorDetect() == True ):
print("人感センサ 検知")
videoPowerPush(1)
time.sleep(10)
# 再録画用のループです
while(True):
# 明るさを確認してLEDを点けます
checkNight()
# ビデオの録画ボタンを押します
videoRecPush(1)
# 録画している間は待機します
time.sleep(10)
# ビデオの録画ボタンを押して、録画を止めます。
videoRecPush(1)
# LED照明を消灯します
ledOff()
# 録画完了語、再度人感セセンサをチェックします。
if( isMotionSensorDetect() == True ):
print("人感センサを再度検知しました")
else:
print("人感センサは、再度検知されませんでした")
#録画停止
break
time.sleep(10)
videoPowerPush(1)
print("電源OFFしました")
# 人感センサ非検知
else:
print("人感センサ 非検知")
time.sleep(1)
コードのポイント
無限ループと人感センサの確認
以下の部分がプログラムのフレームになります。センサの反応があるまでプログラムを動かし続けるため、while(True)でプログラムを無限ループさせます。
無限ループの中でisMotionSensorDetect関数を使って人感センサを確認し、反応があった場合はその下の処理に。ない場合はループの最後のelseに飛びます。elseに飛んだあとは、1秒待機するのみで、無限ループの冒頭に戻ります。
上記「無限ループ」と「反応がない場合は何もしない」という仕組みで、「人感センサの反応があるまで待ち続ける」という処理を作ることができます。自動録画システムの動作内容の①と⑨に該当します。
# 無限ループで終了を防止します。
while(True):
# 人感センサの反応確認
if( isMotionSensorDetect() == True ):
print("人感センサ 検知")
// ~~~~~ 中略 ~~~~~~~
# 人感センサ非検知
else:
print("人感センサ 非検知")
time.sleep(1)
isMotionSensorDetect関数
関数の詳細です。「Motion」という名前を付けた人感センサ用のGPIO(GP16, IN)から、センサ情報を取得して、判定結果を返します。
このように関数化しておくと、センサの論理(High/Low)の仕様が変わったり、センサを変更したい場合に、関数内の修正だけで対応できます。バグの発生防止や問題切り分けに有効なのでおすすめです。
#
# 人感センサ確認用関数
#
def isMotionSensorDetect():
if Motion.value() == 1:
# 人感センサ検知
return True
return False
ビデオカメラの電源ON
人感センサを検知すると、videoPowerPush関数を使ってビデオカメラの電源用ソレノイドを動作させます。
関数の後ろの(1)は「引数」というものです。数値・文字・True/Falseなどを関数にセットした上で、関数を実行します。以下のコードはvideoPowerPush関数のの「onTime」に「1」がセットされた状態で、関数が実行されます。
# 人感センサの反応確認
if( isMotionSensorDetect() == True ):
print("人感センサ 検知")
videoPowerPush(1)
time.sleep(10)
videoPowerPush関数
関数の詳細です。「onTime」に1がセットされると「ビデオ電源用のソレノイドを1秒間Highにして、Lowに戻す」という動作になります。
#
# CDS(明るさセンサ)の確認とLEDを点灯する関数
#
def checkNight():
if CDS.value() == 0:
# CDSが0(暗かったら) LEDを光らせる
LED.value(1)
print("LED照明を点けました")
else:
print("LED照明はいりません")
再録画のループ
録画に関する処理内容です。自動録画システムの動作内容の③~⑥に該当します。
以下の録画に関する処理は、繰り返し行われる可能性があるため、ループで囲っています。ループを終了する条件については、後述します。
# 再録画用のループです
while(True):
# 明るさを確認してLEDを点けます
checkNight()
# ビデオの録画ボタンを押します
videoRecPush(1)
# 録画している間は待機します
time.sleep(10)
# ビデオの録画ボタンを押して、録画を止めます。
videoRecPush(1)
# LED照明を消灯します
ledOff()
明るさのチェック
checkNight関数を使って、明るさの確認とLED照明の点灯を行います。人感センサのチェックと同様ですが、暗い場合のみLED照明をON(GPIOをHigh)にしています。
# 明るさを確認してLEDを点けます
checkNight()
#
# CDS(明るさセンサ)確認とLED ON用関数
#
def checkNight():
# CDSが0(暗かったら) LEDを光らせる
if CDS.value() == 0:
LED.value(1)
print("LED照明を点けました")
else:
print("LED照明はいりません")
ビデオ録画ボタン操作とブザー
videoRecPush関数を使って、録画ボタンの操作と操作時のブザーを鳴らします。
videoRecPush(1)
videoRecPush関数
ビデオ電源操作用の関数と同様ですが、ソレノイドをONにしている間、後述のSound()関数を使ってブザーを鳴らします。
#
# ビデオの録画用ソレノイドの動作関数
# ソレノイドを「onTime」で指定した時間、Highにして戻します。
# ピンがHighの間は、スピーカーから音が出ます
#
def videoRecPush(onTime):
VideoRec.value(1)
# スピーカーから音を出します
Sound(True)
time.sleep(onTime)
# スピーカーの音を止めます
Sound(False)
VideoRec.value(0)
Sound関数
duty_u16という関数を使ってPWM信号を出力します。
引数でデューティー比は、16bit(0~65536)で指定する必要があるため、デューティー比50となる「32768」を指定しています。PWM信号を止める場合は「0」を指定します。
# スピーカーから音を鳴らす関数
def Sound(switch):
if switch == True:
# Dutyを50でON。(100は65536)
Speaker.duty_u16(32768)
else:
# Duty0で出力されなくなる
Speaker.duty_u16(0)
録画終了とLEDの消灯
前述したvideoRecPush関数を使って録画を停止します。checkNight関数によって、LED照明が点灯している場合があるので消灯します。
(すでに消灯している場合でもピンがLow->Lowになるだけなので、分岐は入れていません)
# 録画している間は待機します
time.sleep(10)
# ビデオの録画ボタンを押して、録画を止めます。
videoRecPush(1)
# LED照明を消灯します
ledOff()
再録画ループの終了判定
録画処理を行ったら、再度isMotionSensorDetect関数を使って、人感センサの反応を確認します。検知した場合は再録画のループの先頭に戻って、録画処理を繰り返します。
人感センサの反応がない場合は、ループを終了する(抜ける)breakという構文を使って、再録画のループの外側に移動します。
# 再録画用のループです
while(True):
checkNight()
~~~~~ 中略 ~~~~~
if( isMotionSensorDetect() == True ):
print("人感センサを再度検知しました")
continue
else:
print("人感センサは、再度検知されませんでした")
#録画停止
break
ビデオの電源OFFと最初に戻る
前述した再録画のループがbreakになると、以下に移ります。
録画データの保存を10秒待ったのち、videoPowerPush関数を使ってビデオの電源をOFFにします。
上記の処理で電源ON~録画の処理が完了し、無限ループの先頭に戻ます。戻った後は再度、人感センサ反応があるまで待つ。という流れになります。
time.sleep(10)
videoPowerPush(1)
print("電源OFFしました")
まとめ
RaspberryPi Pico・MicroPythonを使って、ビデオの自動録画を行う(イベントドリブンな)プログラムについて解説しました。
今回の方法以外にも、タイマーやスレッド、状態遷移を使った方法など、いろいろな実現方法はあるかと思います。今回はシンプルで入門者にも優しいSleepを使った同期的な方法で作成してみました。(H/W・S/W的エラー処理も省略しています)
つたないコードと解説ですが、お役に立てればうれしいです。
お知らせ
MicroPythonのプログラミングガイドブックが遂に発売!
「MicroPython」の本が遂にでました。
この一冊で、MicroPythonの言語仕様から、プログラミングの仕方まで”ガッツリ”学べます!
内容は、普段別言語で開発している人や、これからマイコンを始める(工学系の)学生を対象としているので「初心者向け」ではありません。しかし、「自前のライブラリの作成」が目標なので、これ一冊で「ガッツリ」とMicroPythonを学ぶことができます。
全ての内容はここでは紹介しきれないので、詳細は以下のAmazonページをご覧ください。目次だけでも”ガッツリ”なのが確認できると思います。

Pico/Pico W関連のおすすめ本
RaspberryPi Pico / Pico W関連のおすすめ本を独断と偏見で3つ選んでみました。Picoやるならとりあえずこれ買っとけ的な本や、電子工作全般で使える本などを厳選しています。
質問・要望 大歓迎です
「こんな解説記事作って」「こんなことがしたいけど、〇〇で困ってる」など、コメント欄で教えてください。 質問・要望に、中の人ができる限り対応します。
使えたよ・設定できたよの一言コメントも大歓迎。気軽に足跡を残してみてください。記事を紹介したい方はブログ、SNSにバシバシ貼ってもらってOKです。