ArduinoとPythonでジェスチャー制御PC:ハンズフリー操作を実現
必要な部品と材料
| 部品 | 数量 |
|---|---|
| Arduino UNO | 1 |
| 超音波センサー HC-SR04(汎用) | 2 |
| ジャンパーワイヤー(汎用) | 1 |
使用するアプリとオンラインサービス
- Arduino IDE
- Python IDLE
- PySerialライブラリ
- PyAutoGUIライブラリ
プロジェクト概要
このプロジェクトでは、ジェスチャーでノートパソコンやコンピューターを制御する方法を学びます。ArduinoとPythonの組み合わせに基づいています。
キーボード、マウス、ジョイスティックの代わりに、手のジェスチャーでコンピューターの特定機能を制御できます。動画の再生/一時停止、写真スライドショーの左右移動、Webページの上下スクロールなどが可能です。そのため、VLC Media Playerを手ジェスチャーで制御するプロジェクトにしました。
アイデアはシンプルです。2つの超音波センサー(HC-SR04)をArduinoで使用します。2つのセンサーをノートパソコン画面の上部に配置し、手とセンサーの距離を計測。Arduinoからシリアルポート経由で送信される情報を、コンピューターで実行中のPythonが読み取り、特定のアクションを実行します。
ハードウェアコンポーネント:
- Arduino
- 超音波センサー(HC-SR04)× 2
- ワイヤー数本
ソフトウェアアプリ:
- Arduino IDE
- Python IDLE
- PySerialライブラリ(シリアルポート通信用)
- PyAutoGUIライブラリ(アクション実行用)
PythonとPySerialライブラリがインストール済みで、基本的なプロジェクトをいくつか成功させていることを前提としています。そうでない場合は、私の前のチュートリアル(Pythonを使ったArduinoプログラミング)を参考にしてください。超音波センサーに慣れていない場合はこちらをご覧ください。
ステップ1:詳細については動画をご覧ください
ステップ2:手ジェスチャーの目的
デモンストレーション用にプログラミングした5つの手ジェスチャーコマンドは以下の通りです。
- 第1ジェスチャー:左右の超音波センサーの前に両手を特定の遠い距離に置いて、VLCの「再生/一時停止」を実行
- 第2ジェスチャー:左センサーの前に片手を特定の遠い距離に置いて、「巻き戻し」を実行
- 第3ジェスチャー:右センサーの前に片手を特定の遠い距離に置いて、「早送り」を実行
- 第4ジェスチャー:左センサーの前に片手を特定の遠い距離に置き、センサーから離れる動作で「音量アップ」を実行
- 第5ジェスチャー:左センサーの前に片手を特定の遠い距離に置き、センサーに近づく動作で「音量ダウン」を実行
ステップ3:回路図



回路は非常にシンプルです。以下の手順に従ってください。各センサーには4つのピンがあります:
- Vcc - 5V+に接続
- Trig - プログラムでこのピンを定義
- Echo - Trigと同様、プログラムで定義
- GND - グランドに接続
ステップ4:Pythonプログラミング



1. Python IDLEのインストール
Python IDLEがすでにインストール済みの場合はこのステップをスキップしてステップ2へ。未インストールの場合は以下の手順で:
- Python公式サイトからダウンロード(こちら)
- デフォルトのインストールディレクトリを維持してインストール
※ 64ビットOSでも、Arduinoライブラリとの互換性のため32ビット版Pythonを使用できます。
2. PySerialライブラリのインストール
PySerialは、Arduinoや他のマイクロコントローラーにシリアルデータを読み書きするためのPython APIモジュールです。Windowsでのインストール手順:
- PySerialのダウンロードページからダウンロード
- デフォルト設定でインストール
- 正しく動作するか確認:
import serialと入力してエラーが出なければOK
3. PyAutoGUIライブラリのインストール
PyAutoGUIの目的は、人間のためのクロスプラットフォームPython GUI自動化モジュールを提供することです。APIは可能な限りシンプルに設計されています。Windowsでのインストール手順(Python IDLEインストール済み前提):
- Windowsコマンドプロンプトを開く
cd C:\Python27と入力python –m pip install –upgrade pipと入力python –m pip install pyautoguiと入力
※ 他のプラットフォームの場合はこちらを参照。
正しく動作するか確認:import pyautogui と入力してエラーが出なければOK。
ステップ5:Arduinoコード

