哈Ha!本文介绍了将基于esp8266 MK 的自推式平台(带有micropython)升级为配备了扫描超声波障碍传感器,闪烁的LED,启动/停止按钮以及集成的Web服务器的简单机器人的过程,这是培训项目的一部分。KDPV:
因此,前两个部分描述了通过wifi网络界面控制的自推式平台的制造。当前阶段的任务是为该超声平台配备HC-SR04传感器,并增加离线工作的能力。首先-机械部分:有必要将传感器和伺服器固定在外壳中,设计(我为此使用FreeCAD)并制造缺少的部分:
然后-电气部分:绘制电路(例如在Fritzing中)并根据其进行切换:
之后,试着让一切飞起来...由于我希望并行执行机器人程序的某些功能(例如,扫描到障碍物的距离的过程和运动功能),因此我不得不投入异步模块的功能。与ASYNCIO更细致的工作中描述这个和这个文章。例如,要使LED闪烁,可以应用这样的协程,实际上与同步没有什么不同:import uasyncio as asyncio
from machine import Pin
syst_led = Pin(16, Pin.OUT)
async def blink_led(led, interval_ms):
led_val = True
while True:
led_val = not(led_val)
led_state = led.value(int(led_val))
await asyncio.sleep_ms(interval_ms)
loop = asyncio.get_event_loop()
loop.create_task(blink_led(syst_led, interval_ms=250))
loop.run_forever()
不同之处在于,可以同时启动执行不同任务的此类协程(资源将由调度程序分配)。因此,我们将编写协程以测量距离和扫描扇区,并编写一个用于开始或停止扫描的硬件中断(按钮)的回调。在最简单的情况下,协程之间的状态转移可以通过全局变量完成:按钮的回调:from machine import Pin
run_flag = False
button = Pin(15, Pin.IN, Pin.PULL_UP)
def callback(p):
global run_flag
run_flag = not(run_flag)
print('set run_flag', run_flag, p)
button.irq(trigger=Pin.IRQ_FALLING, handler=callback)
距离测量:import uasyncio as asyncio
from utime import sleep, sleep_us
from machine import Pin, time_pulse_us
trig=Pin(12, Pin.OUT)
echo=Pin(13, Pin.IN)
async def async_measure_range():
echo_timeout_us=500*2*30
trig.off()
sleep_us(5)
trig.on()
sleep_us(10)
trig.off()
try:
pulse_time = time_pulse_us(echo, 1, echo_timeout_us)
except:
pass
dist = (pulse_time / 2) / 29.1
return dist
扇区扫描(调用测距协程):import uasyncio as asyncio
from machine import Pin, PWM
pos_actual = 75
dist_cm = 50
p14 = Pin(14, Pin.OUT)
servo = PWM(p14, freq=50)
async def radar_scan(interval_ms):
pos_list = [45,75,105,75]
global pos_actual
global dist_cm
while True:
if run_flag:
for pos in pos_list:
servo.duty(pos)
await asyncio.sleep_ms(interval_ms)
dist_cm = await async_measure_range()
pos_actual = pos
print('pos_actual = %s, dist_cm = %s' % (pos_actual, dist_cm)
elif not run_flag:
await asyncio.sleep(0)
loop = asyncio.get_event_loop(
loop.create_task(radar_scan(interval_ms=250))
loop.run_forever()
在调试传感器的过程中,有时会给出负距离值。事实证明,“电子学是不良接触的科学”,当转动传感器时,电缆被拔出并且接触消失。仍然需要根据扫描结果来固定操作选择的逻辑:avoid_left = False
avoid_right = False
avoid_backward = False
async def make_decision(interval_ms, avoid_limit_cm):
global avoid_left
global avoid_right
global avoid_backward
while True:
if run_flag:
if pos_actual == 45 and dist_cm < avoid_limit_cm :
avoid_left = True
if debug : print('avoid_left = %s' % avoid_left)
elif pos_actual == 45 and dist_cm >= avoid_limit_cm :
avoid_left = False
if debug : print('avoid_left = %s' % avoid_left)
elif pos_actual == 75 and dist_cm < avoid_limit_cm*1.25 :
avoid_backward = True
if debug : print('avoid_backward = %s' % avoid_backward)
elif pos_actual == 75 and dist_cm >= avoid_limit_cm*1.25 :
avoid_backward = False
if debug : print('avoid_backward = %s' % avoid_backward)
elif pos_actual == 105 and dist_cm < avoid_limit_cm :
avoid_right = True
if debug : print('avoid_right = %s' % avoid_right)
elif pos_actual == 105 and dist_cm >= avoid_limit_cm :
avoid_right = False
if debug : print('avoid_right = %s' % avoid_right)
if debug : print('pos = %s, dist_cm = %s' % (pos_actual,dist_cm))
await asyncio.sleep_ms(interval_ms)
elif not run_flag:
await asyncio.sleep(0)
loop.create_task(make_decision(interval_ms=250, avoid_limit_cm=15))
电机功能:from random import getrandbits
async def moving(interval_ms):
while True:
if run_flag:
if avoid_backward :
print('avoid_backward = %s' % avoid_backward)
await backward(interval_ms*2)
if bool(getrandbits(1)) :
await right_rotate(interval_ms+getrandbits(3)*100)
await stop_all()
else:
await left_rotate(interval_ms+getrandbits(3)*100)
await stop_all()
elif avoid_left :
print('avoid_left = %s' % avoid_left)
await left_turn(interval_ms)
elif avoid_right :
print('avoid_right = %s' % avoid_right)
await right_turn(interval_ms)
else:
print('move_forward')
await forward(interval_ms)
await asyncio.sleep_ms(interval_ms)
elif not run_flag:
await stop_all()
await asyncio.sleep(0)
loop.create_task(moving(interval_ms=1000))
和电机控制
p5 = Pin(5, Pin.OUT)
p4 = Pin(4, Pin.OUT)
revrs_L = Pin(0, Pin.OUT, value=0)
revrs_R = Pin(2, Pin.OUT, value=0)
motor_L = PWM(p5, freq=1000, duty=0)
motor_R = PWM(p4, freq=1000, duty=0)
speed = 1023
async def stop_all():
revrs_L.value(0)
motor_L.duty(0)
revrs_R.value(0)
motor_R.duty(0)
async def forward(interval_ms):
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def backward(interval_ms):
revrs_L.value(1)
motor_L.duty(speed)
revrs_R.value(1)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def right_rotate(interval_ms):
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(1)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def left_rotate(interval_ms):
revrs_L.value(1)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def right_turn(interval_ms):
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(0)
await asyncio.sleep_ms(interval_ms)
async def left_turn(interval_ms):
revrs_L.value(0)
motor_L.duty(0)
revrs_R.value(0)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
以及一个闪烁的LED以控制程序正在运行:async def blink_led(led, interval_ms):
led_val = True
while True:
if run_flag:
led_val = not(led_val)
led_state = led.value(int(led_val))
await asyncio.sleep_ms(interval_ms)
elif not run_flag:
await asyncio.sleep(0)
loop.create_task(blink_led(syst_led, interval_ms=250))
之后,仅收集所有这些完好无损import gc
import uasyncio as asyncio
from utime import sleep, sleep_us
from machine import Pin, PWM, time_pulse_us
from random import getrandbits
p5 = Pin(5, Pin.OUT)
p4 = Pin(4, Pin.OUT)
revrs_L = Pin(0, Pin.OUT, value=0)
revrs_R = Pin(2, Pin.OUT, value=0)
motor_L = PWM(p5, freq=1000, duty=0)
motor_R = PWM(p4, freq=1000, duty=0)
speed = 1023
p14 = Pin(14, Pin.OUT)
servo = PWM(p14, freq=50)
button = Pin(15, Pin.IN, Pin.PULL_UP)
syst_led = Pin(16, Pin.OUT)
trig=Pin(12, Pin.OUT)
echo=Pin(13, Pin.IN)
run_flag = False
avoid_left = False
avoid_right = False
avoid_backward = False
pos_actual = 75
dist_cm = 50
debug = False
def callback(p):
global run_flag
run_flag = not(run_flag)
print('set run_flag', run_flag, p)
def stop_all_sync():
revrs_L.value(0)
motor_L.duty(0)
revrs_R.value(0)
motor_R.duty(0)
async def stop_all():
revrs_L.value(0)
motor_L.duty(0)
revrs_R.value(0)
motor_R.duty(0)
async def forward(interval_ms):
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def backward(interval_ms):
revrs_L.value(1)
motor_L.duty(speed)
revrs_R.value(1)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def right_rotate(interval_ms):
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(1)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def left_rotate(interval_ms):
revrs_L.value(1)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def right_turn(interval_ms):
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(0)
await asyncio.sleep_ms(interval_ms)
async def left_turn(interval_ms):
revrs_L.value(0)
motor_L.duty(0)
revrs_R.value(0)
motor_R.duty(speed)
await asyncio.sleep_ms(interval_ms)
async def moving(interval_ms):
while True:
if run_flag:
if avoid_backward :
print('avoid_backward = %s' % avoid_backward)
await backward(interval_ms*2)
if bool(getrandbits(1)) :
await right_rotate(interval_ms+getrandbits(3)*100)
await stop_all()
else:
await left_rotate(interval_ms+getrandbits(3)*100)
await stop_all()
elif avoid_left :
print('avoid_left = %s' % avoid_left)
await left_turn(interval_ms)
elif avoid_right :
print('avoid_right = %s' % avoid_right)
await right_turn(interval_ms)
else:
print('move_forward')
await forward(interval_ms)
await asyncio.sleep_ms(interval_ms)
elif not run_flag:
await stop_all()
await asyncio.sleep(0)
async def blink_led(led, interval_ms):
led_val = True
while True:
if run_flag:
led_val = not(led_val)
led_state = led.value(int(led_val))
await asyncio.sleep_ms(interval_ms)
elif not run_flag:
await asyncio.sleep(0)
async def async_measure_range():
echo_timeout_us=500*2*30
trig.off()
sleep_us(5)
trig.on()
sleep_us(10)
trig.off()
try:
pulse_time = time_pulse_us(echo, 1, echo_timeout_us)
except:
pass
dist = (pulse_time / 2) / 29.1
return dist
async def make_decision(interval_ms, avoid_limit_cm):
global avoid_left
global avoid_right
global avoid_backward
while True:
if run_flag:
if pos_actual == 45 and dist_cm < avoid_limit_cm :
avoid_left = True
if debug : print('avoid_left = %s' % avoid_left)
elif pos_actual == 45 and dist_cm >= avoid_limit_cm :
avoid_left = False
if debug : print('avoid_left = %s' % avoid_left)
elif pos_actual == 75 and dist_cm < avoid_limit_cm*1.25 :
avoid_backward = True
if debug : print('avoid_backward = %s' % avoid_backward)
elif pos_actual == 75 and dist_cm >= avoid_limit_cm*1.25 :
avoid_backward = False
if debug : print('avoid_backward = %s' % avoid_backward)
elif pos_actual == 105 and dist_cm < avoid_limit_cm :
avoid_right = True
if debug : print('avoid_right = %s' % avoid_right)
elif pos_actual == 105 and dist_cm >= avoid_limit_cm :
avoid_right = False
if debug : print('avoid_right = %s' % avoid_right)
if debug : print('pos = %s, dist_cm = %s' % (pos_actual,dist_cm))
await asyncio.sleep_ms(interval_ms)
elif not run_flag:
await asyncio.sleep(0)
async def radar_scan(interval_ms):
pos_list = [45,75,105,75]
global pos_actual
global dist_cm
while True:
if run_flag:
for pos in pos_list:
servo.duty(pos)
await asyncio.sleep_ms(interval_ms)
dist_cm = await async_measure_range()
pos_actual = pos
elif not run_flag:
await asyncio.sleep(0)
stop_all_sync()
print('Move sensor to initial position...')
servo.duty(75)
sleep(1)
print('Waiting for start button...')
gc.enable()
button.irq(trigger=Pin.IRQ_FALLING, handler=callback)
loop = asyncio.get_event_loop()
loop.create_task(blink_led(syst_led, interval_ms=250))
loop.create_task(radar_scan(interval_ms=250))
loop.create_task(make_decision(interval_ms=250, avoid_limit_cm=15))
loop.create_task(moving(interval_ms=1000))
loop.run_forever()
并签入工作:但是,我想保留通过网页进行手动控制的可能性。为此,在单独的协程中添加一个简单的Web服务器:async def web_page(request):
global auto_run_flag
motor_state="Stopped"
if request.find('GET /?forward') > 0:
motor_state="Going Forward"
auto_run_flag = False
forward_sync()
elif request.find('GET /?left_rotate') > 0:
motor_state="Rotate Left"
auto_run_flag = False
left_rotate_sync()
elif request.find('GET /?right_rotate') > 0:
motor_state="Rotate Right"
auto_run_flag = False
right_rotate_sync()
elif request.find('GET /?left_turn') > 0:
motor_state="Turn Left"
auto_run_flag = False
left_turn_sync()
elif request.find('GET /?right_turn') > 0:
motor_state="Turn Right"
auto_run_flag = False
right_turn_sync()
elif request.find('GET /?backward') > 0:
motor_state="Going Backward"
auto_run_flag = False
backward_sync()
elif request.find('GET /?stop') > 0:
motor_state="Stopped"
auto_run_flag = False
stop_all_sync()
elif request.find('GET /?auto') > 0:
auto_run_flag = not auto_run_flag
if auto_run_flag :
motor_state="Autopilot"
elif not auto_run_flag :
motor_state="Stopped"
stop_all_sync()
html = """<html><head><title>RoboTank WEB</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"> <style>
html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}
.button{display: inline-block; background-color: #33c080; border: none;
border-radius: 4px; color: white; text-decoration: none; font-size: 30px; width:100%}
.button2{background-color: #4286f4; width:30%}
.button3{background-color: #eb2b10; width:35%}
.button4{background-color: #8386f4; width:44%}
</style></head>
<body> <h1>RoboTank WEB</h1>
<p>Status : <strong>""" + motor_state + """</strong></p>
<p><a href='/?forward'><button class="button">Forward</button></a></p>
<p><a href='/?left_turn'><button class="button button2">LEFT</button></a>
<a href='/?stop'><button class="button button3">STOP</button></a>
<a href='/?right_turn'><button class="button button2">RIGHT</button></a>
<p><a href='/?backward'><button class="button">Backward</button></a></p>
<p><a href='/?left_rotate'><button class="button button4">L-rotate</button></a>
<a href='/?right_rotate'><button class="button button4">R-rotate</button></a></p>
<p><a href='/?auto'><button class="button button3">AUTO</button></a></p>
</body></html>"""
return html
async def web_handler(reader, writer):
try:
request = str(await reader.read(1024))
header = """HTTP/1.1 200 OK\nContent-Type: text/html\nConnection: close\n\n"""
response = await web_page(request)
await writer.awrite(header)
await writer.awrite(response)
await writer.aclose()
print("Finished processing request")
except Exception as e:
print(e)
async def tcp_server(host, port):
server = await asyncio.start_server(web_handler, host, port)
loop.create_task(tcp_server('0.0.0.0', 80))
并具有同步运动功能,用于手动控制。def stop_all_sync():
revrs_L.value(0)
motor_L.duty(0)
revrs_R.value(0)
motor_R.duty(0)
def backward_sync():
revrs_L.value(1)
motor_L.duty(speed)
revrs_R.value(1)
motor_R.duty(speed)
def forward_sync():
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(speed)
def right_rotate_sync():
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(1)
motor_R.duty(speed)
def left_rotate_sync():
revrs_L.value(1)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(speed)
def right_turn_sync():
revrs_L.value(0)
motor_L.duty(speed)
revrs_R.value(0)
motor_R.duty(0)
def left_turn_sync():
revrs_L.value(0)
motor_L.duty(0)
revrs_R.value(0)
motor_R.duty(speed)
界面外观:
最终版本的测试:资料来源在这里。灵感来源:docs.micropython.org/en/latest/library/uasyncio.htmlhabr.com/en/post/484446habr.com/en/post/337420habr.com/en/post/484472github.com/peterhinch /micropython-async/blob/master/TUTORIAL.mdgithub.com/rsc1975/micropython-hcsr04medium.com/@pgjones/an-asyncio-socket-tutorial-5e6f3308b8b0