硬件介绍:
funpack第12期活动推出的开发板为Wio Terminal。是一个自身配有一个2.4英寸 LCD屏幕, 板载IMU(LIS3DHTR),麦克风,蜂鸣器,microSD卡槽,光传感器和940nm红外发射器。两个用于Grove生态系统的多功能Grove接口和兼容Raspberry pi的40个GPIO引脚(管脚分布兼容树莓派).最让人激动地是这个开发板除了支持Arduino和micropython外还支持机器学习!
任务:
本期选择任务1:利用扩展接口,自由选择连接三到五个传感器,并将采集的数据显示在LCD屏幕上,并解释数据的含义。
这里我选用了三个模块:AMG8833模块,这是一个8*8的红外热传感器阵列模块。温度范围为 0°C至80°C;测量距离7米,最大帧率10Hz,通讯方式IIC。BMP180模块,是一个测量气压的模块,压强范围为:300至1100 hPa(海拔9000m至-500m)的大气压,通讯方式也为IIC。超声波测距模块:通过一个超声波发射器发射一束超声波,遇到物体后发射回来,被超声波接收器收到,通过计算声波传播时长,获得障碍物的距离。
实现过程:
1、硬件连接。三个模块中有两个模块为IIC接口。Wio Terminal左侧接口即为IIC的接口,不过插口为Grove接口,手头找不到这种接口的线,于是找了个5P的2.0mm的插头端子线,用美工刀切小后即可插入Grove接口。Grove提供了3.3v电源,可供模块使用。
超声波测距模块使用的是5v电源,从Wio Terminal背面40p接口中获得,超声波测距模块的Trig和Echo管脚分别接到Wio Terminal的D0、D1脚。
AMG8833模块、BMP180模块,超声波测距模块一起插到面包板上。
2、显示规划。屏幕分为两个区域,左侧显示红外热成像的图像。右侧上半区显示障碍物距离和气压值,下半区显示最高温度和最低温度对应颜色的图例。通过图例即可看出图像中颜色对应的温度。
3、编程。编程工具使用Arduino。Wio Terminal官方提供了很完整的说明文档。按着官方提供的文档,先驱动起AMG8833模块。这个红外热成像模块分辨率很低,仅仅为8*8。如果直接显示,画面会看起来非常粗糙。这里使用插值方式将8X8的矩阵扩大到80*80像素的矩阵,这样显示起来效果就好很多了。
//插值算法 8*8点阵过于稀疏,使用插值方式 放大点阵
void zoommix(){
for (row = 0; row < 8; row ++) {
for (col = 0; col < 70; col ++) {
// get the first array point, then the next
// also need to bump by 8 for the subsequent rows
aLow = col / 10 + (row * 8);
aHigh = (col / 10) + 1 + (row * 8);
// get the amount to interpolate for each of the 10 columns
// here were doing simple linear interpolation mainly to keep performace high and
// display is 5-6-5 color palet so fancy interpolation will get lost in low color depth
intPoint = (( pixels[aHigh] - pixels[aLow] ) / 10.0 );
// determine how much to bump each column (basically 0-9)
incr = col % 10;
// find the interpolated value
val = (intPoint * incr ) + pixels[aLow];
// store in the 70 x 70 array
// since display is pointing away, reverse row to transpose row data
HDTemp[ (7 - row) * 10][col] = val;
}
}
for (col = 0; col < 70; col ++) {
for (row = 0; row < 70; row ++) {
// get the first array point, then the next
// also need to bump by 8 for the subsequent cols
aLow = (row / 10 ) * 10;
aHigh = aLow + 10;
// get the amount to interpolate for each of the 10 columns
// here were doing simple linear interpolation mainly to keep performace high and
// display is 5-6-5 color palet so fancy interpolation will get lost in low color depth
intPoint = (( HDTemp[aHigh][col] - HDTemp[aLow][col] ) / 10.0 );
// determine how much to bump each column (basically 0-9)
incr = row % 10;
// find the interpolated value
val = (intPoint * incr ) + HDTemp[aLow][col];
// store in the 70 x 70 array
HDTemp[ row ][col] = val;
}
}
}
获得80X80温度矩阵,每个元素都是一个具体温度值(浮点数)。将温度显示出来有两个办法,方法一:给每个温度指定一个具体的颜色。这样显示的优点是通过颜色就能知道具体的温度,比较好地显示出温度的分布;缺点是,当温差较小时,屏幕上都显示比较接近的颜色,不能很好地显示温差的细节。方法二:将测量到的温度范围映射到颜色,这样优点是能够很好地显示温度差;缺点是不能够直观地通过颜色判断出温度,颜色是动态变幻的。
这里采用的是方法二,将温度范围映射到颜色,蓝色为最低温度,红色为最高温度,然后用图例显示温度范围和温度对应的颜色。
//浮点数转颜色 伪彩色
uint16_t GetColor(float val) {
byte red = 0, green = 0, blue = 0;
red = constrain(255.0 / (c - b) * val - ((b * 255.0) / (c - b)), 0, 255);
if ((val > MinTemp) & (val < a)) {
green = constrain(255.0 / (a - MinTemp) * val - (255.0 * MinTemp) / (a - MinTemp), 0, 255);
} else if ((val >= a) & (val <= c)) {
green = 255;
} else if (val > c) {
green = constrain(255.0 / (c - d) * val - (d * 255.0) / (c - d), 0, 255);
} else if ((val > d) | (val < a)) {
green = 0;
}
if (val <= b) {
blue = constrain(255.0 / (a - b) * val - (255.0 * b) / (a - b), 0, 255);
} else if ((val > b) & (val <= d)) {
blue = 0;
} else if (val > d) {
blue = constrain(240.0 / (MaxTemp - d) * val - (d * 240.0) / (MaxTemp - d), 0, 240);
}
// use the displays color mapping function to get 5-6-5 color palet (R=5 bits, G=6 bits, B-5 bits)
return Display.color565(red, green, blue);
}
获得的8*8的温度矩阵数据后,因为面包板的问题,获得的矩阵在展示时顺时针旋转了90度。为了和实际环境保持一致,将8*8的矩阵逆时针旋转90度,然后再插值、显示。
//对源矩阵进行旋转
//镜像翻转
for(row=0;row<8;row++){
for(col=0;col<4;col++){
val=pixels[row*8+col];
pixels[row*8+col]=pixels[row*8+8-col-1];
pixels[row*8+8-col-1]=val;
}
}
// 对角旋转90度
for(row=0;row<8;row++){
for(col=0;col<row;col++){
val=pixels[row+8*col];
pixels[row+8*col]=pixels[row*8+col];
pixels[row*8+col]=val;
}
}
通过超声波获取环境的距离。超声波测距通过给Trig管脚拉高10us,就会触发超声波测距模块发出一束超声波,开始计时,等待Echo管脚的电平变高(接收到返还的超声波),通过计算时间,就可以测量出障碍物的距离。测试距离=(高电平时间*声速(340M/S))/2 。pulseIn()单位为微秒,每微秒声波走0.017cm,测量出echo管脚低电平时长,就可以直接换算出障碍物的距离了,这里获得的单位为厘米。
//超声波测量距离
uint16_t supwavedist(){
// 产生一个10us的高脉冲去触发TrigPin
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
// 检测脉冲宽度,并计算出距离
return (uint16_t)pulseIn(EchoPin, HIGH)/58.8 ;
}
在Arduino的库中搜索BMP180,即可找到BMP180模块对应的库。安装后直接参考例程,即可驱动BMP180模块。这里遇到个小问题,气压的单位用kPa的话,因为没法去高山,所以气压值基本不变。用Pa做单位,气压值又太长了,显示会乱掉。所以这里将气压值的显示用1号字体来显示。
心得体会:
感谢funpack带来的这期活动。Wio Terminal这款开发板更像是一个功能强大的手持终端。尝试机器学习,但是和图片显示始终有冲突。在Funpack的活动中能够和高手抱团学习,事半功倍!谢谢!