MicroPythonの仕様をざっと読んでみたので、以前からやってみたかったサーボ制御をやってみる。入力は1Kのボリュームで、それをAD変換して、得られたレベルに従って、PWM変換してデューティを変えてサーボの角度を調整する。
まずは、ボリューム値を定期的に取ってくるサンプル。
アッテネーションを11DBに設定して3.3Vでも扱えるようにする。また、取得値の幅は計算がしやすいように0-1023と設定。以下のサンプルではIO32に0V-3.3Vまでの変動する電圧がかかるのを想定している。
from machine import ADC
import time
adc = ADC(Pin(32)) # create ADC object on ADC pin
adc.atten(ADC.ATTN_11DB) # set 11dB input attentuation (voltage range roughly 0.0v - 3.6v)
adc.width(ADC.WIDTH_10BIT) # set 9 bit return values (returned range 0-1023)
while True:
print(adc.read())
time.sleep_ms(500)
オンラインマニュアルよりコードを引用して改変
http://docs.micropython.org/en/latest/esp32/quickref.html#adc-analog-to-digital-conversion
上記ADCのサンプルとPWMによるサーボ制御を連結させて作ったのが以下のソース
PWMの設定として、50Hz周期で、パルス幅が0.5 - 2.4の間を変動させることでサーボのアームの角度が変わる。ボリュームのレベルの比率で、0.5msec-2.4msecの間を遷移させればボリュームの回した状態に応じてアームが動くと。。
デバッグ用にprintさせている、また、貧乏省のため、loop内では100msecWAIT(sleep)を入れている。100msecのWAITを入れるとやっぱり応答が遅くなり、微妙な制御の目的には使えない。一方、WAITを取ってしまうと、AD変換でサンプリングの誤差が出て、サーボがプルプル微振動する。だから、、人のフィードバックには忠実に、しかも、サンプリングした値をサーボに与える時点で±1~2の変動は丸めるといった変換が必要と思う。簡単なフィルタ関数かと。。
#-------------------------------------------------------------
# servo_ctrl.py
from machine import Pin, PWM
from machine import ADC
import time
LOOP_WAIT = 100 # wait 100msec
SERVO_MIN = 27
SERVO_MAX = 126
SERVO_CENTER = int((SERVO_MAX - SERVO_MIN)/2) + SERVO_MIN
servo = PWM(Pin(12), freq=50, duty=SERVO_CENTER) # setup servo freq=50Hz set Center=77
vol = ADC(Pin(32)) # create ADC object on ADC pin
vol.atten(ADC.ATTN_11DB) # set 11dB input attentuation (voltage range roughly 0.0v - 3.6v)
vol.width(ADC.WIDTH_10BIT) # set 9 bit return values (returned range 0-1023)
while True:
level = vol.read()
servo_setting = int((SERVO_MAX - SERVO_MIN) * level / 1023) + SERVO_MIN
servo.duty(servo_setting)
print("VR:{:d} Servo:{:d}".format(level,servo_setting))
time.sleep_ms(LOOP_WAIT)
ESP-WROOM-03にサーボとボリュームを付けて動かしているところ。デバッグにはオシロも欠かせない。
勝手にリンク。。
http://nomolk.hatenablog.com/entry/2017/04/09/222415
滅茶苦茶サーボに詳しい記事 nomolkのブログ 様
No comments:
Post a Comment