PythonからArduinoとの接続を開始するには、まずArduinoがどのCOMポートにあるかを特定する必要があります。これはArduinoプログラミング環境で簡単に確認できます(上図参照)。
const int trigger1 = 2; // 1つ目のセンサーのTriggerピン
const int echo1 = 3; // 1つ目のセンサーのEchoピン
const int trigger2 = 4; // 2つ目のセンサーのTriggerピン
const int echo2 = 5; // 2つ目のセンサーのEchoピン
long time_taken;
int dist, distL, distR;
void setup() {
Serial.begin(9600);
pinMode(trigger1, OUTPUT);
pinMode(echo1, INPUT);
pinMode(trigger2, OUTPUT);
pinMode(echo2, INPUT);
}
/*### 距離計算関数 ###*/
void calculate_distance(int trigger, int echo) {
digitalWrite(trigger, LOW);
delayMicroseconds(2);
digitalWrite(trigger, HIGH);
delayMicroseconds(10);
digitalWrite(trigger, LOW);
time_taken = pulseIn(echo, HIGH);
dist = time_taken * 0.034 / 2;
if (dist > 60) dist = 60;
}
void loop() {
// 無限ループ
calculate_distance(trigger1, echo1);
distL = dist; // 左センサーの距離取得
calculate_distance(trigger2, echo2);
distR = dist; // 右センサーの距離取得
// ポーズモード - ホールド
if ((distL > 40 && distR > 40) && (distL < 60 && distR < 60)) // 両手検出
{ Serial.println("Play/Pause"); delay(500); }
calculate_distance(trigger1, echo1);
distL = dist;
calculate_distance(trigger2, echo2);
distR = dist;
// コントロールモード
// 左ロック - コントロールモード
if (distL >= 13 && distL <= 17) {
delay(100); // 手の保持時間
calculate_distance(trigger1, echo1);
distL = dist;
if (distL >= 13 && distL <= 17) {
Serial.println("Left Locked");
while (distL <= 40) {
calculate_distance(trigger1, echo1);
distL = dist;
if (distL < 10) // 手を押し込む
{ Serial.println("Volume Increased"); delay(300); }
if (distL > 20) // 手を引く
{ Serial.println("Volume Decreased"); delay(300); }
}
}
}
// 右ロック - コントロールモード
if (distR >= 13 && distR <= 17) {
delay(100); // 手の保持時間
calculate_distance(trigger2, echo2);
distR = dist;
if (distR >= 13 && distR <= 17) {
Serial.println("Right Locked");
while (distR <= 40) {
calculate_distance(trigger2, echo2);
distR = dist;
if (distR < 10) // 右手を押し込む
{ Serial.println("Rewind"); delay(300); }
if (distR > 20) // 右手を引く
{ Serial.println("Forward"); delay(300); }
}
}
}
delay(200);
}
Arduinoコードを読めば、特定のキーボード機能を制御して必要なタスクを達成する5つのコマンドがあることがわかります。
arduino_pythogui.ino ダウンロード
ステップ6:Pythonコード

