5、Pico Robot 机器人课程
5.1 小车前进
注意:电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机结合进行实验。
2. 了解电机的使用。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机,注意,运行例程会让小车向前跑1s,请避免前方有台阶,或者拿起小车以免损坏。
在小车的扩展板上我们集成了电机驱动电路,只需要使用PWM即可控制电机方向和转速,通过调整PWM的占空比,高电平时间越长电机速度越快。在电机内部,通过线圈将电流变成磁场,在磁铁的作用下实现电机的转动。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 1.小车前进.py
1 from pico_car import pico_car 2 import time 3 4 Motor = pico_car() 5 #Car forward,parameter(Left motor speed,Right motor speed),speed 0-255 6 Motor.Car_Run(255,255) 7 time.sleep(1) 8 #Car stop 9 Motor.Car_Stop()
from pico_car import pico_car
使用pico_car 的pico_car,这是我们封装好的电机驱动库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
Motor = pico_car()
初始化电机驱动。
Motor.Car_Run(255,255)
控制小车前进,速度设置为255,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Stop()
控制小车停止。
四、实验现象
程序下载完成之后,小车会以最大速度向前前进1s,然后停止。
5.2 小车花式动作
在上一节,我们实现了小车的前进,在这一节我们会让小车前后左右运行。
注意:电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机结合进行实验。
2. 了解电机的使用。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机,注意,运行例程会让小车前后左右运动,请在空旷的地方,或者拿起小车运行程序,以免损坏。
在小车的扩展板上我们集成了电机驱动电路,只需要使用PWM即可控制电机方向和转速,通过调整PWM的占空比,高电平时间越长电机速度越快。在电机内部,通过线圈将电流变成磁场,在磁铁的作用下实现电机的转动。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 2.小车花式动作.py
1 from pico_car import pico_car 2 import time 3 4 Motor = pico_car() 5 #Car forward,parameter(Left motor speed,Right motor speed),speed 0-255 6 Motor.Car_Run(255,255) 7 time.sleep(1) 8 #Car back 9 Motor.Car_Back(255,255) 10 time.sleep(1) 11 #left 12 Motor.Car_Run(0,255) 13 time.sleep(1) 14 #right 15 Motor.Car_Run(255,0) 16 time.sleep(1) 17 #Turn left 18 Motor.Car_Left(255,255) 19 time.sleep(1) 20 #Turn right 21 Motor.Car_Right(255,255) 22 time.sleep(1) 23 #Car stop 24 Motor.Car_Stop()
from pico_car import pico_car
使用pico_car 的pico_car,这是我们封装好的电机驱动库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
Motor = pico_car()
初始化电机驱动。
Motor.Car_Run(255,255)
控制小车前进,速度设置为255,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Stop()
控制小车停止。
Motor.Car_Back(255,255)
控制小车后退。
Motor.Car_Run(0,255)
控制小车左转。
Motor.Car_Run(255,0)
控制小车右转。
Motor.Car_Left(255,255)
控制小车左旋。
Motor.Car_Right(255,255)
控制小车右旋。
四、实验现象
程序下载完成之后,小车会以最大速度向前前进1s,然后向后1s,左转1s,右转1s,左旋1s,右旋1s,最后停止。
5.3 小车唱歌跳舞
在上一节,我们实现了小车前后左右运行,在这一节我们把运动和3.3节的蜂鸣器音乐播放结合起来。
注意:电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、蜂鸣器、可编程RGB灯结合进行实验,在这一节我们会让小车一边运行一边播放音乐。
2. 了解电机和蜂鸣器的使用。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、可编程RGB灯和蜂鸣器,注意,运行例程会让小车前后左右运动,请在空旷的地方,或者拿起小车运行程序,以免损坏。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 3.小车唱歌跳舞.py
1 from pico_car import pico_car, ws2812b 2 import time 3 from machine import Pin, PWM 4 5 Motor = pico_car() 6 # set buzzer pin 7 BZ = PWM(Pin(22)) 8 BZ.freq(1000) 9 num_leds = 8 # Number of NeoPixels 10 # Pin where NeoPixels are connected 11 pixels = ws2812b(num_leds, 0) 12 # Set all led off 13 pixels.fill(0,0,0) 14 pixels.show() 15 # Initialize music 16 CM = [0, 330, 350, 393, 441, 495, 556, 624] 17 song = [CM[1],CM[1],CM[5],CM[5],CM[6],CM[6],CM[5], 18 CM[4],CM[4],CM[3],CM[3],CM[2],CM[2],CM[1],] 19 beat = [ 0.5,0.5,0.5,0.5,0.5,0.5,1,0.5,0.5,0.5,0.5,0.5,0.5,1,] 20 # music 21 def music_Run(): 22 for i in range(0,2): 23 BZ.duty_u16(500) 24 BZ.freq(song[i]) 25 time.sleep(beat[i]) 26 BZ.duty_u16(0) 27 time.sleep(0.01) 28 def music_Back(): 29 for i in range(2,4): 30 BZ.duty_u16(500) 31 BZ.freq(song[i]) 32 time.sleep(beat[i]) 33 BZ.duty_u16(0) 34 time.sleep(0.01) 35 def music_Left(): 36 for i in range(4,7): 37 BZ.duty_u16(500) 38 BZ.freq(song[i]) 39 time.sleep(beat[i]) 40 BZ.duty_u16(0) 41 time.sleep(0.01) 42 def music_Right(): 43 for i in range(7,9): 44 BZ.duty_u16(500) 45 BZ.freq(song[i]) 46 time.sleep(beat[i]) 47 BZ.duty_u16(0) 48 time.sleep(0.01) 49 def music_TLeft(): 50 for i in range(9,11): 51 BZ.duty_u16(500) 52 BZ.freq(song[i]) 53 time.sleep(beat[i]) 54 BZ.duty_u16(0) 55 time.sleep(0.01) 56 def music_TRight(): 57 for i in range(11,14): 58 BZ.duty_u16(500) 59 BZ.freq(song[i]) 60 time.sleep(beat[i]) 61 BZ.duty_u16(0) 62 time.sleep(0.01) 63 #Car forward 64 Motor.Car_Run(255,255) 65 for i in range(num_leds): 66 pixels.set_pixel(i,255,255,0) 67 pixels.show() 68 music_Run() 69 #Car back 70 Motor.Car_Back(255,255) 71 for i in range(num_leds): 72 pixels.set_pixel(i,0,255,255) 73 pixels.show() 74 music_Back() 75 #left 76 Motor.Car_Run(0,255) 77 for i in range(num_leds): 78 pixels.set_pixel(i,255,0,255) 79 pixels.show() 80 music_Left() 81 #right 82 Motor.Car_Run(255,0) 83 for i in range(num_leds): 84 pixels.set_pixel(i,255,0,0) 85 pixels.show() 86 music_Right() 87 #Turn left 88 Motor.Car_Left(255,255) 89 for i in range(num_leds): 90 pixels.set_pixel(i,0,255,0) 91 pixels.show() 92 music_TLeft() 93 #Turn right 94 Motor.Car_Right(255,255) 95 for i in range(num_leds): 96 pixels.set_pixel(i,0,0,255) 97 pixels.show() 98 music_TRight() 99 #Car stop 100 Motor.Car_Stop() 101 for i in range(num_leds): 102 pixels.set_pixel(i,0,0,0) 103 pixels.show()
from pico_car import pico_car, ws2812b
使用pico_car 的pico_car和 ws2812b,封装了电机驱动和RGB灯库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, PWM
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin和PWM的库。
Motor = pico_car()
初始化电机驱动。
Motor.Car_Run(255,255)
控制小车前进,速度设置为255,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Stop()
控制小车停止。
Motor.Car_Back(255,255)
控制小车后退。
Motor.Car_Run(0,255)
控制小车左转。
Motor.Car_Run(255,0)
控制小车右转。
Motor.Car_Left(255,255)
控制小车左旋。
Motor.Car_Right(255,255)
控制小车右旋。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(i,255,255,0)
使用for循环把所有车灯设置为黄色。
music_Run()
在这个函数中我们把之前蜂鸣器的播放音乐切成6个部分,每一部分分别运行小车不同的动作。
四、实验现象
程序下载完成之后,小车会踩点音乐,先前进并且RGB灯亮黄色,然后后退RGB灯亮青色,左转RGB灯亮紫色,右转RGB灯亮红色,左旋RGB灯亮绿色,右旋RGB灯亮蓝色,最后停止并关闭RGB灯。
5.4 巡线小车
在4.3节,我们把巡线传感器的检测结果显示在OLED上,这一节我们将利用巡线传感器来实现控制小车巡线。
注意:巡线传感器会受到光线影响,请在室内无太阳光照的环境下运行程序,以减少太阳光对巡线传感器的干扰。并且在巡线时需保持室内光线充足。
电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、巡线传感器、可编程RGB灯结合实现巡线。
2. 了解如何通过巡线传感器控制小车巡线。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、巡线传感器、可编程RGB灯,并且需要巡线地图
在程序中我们通过判断每个巡线传感器接收到的数据值,将结果分成七种不同的情况,确定小车的运行状态,从而实现小车巡线。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 4.巡线小车.py
1 from machine import Pin, I2C 2 from pico_car import pico_car, ws2812b, SSD1306_I2C 3 import time 4 5 Motor = pico_car() 6 num_leds = 8 # Number of NeoPixels 7 # Pin where NeoPixels are connected 8 pixels = ws2812b(num_leds, 0) 9 # Set all led off 10 pixels.fill(0,0,0) 11 pixels.show() 12 #initialization oled 13 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 14 oled = SSD1306_I2C(128, 32, i2c) 15 #Define the tracking sensor, 1-4 from left to right 16 #recognize that black is 0 and white is 1 17 #Tracing_1 Tracing_2 Tracing_3 Tracing_4 18 # 2 3 4 5 19 Tracing_1 = machine.Pin(2, machine.Pin.IN) 20 Tracing_2 = machine.Pin(3, machine.Pin.IN) 21 Tracing_3 = machine.Pin(4, machine.Pin.IN) 22 Tracing_4 = machine.Pin(5, machine.Pin.IN) 23 24 while True: 25 26 #四路循迹引脚电平状态 27 #Four channel tracking pin level status 28 # 0 0 X 0 29 # 1 0 X 0 30 # 0 1 X 0 31 #处理右锐角和右直角的转动 32 #Handle the rotation of right acute angle and right right right angle 33 if (Tracing_1.value() == 0 or Tracing_2.value() == 0) and Tracing_4.value() == 0: 34 Motor.Car_Right(120,120) 35 for i in range(num_leds): 36 pixels.set_pixel(i,0,255,0) 37 oled.text('Turn Right', 0, 0) 38 #time.sleep(0.08) 39 40 #四路循迹引脚电平状态 41 #Four channel tracking pin level status 42 # 0 X 0 0 43 # 0 X 0 1 44 # 0 X 1 0 45 #处理左锐角和左直角的转动 46 #Handle the rotation of left sharp angle and left right angle 47 elif Tracing_1.value() == 0 and (Tracing_3.value() == 0 or Tracing_4.value() == 0): 48 Motor.Car_Left(120,120) 49 for i in range(num_leds): 50 pixels.set_pixel(i,0,0,255) 51 oled.text('Turn Left', 0, 0) 52 #time.sleep(0.08) 53 54 # 0 X X X 55 #最左边检测到 56 #Leftmost detected 57 elif Tracing_1.value() == 0: 58 Motor.Car_Left(100,100) 59 for i in range(num_leds): 60 pixels.set_pixel(i,0,0,255) 61 oled.text('Turn Left', 0, 0) 62 63 # X X X 0 64 #最右边检测到 65 #Rightmost detected 66 elif Tracing_4.value() == 0: 67 Motor.Car_Right(100,100) 68 for i in range(num_leds): 69 pixels.set_pixel(i,0,255,0) 70 oled.text('Turn Right', 0, 0) 71 72 # X 0 1 X 73 #处理左小弯 74 #Deal with small left bend 75 elif Tracing_2.value() == 0 and Tracing_3.value() == 1: 76 Motor.Car_Run(0,100) 77 for i in range(num_leds): 78 pixels.set_pixel(i,0,0,255) 79 oled.text('Left', 0, 0) 80 81 # X 1 0 X 82 #处理右小弯 83 #Handle small right bend 84 elif Tracing_2.value() == 1 and Tracing_3.value() == 0: 85 Motor.Car_Run(100,0) 86 for i in range(num_leds): 87 pixels.set_pixel(i,0,255,0) 88 oled.text('Right', 0, 0) 89 90 # X 0 0 X 91 #处理直线 92 #Processing line 93 elif Tracing_2.value() == 0 and Tracing_3.value() == 0: 94 Motor.Car_Run(200,200) 95 for i in range(num_leds): 96 pixels.set_pixel(i,255,255,255) 97 oled.text('Run', 0, 0) 98 99 pixels.show() 100 oled.show() 101 oled.fill(0) 102 #其他时小车保持上一个小车运行状态 103 #In other cases, the trolley keeps the previous trolley running
from pico_car import pico_car, ws2812b, SSD1306_I2C
使用pico_car 的pico_car、ws2812b、SSD1306_I2C,封装了电机驱动和RGB灯、OLED库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin和I2C的库。
Motor = pico_car()
初始化电机驱动。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(i,0,255,0)
使用for循环把所有车灯设置为绿色。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
oled.text('Turn Right', 0, 0)
设置OLED在0,0的位置显示'Turn Right'。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
Motor.Car_Run(200,200)
控制小车前进,速度设置为200,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Run(0,100)
控制小车左转。
Motor.Car_Run(100,0)
控制小车右转。
Motor.Car_Left(100,100)
控制小车左旋。
Motor.Car_Right(100,100)
控制小车右旋。
Tracing_1 = machine.Pin(2, machine.Pin.IN)
初始化引脚2作为巡线传感器1的脚,设置为输入。
Tracing_1.value()
Tracing_1.value()函数用来检测对应端口的电平高低。
四、实验现象
程序下载完成之后,小车会巡黑线移动,并且右转时亮绿灯OLED显示'Turn Right',左转时亮蓝灯OLED显示'Turn Left',右旋时亮绿灯OLED显示'Turn Right',左旋时亮蓝灯OLED显示'Turn Left',前进的时候亮白色灯OLED显示'Run'。
注意:巡线传感器会受到光线影响,请在室内无太阳光照的环境下运行程序,以减少太阳光对巡线传感器的干扰。并且在巡线时需保持室内光线充足,如果运行的时候出现偏离黑线,可以通过调节小车的速度、拐弯延时来提高小车的巡线稳定性。
另外配两个传感器版本的程序:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 4.巡线小车-两个传感器版本.py
5.5 悬崖检测
在上一节,我们使用巡线传感器完成了小车巡黑线,其实位于小车前方的巡线传感器还有更多的功能,这一节我们就用这些巡线传感器来实现悬崖检测。
注意:巡线传感器会受到光线影响,请在室内无太阳光照的环境下运行程序,以减少太阳光对巡线传感器的干扰。并且在巡线时需保持室内光线充足。
电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、巡线传感器、可编程RGB灯结合实现悬崖检测。
2. 了解如何通过巡线传感器控制小车悬崖检测。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、巡线传感器、可编程RGB灯,可以将小车放在没有障碍物的桌子上运行程序,检测到桌子边缘的时候,小车会自动后退。
在程序中我们通过判断每个巡线传感器接收到的数据值,在底下是悬崖时,因为巡线传感器接收管无法收到发射管返回的光,所以和识别到黑色一样数值为0,将结果分成三种不同的情况,确定小车的运行状态,从而实现小车悬崖检测。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 5.悬崖检测.py
1 from machine import Pin, I2C 2 from pico_car import pico_car, ws2812b, SSD1306_I2C 3 import time 4 5 Motor = pico_car() 6 num_leds = 8 # Number of NeoPixels 7 # Pin where NeoPixels are connected 8 pixels = ws2812b(num_leds, 0) 9 # Set all led off 10 pixels.fill(0,0,0) 11 pixels.show() 12 #initialization oled 13 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 14 oled = SSD1306_I2C(128, 32, i2c) 15 #Define the tracking sensor, 1-4 from left to right 16 #recognize that black is 0 and white is 1 17 #Tracing_1 Tracing_2 Tracing_3 Tracing_4 18 # 2 3 4 5 19 Tracing_1 = machine.Pin(2, machine.Pin.IN) 20 Tracing_2 = machine.Pin(3, machine.Pin.IN) 21 Tracing_3 = machine.Pin(4, machine.Pin.IN) 22 Tracing_4 = machine.Pin(5, machine.Pin.IN) 23 24 while True: 25 26 #四路循迹引脚电平状态 27 #Four channel tracking pin level status 28 # 0 0 0 X 29 if Tracing_1.value() == 0 and Tracing_2.value() == 0: 30 for i in range(num_leds): 31 pixels.set_pixel(i,255,0,0) 32 oled.text('Cliff', 0, 0) 33 Motor.Car_Back(150,150) 34 time.sleep(0.5) 35 Motor.Car_Right(150,150) 36 time.sleep(0.5) 37 #time.sleep(0.08) 38 39 #四路循迹引脚电平状态 40 #Four channel tracking pin level status 41 # X 0 0 0 42 elif Tracing_3.value() == 0 and Tracing_4.value() == 0: 43 for i in range(num_leds): 44 pixels.set_pixel(i,255,0,0) 45 oled.text('Cliff', 0, 0) 46 Motor.Car_Back(150,150) 47 time.sleep(0.5) 48 Motor.Car_Left(150,150) 49 time.sleep(0.5) 50 #time.sleep(0.08) 51 52 else: 53 Motor.Car_Run(100,100) 54 for i in range(num_leds): 55 pixels.set_pixel(i,255,255,255) 56 oled.fill(0) 57 58 pixels.show() 59 oled.show() 60 #其他时小车保持上一个小车运行状态 61 #In other cases, the trolley keeps the previous trolley running
from pico_car import pico_car, ws2812b, SSD1306_I2C
使用pico_car 的pico_car、ws2812b、SSD1306_I2C,封装了电机驱动和RGB灯、OLED库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin和I2C的库。
Motor = pico_car()
初始化电机驱动。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(i,255,0,0)
使用for循环把所有车灯设置为红色。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
oled.text('Cliff', 0, 0)
设置OLED在0,0的位置显示'Cliff'。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
Motor.Car_Run(100,100)
控制小车前进,速度设置为100,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Back(255,255)
控制小车后退。
Motor.Car_Left(255,255)
控制小车左旋。
Motor.Car_Right(255,255)
控制小车右旋。
Tracing_1 = machine.Pin(2, machine.Pin.IN)
初始化引脚2作为巡线传感器1的脚,设置为输入。
Tracing_1.value()
Tracing_1.value()函数用来检测对应端口的电平高低。
四、实验现象
程序下载完成之后,小车遇到悬崖时,当传感器1和2检测到悬崖时,小车亮红色灯后退然后右旋,OLED显示'Cliff',当传感器3和4检测到悬崖时,小车亮红色灯后退然后左旋,OLED显示'Cliff',其他情况小车亮白色灯前进。
注意:巡线传感器会受到光线影响,请在室内无太阳光照的环境下运行程序,以减少太阳光对巡线传感器的干扰。并且在巡线时需保持室内光线充足,如果运行的时候出现无法及时停住的情况,可以通过调节小车的速度来提高稳定性。
5.6 超声波避障
在4.4节,我们使用超声波传感器进行测距,并把结果显示在OLED上,在这一节,我们利用这个测距结果来实现超声波避障。
注意:电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、超声波传感器、可编程RGB灯、蜂鸣器结合实现超声波避障。
2. 了解如何通过超声波传感器实现避障。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、超声波传感器、可编程RGB灯、蜂鸣器,可以将小车放在地上,地面障碍物不要太密集,小车遇到障碍物会自动后退。
在程序中我们通过读取超声波传感器数值,对不同的距离数值做出不同的动作。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 6.超声波避障.py
1 import time 2 from machine import Pin, I2C, PWM 3 from pico_car import SSD1306_I2C, ultrasonic, pico_car, ws2812b 4 5 Motor = pico_car() 6 Motor.Car_Stop() 7 num_leds = 8 # Number of NeoPixels 8 # Pin where NeoPixels are connected 9 pixels = ws2812b(num_leds, 0) 10 pixels.fill(0,0,0) 11 pixels.show() 12 # set buzzer pin 13 BZ = PWM(Pin(22)) 14 BZ.freq(1000) 15 # Initialize music 16 CM = [0, 330, 350, 393, 441, 495, 556, 624] 17 #initialization ultrasonic 18 ultrasonic = ultrasonic() 19 #initialization oled 20 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 21 oled = SSD1306_I2C(128, 32, i2c) 22 23 while True: 24 #get distance 25 distance = ultrasonic.Distance_accurate() 26 print("distance is %d cm"%(distance) ) 27 #display distance 28 oled.text('distance:', 0, 0) 29 oled.text(str(distance), 75, 0) 30 oled.show() 31 oled.fill(0) 32 #Control action 33 if distance < 10: 34 for i in range(num_leds): 35 pixels.set_pixel(i,255,0,0) 36 pixels.show() 37 Motor.Car_Back(150,150) 38 BZ.duty_u16(500) 39 BZ.freq(CM[7]) 40 time.sleep(0.2) 41 Motor.Car_Right(150,150) 42 BZ.duty_u16(500) 43 BZ.freq(CM[5]) 44 time.sleep(0.2) 45 BZ.duty_u16(0) 46 elif distance >= 10 and distance < 30: 47 for i in range(num_leds): 48 pixels.set_pixel(i,255,255,0) 49 pixels.show() 50 Motor.Car_Run(100,100) 51 else: 52 for i in range(num_leds): 53 pixels.set_pixel(i,0,255,0) 54 pixels.show() 55 Motor.Car_Run(100,100) 56 time.sleep(0.1)
from pico_car import SSD1306_I2C, ultrasonic, pico_car, ws2812b
使用pico_car 的SSD1306_I2C、ultrasonic、pico_car、ws2812b,封装了电机驱动和RGB灯、OLED、超声波库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C, PWM
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin、PWM和I2C的库。
Motor = pico_car()
初始化电机驱动。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(i,255,0,0)
使用for循环把所有车灯设置为红色。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
Motor.Car_Run(100,100)
控制小车前进,速度设置为150,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Back(150,150)
控制小车后退。
Motor.Car_Right(150,150)
控制小车右旋。
Motor.Car_Stop()
控制小车停止。
BZ = PWM(Pin(22))
将IO22设置为PWM输出引脚,用于控制蜂鸣器。
BZ.freq(1000)
将PWM频率设置为1000。
BZ.duty_u16(0)
数值为0的时候关闭声音,为500的时候开启声音。
ultrasonic = ultrasonic()
初始化超声波测距。
distance = ultrasonic.Distance_accurate()
将超声波测距返回的数值,赋值给变量distance 。
oled.text(str(distance), 75, 0)
将距离转换为字符串,显示在OLED的75,0位置上。
四、实验现象
程序下载完成之后,我们可以看到OLED显示 'distance: ' 和测量出来的距离,数值会根据测量结果改变,同时Shell也会显示测量的距离,当距离小于10(遇到障碍物),RGB灯亮红色,小车后退右旋,同时蜂鸣器发出“滴滴”声;当距离在10-30之间,RGB灯亮黄色,小车前进;当距离超过30,RGB灯亮绿色,小车前进。
注意,超声波最短测量距离在2-3cm,程序中使用10cm的距离进行避障,如果障碍物过密集,可以修改这个数值。
5.7 超声波跟随
在上一节,我们使用超声波传感器进行测距,实现了超声波避障,在这一节我们换一种用法,使用超声波来实现跟随。
注意:电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、超声波传感器、可编程RGB灯、蜂鸣器结合实现超声波跟随。
2. 了解如何通过超声波传感器实现跟随。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、超声波传感器、可编程RGB灯、蜂鸣器,可以将小车放在空旷的地面上,如果有障碍物可能会影响跟随效果。
在程序中我们通过读取超声波传感器数值,对不同的距离数值做出不同的动作。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 7.超声波跟随.py
1 import time 2 from machine import Pin, I2C, PWM 3 from pico_car import SSD1306_I2C, ultrasonic, pico_car, ws2812b 4 5 Motor = pico_car() 6 Motor.Car_Stop() 7 num_leds = 8 # Number of NeoPixels 8 # Pin where NeoPixels are connected 9 pixels = ws2812b(num_leds, 0) 10 pixels.fill(0,0,0) 11 pixels.show() 12 # set buzzer pin 13 BZ = PWM(Pin(22)) 14 BZ.freq(1000) 15 # Initialize music 16 CM = [0, 330, 350, 393, 441, 495, 556, 624] 17 song = [CM[1],CM[1],CM[5],CM[5],CM[6],CM[6],CM[5],CM[4],CM[4],CM[3],CM[3],CM[2],CM[2],CM[1],] 18 beat = [ 0.5,0.5,0.5,0.5,0.5,0.5,1,0.5,0.5,0.5,0.5,0.5,0.5,1,] 19 #initialization ultrasonic 20 ultrasonic = ultrasonic() 21 #initialization oled 22 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 23 oled = SSD1306_I2C(128, 32, i2c) 24 #Define variables 25 global time_ul, music_i, t_turn, i_turn, t_turn, music_back 26 music_i = 0 27 time_ul = 0 28 i_run = 0 29 i_turn = 0 30 t_turn = 0 31 music_back = 0 32 33 while True: 34 #get distance 35 distance = ultrasonic.Distance_accurate() 36 print("distance is %d cm"%(distance) ) 37 #display distance 38 oled.text('distance:', 0, 0) 39 oled.text(str(distance), 75, 0) 40 oled.show() 41 oled.fill(0) 42 #Control action 43 if distance < 9: 44 for i in range(num_leds): 45 pixels.set_pixel(i,255,0,0) 46 pixels.show() 47 Motor.Car_Back(100,100) 48 if music_back < 5: 49 BZ.duty_u16(500) 50 BZ.freq(624) 51 else: 52 BZ.duty_u16(0) 53 elif distance >= 9 and distance < 20: 54 if i_run == 0: 55 pixels.set_pixel(6,0,0,0) 56 pixels.set_pixel(7,0,0,0) 57 pixels.set_pixel(2,150,0,150) 58 pixels.set_pixel(3,150,0,150) 59 i_run = 1 60 elif i_run == 1: 61 pixels.set_pixel(2,0,0,0) 62 pixels.set_pixel(3,0,0,0) 63 pixels.set_pixel(1,150,0,150) 64 pixels.set_pixel(4,150,0,150) 65 i_run = 2 66 elif i_run == 2: 67 pixels.set_pixel(1,0,0,0) 68 pixels.set_pixel(4,0,0,0) 69 pixels.set_pixel(0,150,0,150) 70 pixels.set_pixel(5,150,0,150) 71 i_run = 3 72 elif i_run == 3: 73 pixels.set_pixel(0,0,0,0) 74 pixels.set_pixel(5,0,0,0) 75 pixels.set_pixel(6,150,0,150) 76 pixels.set_pixel(7,150,0,150) 77 i_run = 4 78 elif i_run == 4: 79 pixels.set_pixel(0,0,0,0) 80 pixels.set_pixel(5,0,0,0) 81 pixels.set_pixel(6,150,0,150) 82 pixels.set_pixel(7,150,0,150) 83 i_run = 0 84 pixels.show() 85 Motor.Car_Run(100,100) 86 BZ.duty_u16(500) 87 BZ.freq(song[music_i]) 88 time.sleep(beat[music_i]/2) 89 BZ.duty_u16(0) 90 91 else: 92 BZ.duty_u16(0) 93 if i_turn == 0: 94 pixels.set_pixel(7,0,0,0) 95 pixels.set_pixel(0,0,150,150) 96 else: 97 pixels.set_pixel(i_turn-1,0,0,0) 98 pixels.set_pixel(i_turn,0,150,150) 99 pixels.show() 100 if t_turn < 5: 101 Motor.Car_Right(120,120) 102 elif t_turn >= 5 and t_turn < 10: 103 Motor.Car_Left(120,120) 104 105 time_ul = time_ul + 1 106 music_i = music_i + 1 107 if music_i >= len(song): 108 music_i = 0 109 i_turn = i_turn + 1 110 if i_turn == 8: 111 i_turn = 0 112 t_turn = t_turn + 1 113 if t_turn >= 10: 114 t_turn = 0 115 music_back = music_back + 1 116 if music_back >= 10: 117 music_back = 0 118 time.sleep(0.01)
在这个程序里做了RGB灯效,前进的时候会一边播放音乐一边流水灯,旋转寻找跟随目标的时候也有流水灯效果,在单线程只能顺序执行的程序里要实现同时运行多种效果,就需要把音乐、流水灯、小车运行切成一小块一小块,每一小块中都包含音乐、流水灯、小车运行的片段,所以我们在程序里做了多个变量来实现这种效果。
from pico_car import SSD1306_I2C, ultrasonic, pico_car, ws2812b
使用pico_car 的SSD1306_I2C、ultrasonic、pico_car、ws2812b,封装了电机驱动和RGB灯、OLED、超声波库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C, PWM
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin、PWM和I2C的库。
Motor = pico_car()
初始化电机驱动。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(i,255,0,0)
使用for循环把所有车灯设置为红色。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
Motor.Car_Run(100,100)
控制小车前进,速度设置为100,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Back(100,100)
控制小车后退。
Motor.Car_Left(120,120)
控制小车左旋。
Motor.Car_Right(120,120)
控制小车右旋。
Motor.Car_Stop()
控制小车停止。
BZ = PWM(Pin(22))
将IO22设置为PWM输出引脚,用于控制蜂鸣器。
BZ.freq(1000)
将PWM频率设置为1000。
BZ.duty_u16(0)
数值为0的时候关闭声音,为500的时候开启声音。
ultrasonic = ultrasonic()
初始化超声波测距。
distance = ultrasonic.Distance_accurate()
将超声波测距返回的数值,赋值给变量distance 。
oled.text(str(distance), 75, 0)
将距离转换为字符串,显示在OLED的75,0位置上。
四、实验现象
程序下载完成之后,我们可以看到OLED显示 'distance: ' 和测量出来的距离,数值会根据测量结果改变,同时Shell也会显示测量的距离,当距离小于9(距离跟随物体过近),RGB灯亮红色,小车后退,同时蜂鸣器发出“滴滴”声;当距离在9-20之间,RGB灯以两个为一组,亮紫色流水灯,小车前进,并且同时播放音乐;当距离超过20,RGB灯亮青色流水灯,小车右旋左旋寻找跟随物体。
注意,超声波最短测量距离在2-3cm,如果跟随效果不好,可以适当修改距离,或者修改小车运行速度。
5.8 寻光跟随
在4.1节,我们使用光敏传感器检测光线强度,并把结果显示在OLED上,在这一节,我们利用这个光线强度结果来实现寻光跟随。
注意,寻光受到环境光线影响,请在室内光线变化不大或者较暗的地方使用。
电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、光敏传感器、可编程RGB灯结合实现小车寻光。
2. 了解小车寻光的实现。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、光敏传感器、可编程RGB灯,小车放在前方没有障碍物的空旷位置,运行之前请把跳线帽接到Light排针,准备好光源(手电筒或手机的相机灯)。
在程序中我们通过读取两个光敏传感器的数值,比较两个数值大小,判断光源位置,从而控制小车寻光。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 8.寻光跟随.py
1 import time 2 from machine import Pin, I2C, PWM, ADC 3 from pico_car import SSD1306_I2C, pico_car, ws2812b 4 5 Motor = pico_car() 6 Motor.Car_Stop() 7 num_leds = 8 # Number of NeoPixels 8 # Pin where NeoPixels are connected 9 pixels = ws2812b(num_leds, 0) 10 pixels.fill(0,0,0) 11 pixels.show() 12 #Light1 -> GP27 13 #Light2 -> GP26 14 light1 = machine.ADC(27) 15 light2 = machine.ADC(26) 16 #initialization oled 17 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 18 oled = SSD1306_I2C(128, 32, i2c) 19 light_down = 0.9 20 light_up = 1.1 21 22 while True: 23 #get value 24 LightS1 = light1.read_u16() 25 LightS2 = light2.read_u16() 26 print("light1 is %d"%(LightS1) ) 27 print("light2 is %d"%(LightS2) ) 28 #Display sound on OLED 29 oled.text('Light1:', 0, 0) 30 oled.text(str(LightS1), 60, 0) 31 oled.text('Light2:', 0, 10) 32 oled.text(str(LightS2), 60, 10) 33 #Control action 34 if LightS1 > (LightS2*light_down) and LightS1 < (LightS2*light_up): 35 Motor.Car_Run(120,120) 36 for i in range(num_leds): 37 pixels.set_pixel(i,150,150,150) 38 pixels.show() 39 elif LightS2 > (LightS1*light_down) and LightS2 < (LightS1*light_up): 40 Motor.Car_Run(120,120) 41 for i in range(num_leds): 42 pixels.set_pixel(i,150,150,150) 43 pixels.show() 44 elif LightS1 > (LightS2*light_up) or LightS2 < (LightS1*light_down): 45 Motor.Car_Run(120,0) 46 pixels.fill(0,0,0) 47 pixels.set_pixel(0,150,0,150) 48 pixels.set_pixel(1,150,0,150) 49 pixels.set_pixel(2,150,0,150) 50 pixels.set_pixel(7,150,0,150) 51 pixels.show() 52 elif LightS2 > (LightS1*light_up) or LightS1 < (LightS2*light_down): 53 Motor.Car_Run(0,120) 54 pixels.fill(0,0,0) 55 pixels.set_pixel(3,150,0,150) 56 pixels.set_pixel(4,150,0,150) 57 pixels.set_pixel(5,150,0,150) 58 pixels.set_pixel(6,150,0,150) 59 pixels.show() 60 else: 61 Motor.Car_Stop() 62 oled.show() 63 oled.fill(0) 64 time.sleep(0.01)
from pico_car import SSD1306_I2C, pico_car, ws2812b
使用pico_car 的SSD1306_I2C、pico_car、ws2812b,封装了电机驱动和RGB灯、OLED库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C, ADC, PWM
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin、PWM、ADC和I2C的库。
Motor = pico_car()
初始化电机驱动。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(0,150,0,150)
设置第一个车灯为紫色。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
Motor.Car_Run(120,120)
控制小车前进,速度设置为120,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Stop()
控制小车停止。
light1 = machine.ADC(27)
初始化ADC端口27,光敏传感器一共两个,分别设置了27和26脚。
oled.text(str(LightS1), 60, 0)
将光敏的值转换成字符串显示在OLED的60,0位置。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
LightS1 = light1.read_u16()
light1.read_u16()函数用来检测声音传感器的值,赋值给变量LightS1。
四、实验现象
程序下载完成之后,我们可以看到OLED第一行显示光敏传感器1的值 ,第二行显示光敏传感器2的值,同时Shell也会打印光敏传感器数值,使用手电筒对着小车前方左右移动,可以控制小车左右运动。
因为光敏传感器容易受到环境光线影响,请在室内光线变化不大或者较暗的地方使用,若寻光效果不好,可以适当调整检测范围,即变量light_down和light_up。
5.9 声控小车
在4.2节,我们使用声音传感器进行声音检测,在这一节我们将用检测的声音控制小车。
注意:为了防止误触发,声音传感器设置的检测基准值较大,识别效果不好的话可以适当修改检测基准值,或者对声音传感器吹气来触发。
电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、声音传感器、可编程RGB灯、蜂鸣器结合实现声控小车。
2. 了解声控小车的实现。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、声音传感器、可编程RGB灯、蜂鸣器,小车放在前方没有障碍物的空旷位置,运行之前请把跳线帽接到Voice排针。
在程序中我们通过读取声音的数值,当数值超过基准时,控制小车运行一段时间。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 9.声控小车.py
1 from pico_car import SSD1306_I2C, pico_car, ws2812b 2 from machine import Pin, I2C, ADC, PWM 3 import time 4 5 Motor = pico_car() 6 Motor.Car_Stop() 7 num_leds = 8 # Number of NeoPixels 8 # Pin where NeoPixels are connected 9 pixels = ws2812b(num_leds, 0) 10 pixels.fill(0,0,0) 11 pixels.show() 12 # set buzzer pin 13 BZ = PWM(Pin(22)) 14 BZ.freq(1000) 15 CM = [0, 330, 350, 393, 441, 495, 556, 624] 16 #initialization oled 17 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 18 oled = SSD1306_I2C(128, 32, i2c) 19 #initialization ADC 20 Sound = machine.ADC(27) 21 22 while True: 23 #get value 24 sounds = Sound.read_u16() 25 print(sounds) 26 oled.text('Sound:', 0, 0) 27 oled.text(str(sounds), 50, 0) 28 #Control action 29 if sounds > 20000: 30 while sounds > 10000: 31 Motor.Car_Stop() 32 sounds = Sound.read_u16() 33 print(sounds) 34 time.sleep(0.001) 35 Motor.Car_Run(255,255) 36 BZ.duty_u16(500) 37 BZ.freq(CM[1]) 38 pixels.set_pixel(2,150,0,150) 39 pixels.set_pixel(3,150,0,150) 40 pixels.show() 41 time.sleep(0.03) 42 BZ.duty_u16(500) 43 BZ.freq(CM[2]) 44 pixels.set_pixel(2,0,0,0) 45 pixels.set_pixel(3,0,0,0) 46 pixels.set_pixel(1,150,0,150) 47 pixels.set_pixel(4,150,0,150) 48 pixels.show() 49 time.sleep(0.03) 50 BZ.duty_u16(500) 51 BZ.freq(CM[3]) 52 pixels.set_pixel(1,0,0,0) 53 pixels.set_pixel(4,0,0,0) 54 pixels.set_pixel(0,150,0,150) 55 pixels.set_pixel(5,150,0,150) 56 pixels.show() 57 time.sleep(0.03) 58 BZ.duty_u16(500) 59 BZ.freq(CM[4]) 60 pixels.set_pixel(0,0,0,0) 61 pixels.set_pixel(5,0,0,0) 62 pixels.set_pixel(6,150,0,150) 63 pixels.set_pixel(7,150,0,150) 64 pixels.show() 65 time.sleep(0.03) 66 BZ.duty_u16(500) 67 BZ.freq(CM[5]) 68 pixels.set_pixel(0,0,0,0) 69 pixels.set_pixel(5,0,0,0) 70 pixels.set_pixel(6,150,0,150) 71 pixels.set_pixel(7,150,0,150) 72 pixels.show() 73 time.sleep(0.03) 74 BZ.duty_u16(500) 75 BZ.freq(CM[6]) 76 pixels.set_pixel(6,0,0,0) 77 pixels.set_pixel(7,0,0,0) 78 pixels.show() 79 BZ.duty_u16(0) 80 sounds = 0 81 oled.show() 82 oled.fill(0) 83 else: 84 Motor.Car_Stop() 85 oled.show() 86 oled.fill(0) 87 time.sleep(0.01)
声音传感器检测值会受到电池电量的影响,建议先测试再调整比较值,测试的时候建议关闭电机、RGB灯等功耗较高的负载,在程序中检测基准值(30000)之后,防止小车前进时间过长,使用一个while过滤掉多余的数值保证一次检测只执行一次前进。
from pico_car import SSD1306_I2C, pico_car, ws2812b
使用pico_car 的SSD1306_I2C、pico_car、ws2812b,封装了电机驱动和RGB灯、OLED库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C, ADC, PWM
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin、PWM、ADC和I2C的库。
Motor = pico_car()
初始化电机驱动。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(i,255,0,0)
使用for循环把所有车灯设置为红色。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
Motor.Car_Run(150,150)
控制小车前进,速度设置为150,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Stop()
控制小车停止。
BZ = PWM(Pin(22))
将IO22设置为PWM输出引脚,用于控制蜂鸣器。
BZ.freq(1000)
将PWM频率设置为1000。
BZ.duty_u16(0)
数值为0的时候关闭声音,为500的时候开启声音。
oled.text(str(sounds), 50, 0)
将距离转换为字符串,显示在OLED的50,0位置上。
Sound = machine.ADC(27)
初始化ADC端口27。
sounds = Sound.read_u16()
Sound.read_u16()函数用来检测声音传感器的值,赋值给变量sounds。
四、实验现象
程序下载完成之后,我们可以看到OLED第一行显示 Sound的值 ,对着声音传感器吹气小车会一边鸣笛一边前进一段距离,同时底下有流水灯效果,同时Shell也会打印声音传感器数值。
5.10 红外控制
在4.5节,我们学习了如何接收红外遥控器的值并显示在OLED上,在这一节我们使用红外遥控来实现小车的多种控制。
注意:电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、红外接收、可编程RGB灯、蜂鸣器结合实现红外遥控。
2. 了解如何通过红外遥控控制小车。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、红外接收、可编程RGB灯、蜂鸣器,可以将小车放在空旷的地面上,在这个例程里我们还需要使用红外遥控器来发射红外数值给红外接收。
在程序中我们通过遥控按键远程控制小车运动、亮灯、鸣笛等。
三、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 10.红外控制.py
1 import time 2 from machine import Pin, I2C, PWM, Timer 3 from pico_car import SSD1306_I2C, ir, pico_car, ws2812b 4 5 Motor = pico_car() 6 Motor.Car_Stop() 7 num_leds = 8 # Number of NeoPixels 8 # Pin where NeoPixels are connected 9 pixels = ws2812b(num_leds, 0) 10 # Set all led off 11 pixels.fill(0,0,0) 12 pixels.show() 13 # set buzzer pin 14 BZ = PWM(Pin(22)) 15 BZ.freq(1000) 16 #initialization ir 17 Ir = ir() 18 #initialization oled 19 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 20 oled = SSD1306_I2C(128, 32, i2c) 21 #define Timer 22 tim = Timer() 23 times_ = 0 24 def tick(timer): 25 global times_ 26 times_ = times_ + 1 27 if times_ > 100: 28 times_ = 0 29 #set timer frequency 20 30 tim.init(freq = 20,mode = Timer.PERIODIC,callback = tick) 31 32 while True: 33 #get value 34 value = Ir.Getir() 35 time.sleep(0.01) 36 if value != None: 37 print(value) 38 #display press 39 if value == 1: 40 i = 0 41 while value == 1: 42 value = Ir.Getir() 43 Motor.Car_Run(255,255) 44 if times_ > 1: 45 times_ = 0 46 if i == 0: 47 pixels.set_pixel(2,150,0,150) 48 pixels.set_pixel(3,150,0,150) 49 i = 1 50 elif i == 1: 51 pixels.set_pixel(2,0,0,0) 52 pixels.set_pixel(3,0,0,0) 53 pixels.set_pixel(1,150,0,150) 54 pixels.set_pixel(4,150,0,150) 55 i = 2 56 elif i == 2: 57 pixels.set_pixel(1,0,0,0) 58 pixels.set_pixel(4,0,0,0) 59 pixels.set_pixel(0,150,0,150) 60 pixels.set_pixel(5,150,0,150) 61 i = 3 62 elif i == 3: 63 pixels.set_pixel(0,0,0,0) 64 pixels.set_pixel(5,0,0,0) 65 pixels.set_pixel(6,150,0,150) 66 pixels.set_pixel(7,150,0,150) 67 i = 4 68 elif i == 4: 69 pixels.set_pixel(0,0,0,0) 70 pixels.set_pixel(5,0,0,0) 71 pixels.set_pixel(6,150,0,150) 72 pixels.set_pixel(7,150,0,150) 73 i = 5 74 elif i == 5: 75 pixels.set_pixel(6,0,0,0) 76 pixels.set_pixel(7,0,0,0) 77 i = 0 78 pixels.show() 79 Motor.Car_Stop() 80 oled.text('Run', 0, 0) 81 oled.show() 82 oled.fill(0) 83 elif value == 4: 84 i = 0 85 while value == 4: 86 value = Ir.Getir() 87 Motor.Car_Left(130,130) 88 if times_ > 1: 89 times_ = 0 90 if i == 0: 91 pixels.set_pixel(7,0,0,0) 92 pixels.set_pixel(0,150,0,150) 93 i = i + 1 94 else: 95 pixels.set_pixel(i-1,0,0,0) 96 pixels.set_pixel(i,150,0,150) 97 i = i + 1 98 if i == 8: 99 i = 0 100 pixels.show() 101 Motor.Car_Stop() 102 oled.text('Left', 0, 0) 103 oled.show() 104 oled.fill(0) 105 elif value == 6: 106 i = 8 107 while value == 6: 108 value = Ir.Getir() 109 Motor.Car_Right(130,130) 110 if times_ > 1: 111 times_ = 0 112 if i == 8: 113 pixels.set_pixel(7,150,0,150) 114 pixels.set_pixel(0,0,0,0) 115 i = i - 1 116 else: 117 pixels.set_pixel(i-1,150,0,150) 118 pixels.set_pixel(i,0,0,0) 119 i = i - 1 120 if i == 0: 121 i = 8 122 pixels.show() 123 Motor.Car_Stop() 124 oled.text('Right', 0, 0) 125 oled.show() 126 oled.fill(0) 127 elif value == 5: 128 while value == 5: 129 value = Ir.Getir() 130 BZ.duty_u16(500) 131 BZ.freq(624) 132 BZ.duty_u16(0) 133 oled.text('Buzzer', 0, 0) 134 oled.show() 135 oled.fill(0) 136 elif value == 9: 137 i = 0 138 while value == 9: 139 value = Ir.Getir() 140 Motor.Car_Back(255,255) 141 if times_ > 1: 142 times_ = 0 143 if i == 0: 144 pixels.set_pixel(6,150,0,150) 145 pixels.set_pixel(7,150,0,150) 146 i = 1 147 elif i == 1: 148 pixels.set_pixel(6,0,0,0) 149 pixels.set_pixel(7,0,0,0) 150 pixels.set_pixel(0,150,0,150) 151 pixels.set_pixel(5,150,0,150) 152 i = 2 153 elif i == 2: 154 pixels.set_pixel(0,0,0,0) 155 pixels.set_pixel(5,0,0,0) 156 pixels.set_pixel(1,150,0,150) 157 pixels.set_pixel(4,150,0,150) 158 i = 3 159 elif i == 3: 160 pixels.set_pixel(1,0,0,0) 161 pixels.set_pixel(4,0,0,0) 162 pixels.set_pixel(2,150,0,150) 163 pixels.set_pixel(3,150,0,150) 164 i = 4 165 elif i == 4: 166 pixels.set_pixel(1,0,0,0) 167 pixels.set_pixel(4,0,0,0) 168 pixels.set_pixel(2,150,0,150) 169 pixels.set_pixel(3,150,0,150) 170 i = 5 171 elif i == 5: 172 pixels.set_pixel(2,0,0,0) 173 pixels.set_pixel(3,0,0,0) 174 i = 0 175 pixels.show() 176 Motor.Car_Stop() 177 oled.text('Back', 0, 0) 178 oled.show() 179 oled.fill(0) 180 elif value == 16: 181 while value == 16: 182 value = Ir.Getir() 183 for i in range(num_leds): 184 pixels.set_pixel(i,255,0,0) 185 pixels.show() 186 oled.text('Red', 0, 0) 187 oled.show() 188 oled.fill(0) 189 elif value == 17: 190 while value == 17: 191 value = Ir.Getir() 192 for i in range(num_leds): 193 pixels.set_pixel(i,0,255,0) 194 pixels.show() 195 oled.text('Green', 0, 0) 196 oled.show() 197 oled.fill(0) 198 elif value == 18: 199 while value == 18: 200 value = Ir.Getir() 201 for i in range(num_leds): 202 pixels.set_pixel(i,0,0,255) 203 pixels.show() 204 oled.text('Blue', 0, 0) 205 oled.show() 206 oled.fill(0) 207 elif value == 20: 208 while value == 20: 209 value = Ir.Getir() 210 for i in range(num_leds): 211 pixels.set_pixel(i,255,255,0) 212 pixels.show() 213 oled.text('Yellow', 0, 0) 214 oled.show() 215 oled.fill(0) 216 elif value == 21: 217 while value == 21: 218 value = Ir.Getir() 219 for i in range(num_leds): 220 pixels.set_pixel(i,0,255,255) 221 pixels.show() 222 oled.text('Cyan', 0, 0) 223 oled.show() 224 oled.fill(0) 225 elif value == 22: 226 while value == 22: 227 value = Ir.Getir() 228 for i in range(num_leds): 229 pixels.set_pixel(i,255,0,255) 230 pixels.show() 231 oled.text('Purple', 0, 0) 232 oled.show() 233 oled.fill(0) 234 elif value == 24: 235 while value == 24: 236 value = Ir.Getir() 237 for i in range(num_leds): 238 pixels.set_pixel(i,255,255,255) 239 pixels.show() 240 oled.text('White', 0, 0) 241 oled.show() 242 oled.fill(0) 243 elif value == 25: 244 while value == 25: 245 value = Ir.Getir() 246 for i in range(num_leds): 247 pixels.set_pixel(i,100,100,100) 248 pixels.show() 249 oled.text('White', 0, 0) 250 oled.show() 251 oled.fill(0) 252 elif value == 26: 253 while value == 26: 254 value = Ir.Getir() 255 for i in range(num_leds): 256 pixels.set_pixel(i,0,0,0) 257 pixels.show() 258 oled.text('Black', 0, 0) 259 oled.show() 260 oled.fill(0) 261 value = None
在5.7超声波跟随的程序里,我们介绍了如何实现蜂鸣器、RGB灯、小车运动同时控制,在这个程序里我们也做了相似的处理,同时还加了定时器中断Timer来实现RGB灯切换速度控制。
我们使用 while value == 按键值:
来实现遥控器按一下松开再执行的效果。
from pico_car import SSD1306_I2C, ir, pico_car, ws2812b
使用pico_car 的SSD1306_I2C、ir、pico_car、ws2812b,封装了电机驱动和RGB灯、OLED、红外遥控库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C, PWM, Timer
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin、PWM、Timer和I2C的库。
Motor = pico_car()
初始化电机驱动。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.show()
把设置的灯显示出来。
pixels.set_pixel(2,150,0,150)
把第三个灯设置为紫色。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
oled.text('Green', 0, 0)
在OLED的0,0位置显示'Green'。
Motor.Car_Run(255,255)
控制小车前进,速度设置为150,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Back(255,255)
控制小车后退。
Motor.Car_Left(130,130)
控制小车左旋。
Motor.Car_Right(130,130)
控制小车右旋。
Motor.Car_Stop()
控制小车停止。
BZ = PWM(Pin(22))
将IO22设置为PWM输出引脚,用于控制蜂鸣器。
BZ.freq(1000)
将PWM频率设置为1000。
BZ.duty_u16(0)
数值为0的时候关闭声音,为500的时候开启声音。
tim = Timer()
初始化定时中断。
tick(timer)
定时中断函数,在函数中使用变量times_做时间控制,从而控制RGB等切换速度。
tim.init(freq = 1000,mode = Timer.PERIODIC,callback = tick)
设置定时中断函数和频率。
Ir = ir()
初始化红外遥控。
value = Ir.Getir()
读取红外遥控数值,赋值给变量value。
四、实验现象
程序下载完成之后,按照以下协议运行小车。
按键 | Shell打印键值 | OLED显示 | 效果 |
---|---|---|---|
向上 | 1 | Run | 小车前进,底部向前流水灯效果 |
向左 | 4 | Left | 小车左旋,底部逆时针流水灯效果 |
向右 | 6 | Right | 小车右旋,底部顺时针流水灯效果 |
向下 | 9 | Back | 小车后退,底部向后流水灯效果 |
声音 | 5 | Buzzer | 小车蜂鸣器响 |
1 | 16 | Red | RGB灯亮红色 |
2 | 17 | Green | RGB灯亮绿色 |
3 | 18 | Blue | RGB灯亮蓝色 |
4 | 20 | Yellow | RGB灯亮黄色 |
5 | 21 | Cyan | RGB灯亮青色 |
6 | 22 | Purple | RGB灯亮紫色 |
7 | 24 | White | RGB灯亮白色 |
8 | 25 | White | RGB灯亮低亮度白色 |
9 | 26 | Black | RGB灯关灯 |
5.11 蓝牙控制
在这一节,我们将学习如何通过蓝牙控制小车,我们将会把前面学习到的巡线、超声波避障、声控、OLED控制、蜂鸣器控制、可编程RGB灯等都集成到一起,全都可以通过蓝牙控制。
注意:电机速度受到电池电量影响,例程是在电池电量较高(电量数值在26000以上)的情况下,如果电池电量较低需要及时充电或者修改电机速度。
一、学习目标
1. 学习树莓派Pico主板和小车扩展板的电机、OLED、蓝牙、可编程RGB灯、蜂鸣器、超声波、声音传感器结合实现蓝牙控制。
2. 了解如何通过蓝牙控制小车。
二、硬件使用
本次课程使用PICO主板以及小车扩展板的电机、OLED、蓝牙、可编程RGB灯、蜂鸣器、超声波、声音传感器。
注意:请将小车放在地面上。运行电机、可编程RGB灯时,声音传感器和电池电量数值波动是正常的。运行巡线模式的时候,必须在室内无太阳光照的环境下进行,以减少太阳光对巡线传感器的干扰,并且在巡线时需保持室内光线充足,否则需要根据5.4节的方法修改程序。运行超声波避障模式的时候,需要确保障碍物不会过于密集,如果障碍物过于密集可以按5.6节的方法修改程序。运行声控模式的时候,需要在较安静的环境下运行。OLED一行最多显示16个字符,只支持数字和英文显示。使用之前请确保电池电量(电量数值在26000以上),否则可能运行异常。
三、下载程序和蓝牙连接
1. 按照1.3节组装步骤把小车组装完成,注意要接上蓝牙模块和OLED模块,把跳线帽插到Voice排针上。
2. 按照2.4节将库文件导入到PICO开发板中。
3. 打开程序:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 11.蓝牙控制.py 按照2.3开机自启动部分,把程序设置成开机自启动(调试的时候可以不用开机自启动),注意文件名要设置成main.py。
4. 拔掉和电脑连接的USB线,重启一下小车,此时蓝牙模块的红灯闪烁,准备连接手机。
5. Android/IOS手机用户扫描下方二维码下载软件。IOS用户也可以在苹果应用商城搜索并下载【YahboomRobot】
6. 下载完成蓝牙遥控APP之后, 我们要进行安装。安装期间如果手机提示需要获取位置权限,需要点击同意获取位置权限。
7. 打开手机蓝牙,打开已经安装好的YahboomRobot,选择 智能小车 -> PICO ROBOT,进入蓝牙连接界面,当手机靠近小车时蓝牙会自动连接上,如果没有自动连接的话,我们需要点击【搜索蓝牙】,成功连接之后,APP将会跳转到控制界面。
8. 连接成功后,蓝牙模块的红灯变成长亮,提示bluetooth connect successful!,我们就可以通过手机控制小车了,如果蓝牙断了红灯会重新变成闪烁。
四、蓝牙遥控界面介绍
1. 基础功能
2. 音乐选项
3. 车灯选项
4. 车灯灯效
5. 模式选择
五、程序分析
完整程序位置:Pico Robot配套资料 -> 附件 -> 课程程序源码 -> 3.机器人课程 -> 11.蓝牙控制.py
1 import time 2 from machine import Pin, I2C, PWM, Timer, UART, ADC 3 from pico_car import SSD1306_I2C, pico_car, ws2812b, ultrasonic 4 5 Motor = pico_car() 6 Motor.Car_Stop() 7 num_leds = 8 # Number of NeoPixels 8 # Pin where NeoPixels are connected 9 pixels = ws2812b(num_leds, 0) 10 pixels.fill(0,0,0) 11 pixels.show() 12 # set buzzer pin 13 BZ = PWM(Pin(22)) 14 BZ.freq(1000) 15 # Initialize music 16 CM = [0, 330, 350, 393, 441, 495, 556, 624] 17 #initialization ultrasonic 18 ultrasonic = ultrasonic() 19 #initialization oled 20 i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000) 21 oled = SSD1306_I2C(128, 32, i2c) 22 #initialization Bluetooth 23 uart = UART(0, 9600, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17)) 24 dat = 0 25 #initialization ADC 26 Quantity_of_electricity = machine.ADC(28) 27 Sound = machine.ADC(27) 28 #define Timer 29 tim = Timer() 30 def tick(timer): 31 w_power = int(Quantity_of_electricity.read_u16()/65535*240) 32 if w_power > 100: 33 w_power = 100 34 w_distance = ultrasonic.Distance_accurate() 35 w_sounds = int(Sound.read_u16()/65535*200) 36 uart.write('$DAT') 37 uart.write(str(w_distance)) 38 uart.write(',') 39 uart.write(str(w_sounds)) 40 uart.write(',') 41 uart.write(str(w_power)) 42 uart.write('#') 43 #set timer frequency 0.1 44 tim.init(freq = 0.1,mode = Timer.PERIODIC,callback = tick) 45 46 #define water lamp 47 def water(): 48 global i,dat 49 i = 0 50 while dat != b'M#': 51 while uart.any() > 0: 52 dat = uart.read(2) 53 if i == 0: 54 pixels.set_pixel(7,0,0,0) 55 pixels.set_pixel(0,150,0,150) 56 i = i + 1 57 else: 58 pixels.set_pixel(i-1,0,0,0) 59 pixels.set_pixel(i,150,0,150) 60 i = i + 1 61 if i == 8: 62 i = 0 63 pixels.show() 64 time.sleep(0.1) 65 i = 0 66 67 #define breathing lamp 68 def breathing(): 69 global i,dat 70 i = 0 71 brightness = 0 72 fadeAmount = 1 73 while dat != b'M#': 74 while uart.any() > 0: 75 dat = uart.read(2) 76 temp = 0 77 while temp < 400: 78 for i in range(num_leds): 79 pixels.set_pixel(i,0,brightness,brightness) 80 pixels.show() 81 brightness = brightness + fadeAmount 82 if brightness <= 0 or brightness >= 200: 83 fadeAmount = -fadeAmount 84 temp+=1 85 time.sleep(0.005) 86 87 temp = 0 88 while temp < 400: 89 for i in range(num_leds): 90 pixels.set_pixel(i,brightness,0,brightness) 91 pixels.show() 92 brightness = brightness + fadeAmount 93 if brightness <= 0 or brightness >= 200: 94 fadeAmount = -fadeAmount 95 temp+=1 96 time.sleep(0.005) 97 98 temp = 0 99 while temp < 400: 100 for i in range(num_leds): 101 pixels.set_pixel(i,brightness,brightness,0) 102 pixels.show() 103 brightness = brightness + fadeAmount 104 if brightness <= 0 or brightness >= 200: 105 fadeAmount = -fadeAmount 106 temp+=1 107 time.sleep(0.005) 108 109 temp = 0 110 while temp < 400: 111 for i in range(num_leds): 112 pixels.set_pixel(i,brightness,0,0) 113 pixels.show() 114 brightness = brightness + fadeAmount 115 if brightness <= 0 or brightness >= 200: 116 fadeAmount = -fadeAmount 117 temp+=1 118 time.sleep(0.005) 119 120 temp = 0 121 while temp < 400: 122 for i in range(num_leds): 123 pixels.set_pixel(i,0,brightness,0) 124 pixels.show() 125 brightness = brightness + fadeAmount 126 if brightness <= 0 or brightness >= 200: 127 fadeAmount = -fadeAmount 128 temp+=1 129 time.sleep(0.005) 130 131 temp = 0 132 while temp < 400: 133 for i in range(num_leds): 134 pixels.set_pixel(i,0,0,brightness) 135 pixels.show() 136 brightness = brightness + fadeAmount 137 if brightness <= 0 or brightness >= 200: 138 fadeAmount = -fadeAmount 139 temp+=1 140 time.sleep(0.005) 141 i = 0 142 143 #define horse lamp 144 def horse(): 145 global dat 146 while dat != b'M#': 147 while uart.any() > 0: 148 dat = uart.read(2) 149 for i in range(num_leds): 150 for j in range(num_leds): 151 #pixel_num, red, green, blue 152 pixels.set_pixel(j,abs(i+j)%10,abs(i-(j+3))%10,abs(i-(j+6))%10) 153 pixels.show() 154 time.sleep(0.05) 155 156 #Define the tracking sensor, 1-4 from left to right 157 #recognize that black is 0 and white is 1 158 #Tracing_1 Tracing_2 Tracing_3 Tracing_4 159 # 2 3 4 5 160 Tracing_1 = machine.Pin(2, machine.Pin.IN) 161 Tracing_2 = machine.Pin(3, machine.Pin.IN) 162 Tracing_3 = machine.Pin(4, machine.Pin.IN) 163 Tracing_4 = machine.Pin(5, machine.Pin.IN) 164 #define line 165 def line(): 166 global dat 167 oled.fill(0) 168 while dat != b'V#': 169 while uart.any() > 0: 170 dat = uart.read(2) 171 172 #四路循迹引脚电平状态 173 #Four channel tracking pin level status 174 # 0 0 X 0 175 # 1 0 X 0 176 # 0 1 X 0 177 #处理右锐角和右直角的转动 178 #Handle the rotation of right acute angle and right right right angle 179 if (Tracing_1.value() == 0 or Tracing_2.value() == 0) and Tracing_4.value() == 0: 180 Motor.Car_Right(120,120) 181 for i in range(num_leds): 182 pixels.set_pixel(i,0,255,0) 183 oled.text('Turn Right', 0, 0) 184 #time.sleep(0.08) 185 186 #四路循迹引脚电平状态 187 #Four channel tracking pin level status 188 # 0 X 0 0 189 # 0 X 0 1 190 # 0 X 1 0 191 #处理左锐角和左直角的转动 192 #Handle the rotation of left sharp angle and left right angle 193 elif Tracing_1.value() == 0 and (Tracing_3.value() == 0 or Tracing_4.value() == 0): 194 Motor.Car_Left(120,120) 195 for i in range(num_leds): 196 pixels.set_pixel(i,0,0,255) 197 oled.text('Turn Left', 0, 0) 198 #time.sleep(0.08) 199 200 # 0 X X X 201 #最左边检测到 202 #Leftmost detected 203 elif Tracing_1.value() == 0: 204 Motor.Car_Run(0,130) 205 for i in range(num_leds): 206 pixels.set_pixel(i,0,0,255) 207 oled.text('Turn Left', 0, 0) 208 209 # X X X 0 210 #最右边检测到 211 #Rightmost detected 212 elif Tracing_4.value() == 0: 213 Motor.Car_Run(130,0) 214 for i in range(num_leds): 215 pixels.set_pixel(i,0,255,0) 216 oled.text('Turn Right', 0, 0) 217 # X 0 0 X 218 #处理直线 219 #Processing line 220 elif Tracing_2.value() == 0 and Tracing_3.value() == 0: 221 Motor.Car_Run(100,100) 222 for i in range(num_leds): 223 pixels.set_pixel(i,255,255,255) 224 oled.text('Run', 0, 0) 225 226 pixels.show() 227 oled.show() 228 oled.fill(0) 229 #其他时小车保持上一个小车运行状态 230 #In other cases, the trolley keeps the previous trolley running 231 pixels.fill(0,0,0) 232 Motor.Car_Stop() 233 BZ.duty_u16(0) 234 235 #define ultrasonic avoid 236 def avoid(): 237 global dat 238 oled.fill(0) 239 while dat != b'V#': 240 while uart.any() > 0: 241 dat = uart.read(2) 242 #get distance 243 distance = ultrasonic.Distance_accurate() 244 print("distance is %d cm"%(distance) ) 245 #display distance 246 oled.text('distance:', 0, 0) 247 oled.text(str(distance), 75, 0) 248 oled.show() 249 oled.fill(0) 250 #Control action 251 if distance < 10: 252 for i in range(num_leds): 253 pixels.set_pixel(i,255,0,0) 254 pixels.show() 255 Motor.Car_Back(150,150) 256 BZ.duty_u16(500) 257 BZ.freq(CM[7]) 258 time.sleep(0.2) 259 Motor.Car_Right(150,150) 260 BZ.duty_u16(500) 261 BZ.freq(CM[5]) 262 time.sleep(0.2) 263 BZ.duty_u16(0) 264 elif distance >= 10 and distance < 30: 265 for i in range(num_leds): 266 pixels.set_pixel(i,255,255,0) 267 pixels.show() 268 Motor.Car_Run(100,100) 269 else: 270 for i in range(num_leds): 271 pixels.set_pixel(i,0,255,0) 272 pixels.show() 273 Motor.Car_Run(100,100) 274 time.sleep(0.1) 275 pixels.fill(0,0,0) 276 Motor.Car_Stop() 277 BZ.duty_u16(0) 278 279 #define ultrasonic voice 280 def voice(): 281 global dat 282 oled.fill(0) 283 while dat != b'V#': 284 while uart.any() > 0: 285 dat = uart.read(2) 286 #get value 287 sounds = Sound.read_u16() 288 print(sounds) 289 oled.text('Sound:', 0, 0) 290 oled.text(str(sounds), 50, 0) 291 #Control action 292 if sounds > 22000: 293 while sounds > 10000: 294 Motor.Car_Stop() 295 sounds = Sound.read_u16() 296 print(sounds) 297 time.sleep(0.001) 298 Motor.Car_Run(255,255) 299 BZ.duty_u16(500) 300 BZ.freq(CM[1]) 301 pixels.set_pixel(2,150,0,150) 302 pixels.set_pixel(3,150,0,150) 303 pixels.show() 304 time.sleep(0.03) 305 BZ.duty_u16(500) 306 BZ.freq(CM[2]) 307 pixels.set_pixel(2,0,0,0) 308 pixels.set_pixel(3,0,0,0) 309 pixels.set_pixel(1,150,0,150) 310 pixels.set_pixel(4,150,0,150) 311 pixels.show() 312 time.sleep(0.03) 313 BZ.duty_u16(500) 314 BZ.freq(CM[3]) 315 pixels.set_pixel(1,0,0,0) 316 pixels.set_pixel(4,0,0,0) 317 pixels.set_pixel(0,150,0,150) 318 pixels.set_pixel(5,150,0,150) 319 pixels.show() 320 time.sleep(0.03) 321 BZ.duty_u16(500) 322 BZ.freq(CM[4]) 323 pixels.set_pixel(0,0,0,0) 324 pixels.set_pixel(5,0,0,0) 325 pixels.set_pixel(6,150,0,150) 326 pixels.set_pixel(7,150,0,150) 327 pixels.show() 328 time.sleep(0.03) 329 BZ.duty_u16(500) 330 BZ.freq(CM[5]) 331 pixels.set_pixel(0,0,0,0) 332 pixels.set_pixel(5,0,0,0) 333 pixels.set_pixel(6,150,0,150) 334 pixels.set_pixel(7,150,0,150) 335 pixels.show() 336 time.sleep(0.03) 337 BZ.duty_u16(500) 338 BZ.freq(CM[6]) 339 pixels.set_pixel(6,0,0,0) 340 pixels.set_pixel(7,0,0,0) 341 pixels.show() 342 BZ.duty_u16(0) 343 sounds = 0 344 oled.show() 345 oled.fill(0) 346 while sounds > 10000: 347 Motor.Car_Stop() 348 sounds = Sound.read_u16() 349 print(sounds) 350 time.sleep(0.001) 351 else: 352 Motor.Car_Stop() 353 oled.show() 354 oled.fill(0) 355 time.sleep(0.01) 356 pixels.fill(0,0,0) 357 Motor.Car_Stop() 358 BZ.duty_u16(0) 359 360 while True: 361 #receive data 362 while uart.any() > 0: 363 dat = uart.read(2) 364 #OLED display 365 if dat == b'X#': 366 for oledi in range(128): 367 for oledj in range(10): 368 oled.pixel(oledi, oledj,0) 369 datoled_1 = uart.read(16) 370 stroled_1 = str(datoled_1) 371 stroled_1 = stroled_1.replace("b'", "") 372 stroled_1 = stroled_1.replace("'", "") 373 stroled_1 = stroled_1.replace("$", "") 374 oled.text(stroled_1, 0, 0) 375 oled.show() 376 print(stroled_1) 377 elif dat == b'Y#': 378 for oledi in range(128): 379 for oledj in range(10,20): 380 oled.pixel(oledi, oledj,0) 381 datoled_2 = uart.read(16) 382 stroled_2 = str(datoled_2) 383 stroled_2 = stroled_2.replace("b'", "") 384 stroled_2 = stroled_2.replace("'", "") 385 stroled_2 = stroled_2.replace("$", "") 386 oled.text(stroled_2, 0, 10) 387 oled.show() 388 print(stroled_2) 389 elif dat == b'Z#': 390 for oledi in range(128): 391 for oledj in range(20,30): 392 oled.pixel(oledi, oledj,0) 393 datoled_3 = uart.read(16) 394 stroled_3 = str(datoled_3) 395 stroled_3 = stroled_3.replace("b'", "") 396 stroled_3 = stroled_3.replace("'", "") 397 stroled_3 = stroled_3.replace("$", "") 398 oled.text(stroled_3, 0, 20) 399 oled.show() 400 print(stroled_3) 401 elif dat == b'W#': 402 BBuzzer = uart.read(1) 403 if BBuzzer == b'1': 404 BZ.duty_u16(500) 405 BZ.freq(277) 406 elif BBuzzer == b'2': 407 BZ.duty_u16(500) 408 BZ.freq(311) 409 elif BBuzzer == b'3': 410 BZ.duty_u16(500) 411 BZ.freq(370) 412 elif BBuzzer == b'4': 413 BZ.duty_u16(500) 414 BZ.freq(415) 415 elif BBuzzer == b'5': 416 BZ.duty_u16(500) 417 BZ.freq(466) 418 419 #car control 420 if dat == b'A#': 421 Motor.Car_Run(255,255) 422 elif dat == b'B#': 423 Motor.Car_Back(255,255) 424 elif dat == b'C#': 425 Motor.Car_Run(0,255) 426 elif dat == b'D#': 427 Motor.Car_Run(255,0) 428 elif dat == b'E#': 429 Motor.Car_Left(255,255) 430 elif dat == b'F#': 431 Motor.Car_Right(255,255) 432 elif dat == b'0#': 433 Motor.Car_Stop() 434 #music control 435 elif dat == b'1#': 436 BZ.duty_u16(500) 437 BZ.freq(262) 438 elif dat == b'2#': 439 BZ.duty_u16(500) 440 BZ.freq(294) 441 elif dat == b'3#': 442 BZ.duty_u16(500) 443 BZ.freq(330) 444 elif dat == b'4#': 445 BZ.duty_u16(500) 446 BZ.freq(349) 447 elif dat == b'5#': 448 BZ.duty_u16(500) 449 BZ.freq(392) 450 elif dat == b'6#': 451 BZ.duty_u16(500) 452 BZ.freq(440) 453 elif dat == b'7#': 454 BZ.duty_u16(500) 455 BZ.freq(494) 456 elif dat == b'8#': 457 BZ.duty_u16(500) 458 BZ.freq(523) 459 elif dat == b'O#': 460 BZ.duty_u16(0) 461 #car light 462 elif dat == b'G#': 463 pixels.fill(255,0,0) 464 pixels.show() 465 elif dat == b'H#': 466 pixels.fill(0,255,0) 467 pixels.show() 468 elif dat == b'I#': 469 pixels.fill(0,0,255) 470 pixels.show() 471 elif dat == b'J#': 472 pixels.fill(255,255,0) 473 pixels.show() 474 elif dat == b'K#': 475 pixels.fill(0,255,255) 476 pixels.show() 477 elif dat == b'L#': 478 pixels.fill(255,0,255) 479 pixels.show() 480 elif dat == b'N#': 481 water() 482 elif dat == b'P#': 483 horse() 484 elif dat == b'Q#': 485 breathing() 486 elif dat == b'M#': 487 pixels.fill(0,0,0) 488 pixels.show() 489 i = 0 490 brightness = 0 491 fadeAmount = 1 492 #mode 493 elif dat == b'S#': 494 line() 495 elif dat == b'T#': 496 avoid() 497 elif dat == b'U#': 498 voice() 499 elif dat == b'V#': 500 oled.fill(0) 501 oled.show() 502 pixels.fill(0,0,0) 503 pixels.show() 504 Motor.Car_Stop() 505 BZ.duty_u16(0) 506 time.sleep(0.01)
在这个程序中,整合了之前的课程的程序,例如呼吸灯部分是3.4节的程序,超声波避障部分是5.6节的程序。在这个程序也同样用到了定时中断Timer来做定时上报超声波、声音、电池数据给APP显示。
from pico_car import SSD1306_I2C, pico_car, ws2812b, ultrasonic
使用pico_car 的SSD1306_I2C、ultrasonic、pico_car、ws2812b,封装了电机驱动和RGB灯、OLED、超声波库。
import time
“time”库。 这个库处理所有与时间有关的事情,从测量它到将延迟插入到程序中。单位为秒。
from machine import Pin, I2C, PWM, Timer, UART, ADC
机器库包含MicroPython需要与Pico和其他MicroPython兼容的设备通信的所有指令,扩展了物理计算的语言,这里用了Pin、PWM、Timer、UART、ADC和I2C的库。
Motor = pico_car()
初始化电机驱动。
Motor.Car_Run(255,255)
控制小车前进,速度设置为255,参数分别为(左电机速度,右电机速度),速度范围0-255。
Motor.Car_Stop()
控制小车停止。
Motor.Car_Back(255,255)
控制小车后退。
Motor.Car_Run(0,255)
控制小车左转。
Motor.Car_Run(255,0)
控制小车右转。
Motor.Car_Left(255,255)
控制小车左旋。
Motor.Car_Right(255,255)
控制小车右旋。
pixels = ws2812b(num_leds, 0)
初始化RGB灯,我们有8个RGB灯,这里num_leds设置为8。
pixels.fill(0,0,0)
把所有的灯设置为0,0,0,也就是关闭所有灯,参数分别是(红色,绿色,蓝色),颜色亮度是0-255。
pixels.set_pixel(1,150,0,150)
把第一个灯设置为紫色。
pixels.show()
把设置的灯显示出来。
BZ = PWM(Pin(22))
将IO22设置为PWM输出引脚,用于控制蜂鸣器。
BZ.freq(1000)
将PWM频率设置为1000。
BZ.duty_u16(0)
数值为0的时候关闭声音,为500的时候开启声音。
ultrasonic = ultrasonic()
初始化超声波测距。
distance = ultrasonic.Distance_accurate()
将超声波测距返回的数值,赋值给变量distance 。
i2c=I2C(1, scl=Pin(15),sda=Pin(14), freq=100000)
设置IIC 1引脚为SCL 15,SDA 14,频率为100000。
oled = SSD1306_I2C(128, 32, i2c)
初始化OLED的大小为128*32,并把前面设置的IIC参数传进去。
oled.show()
把设置的OLED内容显示出来。
oled.fill(0)
清除设置的内容,准备下一次显示。
oled.text('Run', 0, 0)
在OLED的0,0位置显示'Run'。
tim = Timer()
初始化定时中断。
tick(timer)
定时中断函数,在函数中使用变量times_做时间控制,从而控制RGB等切换速度。
tim.init(freq = 0.5,mode = Timer.PERIODIC,callback = tick)
设置定时中断函数和频率。
machine.ADC(28)
初始化ADC端口28。
Sound.read_u16()/65535*200
读取声音传感器数值,转换成0-100的范围。
Quantity_of_electricity.read_u16()/65535*240
读取电量数值,转换成0-100的范围。
uart = UART(0, 9600, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17))
初始化蓝牙串口UART 0 ,引脚TX 16, RX 17,波特率9600,数据位8位,停止位1,没有奇偶校验位。
uart.write('$DAT')
通过蓝牙发送$DAT给APP。
uart.any()
读取串口数据,当接到任意数据时会返回数据。
dat = uart.read(2)
读取两个数据,并赋值给变量dat,通过判断这个变量的值来做出不同的动作。
Tracing_1 = machine.Pin(2, machine.Pin.IN)
初始化引脚2作为巡线传感器1的脚,设置为输入。
Tracing_1.value()
Tracing_1.value()函数用来检测对应端口的电平高低。
stroled_1 = stroled_1.replace("b'", "")
把变量stroled_1中的 b' 字符串替换为空,即去掉 b' 字符串。
六、通讯协议
程序下载完成之后,按照以下协议运行小车。
小车运动 | 协议内容 |
---|---|
前进 | A# |
后退 | B# |
左转 | C# |
右转 | D# |
左旋 | E# |
右旋 | F# |
停止 | 0# |
音乐播放 | 协议内容 |
do | 1# |
ri | 2# |
mi | 3# |
fa | 4# |
su | 5# |
la | 6# |
xi | 7# |
无 | O# |
高Do | 8# |
do# | W#1 |
ri# | W#2 |
fa# | W#3 |
su# | W#4 |
la# | W#5 |
七彩车灯 | 协议内容 |
红 | G# |
绿 | H# |
蓝 | I# |
黄 | J# |
青 | K# |
品红 | L# |
关闭 | M# |
七彩灯效 | 协议内容 |
流水灯 | N# |
跑马灯 | P# |
呼吸灯 | Q# |
关闭 | M# |
模式选择 | 协议内容 |
巡线模式 | S# |
超声波避障 | T# |
声控小车 | U# |
退出模式 | V# |
OLED显示(每行data不超过16个字符) | 协议内容 |
第一行 | X#data |
第二行 | Y#data |
第三行 | Z#data |
主动上报数据 | 协议内容 |
$DAT120,99,98# | 超声波距离:120 |
声音值:99 | |
电量:98 |