Funpack第12期 Wio Terminal实现的热成像仪
Funpack第12期 Wio Terminal AMG8833 BMP180 插值 超声波测距
标签
嵌入式系统
测试
显示
aramy
更新2021-12-27
1279

硬件介绍
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电源,可供模块使用。FqtJ8IM4aMPwR_c4NUpSbZHE25MB

超声波测距模块使用的是5v电源,从Wio Terminal背面40p接口中获得,超声波测距模块的Trig和Echo管脚分别接到Wio Terminal的D0、D1脚。

AMG8833模块、BMP180模块,超声波测距模块一起插到面包板上。
Fq9akNkQru-UcVfsrJmkAeWY3LfZFkbZ8TlmK-i2YWCBt1VQeBXqaAmPFtE6hsHmPmFA6wSkt1f7IobLufu4

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号字体来显示。
FtdnESMNVmlEC9fyoNz07jWAPDNvFl9WpLv9OeMNeYryPvtm1SzGAWH6Fj_n8PhNyhNngRsx9PPtCqJXgFth

心得体会
感谢funpack带来的这期活动。Wio Terminal这款开发板更像是一个功能强大的手持终端。尝试机器学习,但是和图片显示始终有冲突。在Funpack的活动中能够和高手抱团学习,事半功倍!谢谢!

附件下载
homework_amg8833.zip
团队介绍
团队成员
aramy
单片机业余爱好者,瞎捣鼓小能手。
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号