第一部分:3-5分钟短视频
视频链接:视频
第二部分:任务实现详情
(1)任务/项目介绍
①项目简介
Follow me活动是DigiKey联合EEWorld发起的大型开发板体验活动,每期技术大咖推荐可玩性与可学性较强的开发板/仪器套件,带着大家实际操作,参与者完成任务即返京东卡。
活动旨在带着电子爱好者一起学习实用的电子技术知识,一起积攒DIY经验,一起变成更好的自己!
②物料清单
1.购买的物料:
Adafruit Circuit Playground Express(核心板)
JOY FEATHERWING (摇杆按键控制板)
NEOKEY FEATHERWING (机械按键控制板)
2.非购买的物料:
NEC码红外无线通信控制板
Adafruit ESP32-S3 TFT Feather开发板
③设计思路
用Adafruit ESP32-S3 TFT Feather开发板、 NEOKEY FEATHERWING、 JOY FEATHERWING 和 NEC码红外无线通信控制板 组成一个红外遥控器,可以实现远程控制本期FollowMe的开发板(板载红外收发管)。通过NEC协议实现两个开发板的通信。
(2)软件流程图
(3)各任务对应的主要代码片段、功能展示及图文说明(每个任务需要包含至少一张对应的实物图)
入门任务(必做):开发环境搭建,板载LED点亮
主要代码:
import time
import board
import digitalio
led = digitalio.DigitalInOut(board.D13)
led.switch_to_output()
buttonA = digitalio.DigitalInOut(board.BUTTON_A)
buttonA.switch_to_input(pull=digitalio.Pull.DOWN)
buttonB = digitalio.DigitalInOut(board.BUTTON_B)
buttonB.switch_to_input(pull=digitalio.Pull.DOWN)
while True:
if buttonA.value:
led.value = True
elif buttonB.value:
led.value = False
time.sleep(0.01)
改编自Adafruit官网,按下A键led打开,按下B键关闭
基础任务一(必做):控制板载炫彩LED,跑马灯点亮和颜色变换
import time
import board
from rainbowio import colorwheel
import neopixel
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.2, auto_write=False)
color_chase_demo = 1
flash_demo = 1
rainbow_demo = 1
rainbow_cycle_demo = 1
def color_chase(color, wait):
for i in range(10):
pixels[i] = color
time.sleep(wait)
pixels.show()
time.sleep(0.5)
def rainbow_cycle(wait):
for j in range(255):
for i in range(10):
rc_index = (i * 256 // 10) + j * 5
pixels[i] = colorwheel(rc_index & 255)
pixels.show()
time.sleep(wait)
def rainbow(wait):
for j in range(255):
for i in range(len(pixels)):
idx = int(i + j)
pixels[i] = colorwheel(idx & 255)
pixels.show()
time.sleep(wait)
RED = (255, 0, 0)
YELLOW = (255, 150, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
WHITE = (255, 255, 255)
OFF = (0, 0, 0)
while True:
if color_chase_demo:
color_chase(RED, 0.1)
color_chase(YELLOW, 0.1)
color_chase(GREEN, 0.1)
color_chase(CYAN, 0.1)
color_chase(BLUE, 0.1)
color_chase(PURPLE, 0.1)
color_chase(OFF, 0.1)
if flash_demo:
pixels.fill(RED)
pixels.show()
time.sleep(1)
pixels.fill(GREEN)
pixels.show()
time.sleep(1)
pixels.fill(BLUE)
pixels.show()
time.sleep(1)
pixels.fill(WHITE)
pixels.show()
time.sleep(1)
if rainbow_cycle_demo:
rainbow_cycle(0.05)
if rainbow_demo:
rainbow(0.05)
实现四种灯光效果
基础任务二(必做):监测环境温度和光线,通过板载LED展示舒适程度
import time
import neopixel
import adafruit_thermistor
import board
thermistor = adafruit_thermistor.Thermistor(
board.TEMPERATURE, 10000, 10000, 25, 3950)
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.2, auto_write=False)
warn = False
de_warn = False
while True:
temp_c = thermistor.temperature
print("Temperature is: %f C " % (temp_c))
if temp_c > 30 and not warn:
warn = True
de_warn = False
if temp_c < 30 and not de_warn:
de_warn = True
warn = False
if warn:
pixels.fill((15,0,0))
pixels.show()
if de_warn :
pixels.fill((0,0,0))
pixels.show()
time.sleep(0.25)
代码中设置了温度界限为30度,超过则红灯亮,否则熄灭。视频中可以看到通过打火机升高温度,红灯亮起,移开火源,红灯熄灭。
基础任务三(必做):接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声音报警
import board
import digitalio
import analogio
import time
import math
from adafruit_circuitplayground.express import cpx
ir_tx = digitalio.DigitalInOut(board.IR_TX)
ir_tx.direction = digitalio.Direction.OUTPUT
proximity = analogio.AnalogIn(board.IR_PROXIMITY)
def detect_invade_vel():
ir_tx.value = True
time.sleep(0.001)
ir_tx.value = False
proximity_value = proximity.value
print("proximity value: %d" % proximity_value)
max_value = 42000
min_value = 20000
invade_step = (max_value - min_value) / 11
invade_level = math.floor((proximity_value - min_value) / invade_step)
return invade_level
while True:
invade_level = detect_invade_vel()
if invade_level > 0:
for item in range(invade_level):
cpx.pixels[item] = (math.floor(1.5*invade_level),math.floor(15-1.5*invade_level),0)
cpx.play_tone(262, 0.55-0.05*invade_level)
cpx.pixels.fill((0, 0, 0))
time.sleep(0.05)
接近报警器,距离越近,颜色越红(由绿到红),亮灯数量越多,同时报警频率越高。
进阶任务(必做):制作不倒翁——展示不倒翁运动过程中的不同灯光效果
这个任务需要用到加速度传感器,为了实现不倒翁,我的设计是将原始加速度数值转换为极坐标,再根据极坐标的角度判断应该亮哪个灯,根据极坐标的ρ计算颜色(由绿到红),同时设置容差,防止在静止状态的频繁跳变。
#将笛卡尔坐标系向极坐标系转化
def Cartesian2Polar(cor = (0,0)):
r = math.sqrt(cor[0]*cor[0]+cor[1]*cor[1])
if r == 0:
return None,None
else:
if cor[0]<0:
theta = math.pi - math.asin(cor[1]/r)
else:
theta = math.asin(cor[1]/r)
if theta<0:
theta += 2*math.pi
return r,theta*6/math.pi
完整代码:
import math
import time
from adafruit_circuitplayground import cp
cp.pixels.auto_write = False
cp.pixels.brightness = 0.3
def Cartesian2Polar(cor = (0,0)):
r = math.sqrt(cor[0]*cor[0]+cor[1]*cor[1])
if r == 0:
return None,None
else:
if cor[0]<0:
theta = math.pi - math.asin(cor[1]/r)
else:
theta = math.asin(cor[1]/r)
if theta<0:
theta += 2*math.pi
return r,theta*6/math.pi
def neo_be_light(polar_msg, mode, tolerance = 2):
degree = 90/9.8*(polar_msg[0]-tolerance)
if degree>90:
degree = 90
l_light = math.floor(float(polar_msg[1]))
r_light = math.ceil(float(polar_msg[1]))
if mode == "multi":
if polar_msg[1] - l_light < 0.2:
belight = (l_light - 1,l_light,r_light)
elif r_light - polar_msg[1] > 0.2:
belight = (l_light,r_light,r_light + 1)
else:
belight = (l_light,r_light)
elif mode == "single":
belight = r_light if (l_light - float(polar_msg[1])) > (r_light - float(polar_msg[1])) else l_light
return degree,belight
#返回倾斜程度(角度制)和要点亮的灯的弧度值
def judge_neopixle(data, degree):
if data > -1 and data < 3 :
cp.pixels[data + 7] = (15-15/degree*90, 15/degree*90, 0)
elif data == 3:
pass
elif data >3 and data < 9:
cp.pixels[data - 4] = (15-15/degree*90, 15/degree*90, 0)
elif data == 9:
pass
elif data > 9 and data < 12:
cp.pixels[data - 5] = (15-15/degree*90, 15/degree*90, 0)
elif data == 12:
cp.pixels[7] = (15-15/degree*90, 15/degree*90, 0)
elif data == 13:
cp.pixels[6] = (15-15/degree*90, 15/degree*90, 0)
else:
print("data error")
def tumbler(mode = "multi", tolerance = 2): #opt: "multi", "single"
r,area = Cartesian2Polar(cp.acceleration)
if not(r == None and area == None):
if r < tolerance:
cp.pixels.fill((15, 15, 15))
else:
a,b=neo_be_light(Cartesian2Polar(cp.acceleration), mode, tolerance)
cp.pixels.fill((0, 0, 0))
if isinstance(b,int):
judge_neopixle(b, a)
else:
for item in b:
judge_neopixle(item, a)
cp.pixels.show()
time.sleep(0.1)
while True:
tumbler( "single", 1)
此外我还设置了两种模式:单灯光模式(”single“)和多灯光模式(”multi“),以及参数容差(tolerance),方便设置不倒翁效果
创意任务一:有创意的可穿戴装饰——可结合多种传感器和灯光效果展示
搭配器件: Adafruit Circuit Playground Express、挂饰、自制遥控器
本任务核心是使用红外传感器,其他代码基本已经在上面出现过,故只放红外传感器代码:
import pulseio
import board
import adafruit_irremote
pulsein = pulseio.PulseIn(board.IR_RX, maxlen=120, idle_state=True)
decoder = adafruit_irremote.GenericDecode()
while True:
pulses = decoder.read_pulses(pulsein)
try:
do_msg_neokey(decoder.decode_bits(pulses)[2])
except adafruit_irremote.IRNECRepeatException: # unusual short code!
print("NEC repeat!")
except adafruit_irremote.IRDecodeException as e: # failed to decode
print("Failed to decode: ", e.args)
效果:
(4)对本活动的心得体会
感谢EEworld和Digikey得捷电子提供的活动平台,使我在玩板子的同时学到了很多,例如管理python内存,因为在嵌入式平台,内存资源极为有限。完成任务的过程中,多次遇到Memory Error,最终查阅资料,重新了解python,了解circuitpython,最终解决问题,实现功能
建议这样的活动继续办下去,让更多的人入门电子工程师。
第三部分:可编译下载的代码
源代码:代码