まず、シリアルポート経由でデータを送信するシンプルなプログラムが必要です。
import serial # シリアル通信用
import time # 遅延関数用
import pyautogui # アクション実行用
ArduinoSerial = serial.Serial('com15', 9600) # arduinoSerialDataというシリアルポートオブジェクト作成
time.sleep(2) # 通信確立まで2秒待機
while 1:
incoming = str(ArduinoSerial.readline()) # シリアルデータを読み取り、行として出力
print(incoming)
if 'Play/Pause' in incoming:
pyautogui.typewrite(['space'], 0.2)
if 'Rewind' in incoming:
pyautogui.hotkey('ctrl', 'left')
if 'Forward' in incoming:
pyautogui.hotkey('ctrl', 'right')
if 'Volume Increased' in incoming:
pyautogui.hotkey('ctrl', 'down')
if 'Volume Decreased' in incoming:
pyautogui.hotkey('ctrl', 'up')
incoming = "";
コード
コードスニペット #5 Plain text
const int trigger1 = 2; // 1つ目のセンサーのTriggerピン
const int echo1 = 3; // 1つ目のセンサーのEchoピン
const int trigger2 = 4; // 2つ目のセンサーのTriggerピン
const int echo2 = 5; // 2つ目のセンサーのEchoピン
long time_taken;
int dist, distL, distR;
void setup() {
Serial.begin(9600);
pinMode(trigger1, OUTPUT);
pinMode(echo1, INPUT);
pinMode(trigger2, OUTPUT);
pinMode(echo2, INPUT);
}
/*### 距離計算関数 ###*/
void calculate_distance(int trigger, int echo) {
digitalWrite(trigger, LOW);
delayMicroseconds(2);
digitalWrite(trigger, HIGH);
delayMicroseconds(10);
digitalWrite(trigger, LOW);
time_taken = pulseIn(echo, HIGH);
dist = time_taken * 0.034 / 2;
if (dist > 60) dist = 60;
}
void loop() {
calculate_distance(trigger1, echo1);
distL = dist;
calculate_distance(trigger2, echo2);
distR = dist;
if ((distL > 40 && distR > 40) && (distL < 60 && distR < 60))
{ Serial.println("Play/Pause"); delay(500); }
calculate_distance(trigger1, echo1);
distL = dist;
calculate_distance(trigger2, echo2);
distR = dist;
if (distL >= 13 && distL <= 17) {
delay(100);
calculate_distance(trigger1, echo1);
distL = dist;
if (distL >= 13 && distL <= 17) {
Serial.println("Left Locked");
while (distL <= 40) {
calculate_distance(trigger1, echo1);
distL = dist;
if (distL < 10) { Serial.println("Volume Increased"); delay(300); }
if (distL > 20) { Serial.println("Volume Decreased"); delay(300); }
}
}
}
if (distR >= 13 && distR <= 17) {
delay(100);
calculate_distance(trigger2, echo2);
distR = dist;
if (distR >= 13 && distR <= 17) {
Serial.println("Right Locked");
while (distR <= 40) {
calculate_distance(trigger2, echo2);
distR = dist;
if (distR < 10) { Serial.println("Rewind"); delay(300); }
if (distR > 20) { Serial.println("Forward"); delay(300); }
}
}
}
delay(200);
}
コードスニペット #6 Plain text
import serial
import time
import pyautogui
ArduinoSerial = serial.Serial('com15', 9600)
time.sleep(2)
while 1:
incoming = str(ArduinoSerial.readline())
print(incoming)
if 'Play/Pause' in incoming:
pyautogui.typewrite(['space'], 0.2)
if 'Rewind' in incoming:
pyautogui.hotkey('ctrl', 'left')
if 'Forward' in incoming:
pyautogui.hotkey('ctrl', 'right')
if 'Volume Increased' in incoming:
pyautogui.hotkey('ctrl', 'down')
if 'Volume Decreased' in incoming:
pyautogui.hotkey('ctrl', 'up')
incoming = "";
製造プロセス
- Arduinoで作るモニター用Ambilightシステム:没入感アップの自作ガイド
- Arduinoと1Sheeldで作る万能Androidリモコン──IR制御で家電を一括操作
- Arduinoとスマホで作るスマート電圧計 – 簡単DIYプロジェクト
- IoTで遠隔操作する自作ロボットアーム:Arduino MKR1000とSimulink、ThingSpeak活用
- Arduino UNOで周波数とデューティサイクルを高精度測定
- FirmataとXbox OneコントローラーでArduinoローバーをシームレス操作
- Arduino Nanoで作るスマートな動体検知水鉄砲
- Bolt IoTとArduino UNOでLED輝度をシームレス制御
- スマートなArduino制御ロボットアームの製作:簡単DIYチュートリアル
- Arduino IoT CloudとAlexaでテレビを音声操作:ステップバイステップガイド
- Arduino NanoとRDA5807Mで作るコンパクトFMラジオ