純粋なPythonの記事ではありませんが、エラー解決ができた事例がありましたので記事にしました。
私はArduino(アルドゥイーノ)が好きで、ロボット制御や簡単なIoTシステムを構築しています。
「PythonからArduinoを制御できる」と聞き、やってみたところLチカでつまづきました笑。
その際に色々調べた結果、一つの解決策がヒットしましたので公開します。
あくまで一つの解決策であり、誰しも当てはまる事例ではないかもしれませんが、お役に立てれば幸いです。
実行環境
まず、私の環境を簡単に紹介しておきます。
- Windows10/11
- Arduino IDE 2.1.0
- Arduino本体 UNO R3とUNO R4 MINIMAを使用
- Python 3.9
- PySerial 3.5
上記はそれほど影響がないと思われます。
Arduino本体はUNO R3とUNO R4 MINIMAを試しました。
これ以外のArduinoをお使いの場合は解決できない場合があります。
ちなみに、PythonからArduinoを制御するための方法はいくつかあるようですが、私はPySerialというライブラリを利用する方法を使っています。
以降の解説はPySerialに関するスクリプトの例を提示します。
実行したコードの公開
もし、私と同じようにPythonからArduinoのLチカをやってみたいという場合、以下のコードとスクリプトを試してもらうとできるはずです。
Arduinoのコード
本体の13番ピンに直結しているLEDを点滅させる基本コードとして、「Lチカ」を実行できます。
ただし、純粋にArduinoだけで実行するBlink(Lチカ)と異なる点は「Pythonから送信された値によって制御する」という処理をswitch/caseで実現していることです。
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
}
void loop() {
byte var;
var = Serial.read();
switch(var){
case '0':
digitalWrite(13, HIGH);
break;
case '1':
digitalWrite(13, LOW);
break;
default:
break;
}
}
最初にこれをArduino本体に書き込んでおく必要があります。
この時点でエラーが出る場合、本記事の解決策では対応できません。
Pythonのスクリプト
今回の目的はLチカなので、LEDの点灯と消灯を1秒ずつ繰り返す処理のみです。
Arduinoでは1秒=1000ミリ秒を「delay(1000)」としますが、Pythonではtime.sleepによって1秒を指示しています。
import serial
import time
# 第一引数について:Macなら「'/dev/ttyUSB0'」、Windowsなら「'COM8'」と記述
ser = serial.Serial('COM8', 9600)
while True:
# LEDの点灯と消灯を1秒ずつ繰り返す(=点滅する)
ser.write(b"1")
time.sleep(1)
ser.write(b"0")
time.sleep(1)
上記はWindowsにおいてArduinoを接続したUSBポートが「COM8」の場合の書き方です。
これはお使いの環境によって異なるため、確認してください。
参考までに、以下はUNO R4を接続したUSBポートが「COM6」となっているため、この場合は「ser = serial.Serial(‘COM6’, 9600)」とすればOKです。
また、Macの場合はWindowsと異なり、「ser = serial.Serial(‘/div/ttyUSB0’, 9600)」のようになります。
※手元にmacがなかったので、画面キャプチャは紹介できませんでした。
なお、上記はPySerialをインストール済みであれば実行できます。
pip install pyserial
または
pip3 install pyserial
が必要です。
エラーの状況
PC→Arduinoへの書き込み時はエラーもなくコンパイルできたけど、Pythonのスクリプトを実行したときにエラーが出る場合の解決策を紹介します。
対象外のエラー
ただ、この時点でエラーが出るという場合、この記事の解決策は役に立ちません。
Arduinoのプログラムを見直すか、USBケーブルの接続状況を見直しましょう。
また、Arduino本体が互換品だと問題が起きる場合も多くあります。
上のような青い基盤のものは互換品と言われ、難ありなものが多く存在します。
安くて良いのですが、おススメしません。
対象となるエラー
Pythonのスクリプトを実行したとき、以下のエラーが出る場合は以降の解説を参考にしてください。
C:\pythonarduino\Scripts\python.exe C:\papa3\pythonarduino\sketch_oct23a\main.py
Traceback (most recent call last):
File "C:\papa3\pythonarduino\sketch_oct23a\main.py", line 5, in <module>
ser = serial.Serial('COM8', 9600)
File "C:\pythonarduino\lib\site-packages\serial\serialwin32.py", line 33, in __init__
super(Serial, self).__init__(*args, **kwargs)
File "C:\pythonarduino\lib\site-packages\serial\serialutil.py", line 244, in __init__
self.open()
File "C:\pythonarduino\lib\site-packages\serial\serialwin32.py", line 64, in open
raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError()))
SerialException: could not open port 'COM8': PermissionError(13, 'アクセスが拒否されました。', None, 5)
ただし、上記のように「アクセスが拒否されました」ではなく、
serial.serialutil.SerialException: could not open port 'COM8': FileNotFoundError(2, '指定されたファイルが見つかりません。', None, 2)
のように「指定されたファイルがみつかりません」と表示される場合、Pythonスクリプト内のポート番号が間違っている可能性があります。
正しいポート番号に直すだけで、エラーが解決するかもしれません。
エラーの解決方法
ここからは、エラーが「PermissionError ‘アクセスが拒否されました」の場合の解決策を提示します。
よく目にする解決策
私が困ったとき、ググって出てきた情報をまとめると、
- ・Pythonスクリプトを管理者で実行する
- ・コマンドプロンプトを管理者で起動してPythonスクリプトを実行する
- ・Pythonスクリプト内に管理者権限を追記する
- ・バッチファイルを作ってそこにPythonスクリプトのリンクを貼って管理者権限で…
という解説が多かったです。
しかし、私の場合はそれでは解決ができませんでした。
実際に解決できた方法
非常に簡単だったのですが、「Pythonスクリプト実行時にArduino IDEを閉じる」ということでエラーが消えLチカが実行できました。
一度Arduinoにスケッチを書き込んでしまえば、Arduino IDEを起動している必要がありませんから問題ありませんね。
これで解決できた理由は「シリアルモニターを開いているなどUSBを通して「シリアル通信」が行われているとアクセスできないから」だと考えられます。
それが「アクセスが拒否された」という理由ではないでしょうか。
(これは個人的な見解のため、誤りである可能性が高いです。)
理由はどうであれ、無事に実行できるようになれば幸いです。
まとめ
今回は「PySerialでPermissionError’アクセスが拒否されました’」というエラーを解決する方法について解説しました。
もし、この記事の内容でも解決できないという場合、コメントやフォームにてご質問ください。
今後もPythonを中心としたプログラミングの情報をお届けします。
以下のメルマガにご登録頂くと、不定期に配信をお届けします。
ぜひ購読してください!
それでは、ステキなPythonライフを!