亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

自制 Arduino 测距仪与电子水平仪——分步详解

概述

本教程将学习如何制作一个 Arduino 测距仪和电子水平仪。你可以观看下方视频或阅读以下图文教程。

设备包含超声波测距模块、加速度计测倾角、LCD 显示屏和定制 PCB。

自制 Arduino 测距仪与电子水平仪——分步详解

单按钮操作:上电后先选择单位制;短按切换单位,长按进入第一个程序(测距,可存储最近两次测量)。

自制 Arduino 测距仪与电子水平仪——分步详解

再次长按进入第二程序(测面积:两次垂直测距相乘)。

自制 Arduino 测距仪与电子水平仪——分步详解

第三程序为电子水平仪,测量相对地面的角度,短按切换俯仰/横滚轴。

自制 Arduino 测距仪与电子水平仪——分步详解

Arduino 测距仪电路原理图

自制 Arduino 测距仪与电子水平仪——分步详解

相关模块教程:超声波传感器教程、LCD 教程、MEMS 加速度计教程。

所需组件:

定制 PCB 设计

按原理图用 EasyEDA 设计 PCB,导出 Gerber 文件,JLCPCB 制板(首单 10 片 $2)。

自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解

设备组装

PCB 到货质量优秀。焊排针、三个电阻(两个分压调 LCD 对比度:R1 1k、R2 220Ω;一个按钮上拉)。

自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解

外壳用透明亚克力(5mm 顶盖、其余 4mm),圆锯切割,钻孔开槽装 LCD、开关、按钮、超声波模块。环氧胶组装,顶盖用螺栓+螺母固定。

自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解

LCD、开关、按钮、电池扣焊排针/跳线,装入超声波模块、Arduino、MPU6050、电池扣,盖顶盖拧螺母。9V 电池供电,硬件完成。

自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解
自制 Arduino 测距仪与电子水平仪——分步详解

Arduino 测距仪与电子水平仪源代码

代码分段讲解,文末附完整代码。

库与变量定义

#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int MPU = 0x68;
#define trigPin 8
#define echoPin 9
#define selectButton 10
int16_t AcX, AcY, AcZ;
long duration;
float distance;
int program = 0;
float d = 0, d1 = 0, d2 = 0, area = 0;
int axis = 0, angle = 0;
int unitSelect = 0;
String unit = "cm";

setup 初始化

void setup() {
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B); Wire.write(0); Wire.endTransmission(true);
  lcd.begin(16, 2);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(selectButton, INPUT_PULLUP);
}

主循环:状态机切换程序

case 0:选择单位(cm/in/m/ft),短按切换,长按 >0.5s 进入程序 1。

case 0:
  lcd.setCursor(0,0); lcd.print("Select Unit: "); lcd.setCursor(13,0); lcd.print(unit); lcd.print(" "); delay(10);
  if (digitalRead(selectButton)==0) {
    if (unitSelect==0) { unit="in"; unitSelect=1; }
    else if (unitSelect==1) { unit="m"; unitSelect=2; }
    else if (unitSelect==2) { unit="ft"; unitSelect=3; }
    else if (unitSelect==3) { unit="cm"; unitSelect=0; }
    delay(500);
    if (digitalRead(selectButton)==0) { program=1; lcd.clear(); delay(500); }
  }
  break;

单位换算在 getDistance() 中根据 unitSelect 将基础 cm 转换。

if (unitSelect==1) { distance=distance; unit="cm"; }
else if (unitSelect==2) { distance*=0.393701; unit="in"; }
else if (unitSelect==3) { distance*=0.01; unit="m"; }
else if (unitSelect==0) { distance*=0.0328; unit="ft"; }

case 1:测距程序。调用 getDistance() 获取距离,显示并可短按存储最近两次测量(d 变量切换 0/1),长按进入程序 2。

case 1:
  distance = getDistance();
  lcd.setCursor(0,0); lcd.print("Dist: "); lcd.print(distance); lcd.print(" "); lcd.setCursor(14,0); lcd.print(unit); delay(10);
  lcd.setCursor(0,1); lcd.print("d:"); lcd.setCursor(8,1); lcd.print("d:"); delay(200);
  if (digitalRead(selectButton)==0) {
    if (d==0) { lcd.setCursor(0,1); lcd.print("d: "); lcd.setCursor(2,1); lcd.print(distance); d=1; delay(100); }
    else if (d==1) { lcd.setCursor(8,1); lcd.print("d: "); lcd.setCursor(10,1); lcd.print(distance); d=0; delay(100); }
    delay(500);
    if (digitalRead(selectButton)==0) { program=2; d=0; lcd.clear(); delay(500); }
  }
  break;

getDistance() 自定义函数:触发超声波,pulseIn 读取回波时间,按声速计算距离(cm),再按 unitSelect 换算单位。

float getDistance() {
  digitalWrite(trigPin, LOW);
  digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.034 / 2;
  // 单位换算同上
  return distance;
}

case 2:测面积程序。两次垂直测距相乘,d 变量 0/1/2 分别对应等待第一次、第二次、显示结果。短按存储 d1/d2 并计算面积,第三次短按清零重测,长按进入程序 3。

case 2:
  distance = getDistance();
  lcd.setCursor(0,0); lcd.print("Area: "); lcd.print(area); lcd.setCursor(12,0); lcd.print(unit); lcd.print("^2"); delay(200);
  if (d==0) { lcd.setCursor(0,1); lcd.print("d1: "); lcd.setCursor(3,1); lcd.print(distance); delay(200); }
  else if (d==1) { lcd.setCursor(9,1); lcd.print("d2: "); lcd.setCursor(12,1); lcd.print(distance); delay(200); }
  else if (d==2) { lcd.setCursor(6,0); lcd.print(area); delay(200); }
  if (digitalRead(selectButton)==0) {
    if (d==0) { lcd.setCursor(0,1); lcd.print("d1: "); lcd.setCursor(3,1); lcd.print(distance); d=1; d1=distance; delay(100); }
    else if (d==1) { lcd.setCursor(9,1); lcd.print("d2: "); lcd.setCursor(12,1); lcd.print(distance); d=2; d2=distance; area=d1*d2; delay(100); }
    else if (d==2) { lcd.clear(); d=0; area=0; delay(100); }
    delay(500);
    if (digitalRead(selectButton)==0) { program=3; d=0; lcd.clear(); delay(500); }
  }
  break;

case 3:测角程序。读取 MPU6050 六个寄存器合成 X/Y/Z 轴加速度值,根据公式计算俯仰或横滚角(参考 Freescale 应用笔记《使用三轴加速度计的倾斜感测》)。axis 0 显示 Pitch,1 显示 Roll,短按切换,长按回到程序 0。

case 3:
  Wire.beginTransmission(MPU); Wire.write(0x3B); Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true);
  AcX = Wire.read()<<8 | Wire.read();
  AcY = Wire.read()<<8 | Wire.read();
  AcZ = Wire.read()<<8 | Wire.read();
  if (axis==0) { angle = atan(-1*AcX/sqrt(pow(AcY,2)+pow(AcZ,2)))*180/PI; lcd.setCursor(0,0); lcd.print("Pitch"); }
  else if (axis==1) { angle = atan(-1*AcY/sqrt(pow(AcX,2)+pow(AcZ,2)))*180/PI; lcd.setCursor(0,0); lcd.print("Roll "); }
  lcd.setCursor(0,1); lcd.print("Angle: "); lcd.print(abs(angle)); lcd.print(" "); lcd.setCursor(10,1); lcd.print("deg"); delay(200);
  if (digitalRead(selectButton)==0) {
    if (axis==0) { axis=1; delay(100); }
    else if (axis==1) { axis=0; delay(100); }
    delay(500);
    if (digitalRead(selectButton)==0) { program=0; lcd.clear(); delay(500); }
  }
  break;

完整源代码

/* DIY Digital Range Measurer and Spirit Level by Dejan Nedelkovski, www.HowToMechatronics.com */
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int MPU = 0x68;
#define trigPin 8
#define echoPin 9
#define selectButton 10
int16_t AcX, AcY, AcZ;
long duration;
float distance;
int program = 0;
float d = 0, d1 = 0, d2 = 0, area = 0;
int axis = 0, angle = 0;
int unitSelect = 0;
String unit = "cm";
void setup() {
  Wire.begin(); Wire.beginTransmission(MPU); Wire.write(0x6B); Wire.write(0); Wire.endTransmission(true);
  lcd.begin(16, 2);
  pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(selectButton, INPUT_PULLUP);
}
void loop() {
  switch (program) {
    case 0:
      lcd.setCursor(0,0); lcd.print("Select Unit: "); lcd.setCursor(13,0); lcd.print(unit); lcd.print(" "); delay(10);
      if (digitalRead(selectButton)==0) {
        if (unitSelect==0) { unit="in"; unitSelect=1; }
        else if (unitSelect==1) { unit="m"; unitSelect=2; }
        else if (unitSelect==2) { unit="ft"; unitSelect=3; }
        else if (unitSelect==3) { unit="cm"; unitSelect=0; }
        delay(500);
        if (digitalRead(selectButton)==0) { program=1; lcd.clear(); delay(500); }
      }
      break;
    case 1:
      distance = getDistance();
      lcd.setCursor(0,0); lcd.print("Dist: "); lcd.print(distance); lcd.print(" "); lcd.setCursor(14,0); lcd.print(unit); delay(10);
      lcd.setCursor(0,1); lcd.print("d:"); lcd.setCursor(8,1); lcd.print("d:"); delay(200);
      if (digitalRead(selectButton)==0) {
        if (d==0) { lcd.setCursor(0,1); lcd.print("d: "); lcd.setCursor(2,1); lcd.print(distance); d=1; delay(100); }
        else if (d==1) { lcd.setCursor(8,1); lcd.print("d: "); lcd.setCursor(10,1); lcd.print(distance); d=0; delay(100); }
        delay(500);
        if (digitalRead(selectButton)==0) { program=2; d=0; lcd.clear(); delay(500); }
      }
      break;
    case 2:
      distance = getDistance();
      lcd.setCursor(0,0); lcd.print("Area: "); lcd.print(area); lcd.setCursor(12,0); lcd.print(unit); lcd.print("^2"); delay(200);
      if (d==0) { lcd.setCursor(0,1); lcd.print("d1: "); lcd.setCursor(3,1); lcd.print(distance); delay(200); }
      else if (d==1) { lcd.setCursor(9,1); lcd.print("d2: "); lcd.setCursor(12,1); lcd.print(distance); delay(200); }
      else if (d==2) { lcd.setCursor(6,0); lcd.print(area); delay(200); }
      if (digitalRead(selectButton)==0) {
        if (d==0) { lcd.setCursor(0,1); lcd.print("d1: "); lcd.setCursor(3,1); lcd.print(distance); d=1; d1=distance; delay(100); }
        else if (d==1) { lcd.setCursor(9,1); lcd.print("d2: "); lcd.setCursor(12,1); lcd.print(distance); d=2; d2=distance; area=d1*d2; delay(100); }
        else if (d==2) { lcd.clear(); d=0; area=0; delay(100); }
        delay(500);
        if (digitalRead(selectButton)==0) { program=3; d=0; lcd.clear(); delay(500); }
      }
      break;
    case 3:
      Wire.beginTransmission(MPU); Wire.write(0x3B); Wire.endTransmission(false);
      Wire.requestFrom(MPU, 6, true);
      AcX = Wire.read()<<8 | Wire.read();
      AcY = Wire.read()<<8 | Wire.read();
      AcZ = Wire.read()<<8 | Wire.read();
      if (axis==0) { angle = atan(-1*AcX/sqrt(pow(AcY,2)+pow(AcZ,2)))*180/PI; lcd.setCursor(0,0); lcd.print("Pitch"); }
      else if (axis==1) { angle = atan(-1*AcY/sqrt(pow(AcX,2)+pow(AcZ,2)))*180/PI; lcd.setCursor(0,0); lcd.print("Roll "); }
      lcd.setCursor(0,1); lcd.print("Angle: "); lcd.print(abs(angle)); lcd.print(" "); lcd.setCursor(10,1); lcd.print("deg"); delay(200);
      if (digitalRead(selectButton)==0) {
        if (axis==0) { axis=1; delay(100); }
        else if (axis==1) { axis=0; delay(100); }
        delay(500);
        if (digitalRead(selectButton)==0) { program=0; lcd.clear(); delay(500); }
      }
      break;
  }
}
float getDistance() {
  digitalWrite(trigPin, LOW);
  digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.034 / 2;
  if (unitSelect==1) { distance=distance; unit="cm"; }
  else if (unitSelect==2) { distance*=0.393701; unit="in"; }
  else if (unitSelect==3) { distance*=0.01; unit="m"; }
  else if (unitSelect==0) { distance*=0.0328; unit="ft"; }
  return distance;
}

希望你喜欢这个 Arduino 项目并学到了新知识。欢迎在评论区提问。

制造工艺

  1. Arduino 自制 DCC 命令站:蓝牙控制模型铁路,免费 App 支持 CV 读写
  2. Arduino 数字骰子:LCD 显示随机点数的电子骰子
  3. Arduino UNO 驱动 16x2 LCD 实现动画与小游戏
  4. Arduino 音频频率检测:基于 FFT 测量最响亮声音峰值
  5. 自制 Arduino 电子宠物「Tamaguino」:复刻经典 Tamagotchi 全攻略
  6. Arduino 井字棋游戏:MAX7219 点阵屏 + 纸板外壳 DIY
  7. Arduino DIY 电压表:Nokia 5110 屏幕显示,手把手教学
  8. 使用 SparkFun 7 段数码管构建可靠的 Arduino 倒计时器
  9. Python 3 控制 Arduino UNO - 串口通信点亮内置 LED 入门教程
  10. 使用 Arduino Nano 和 RDA8057M 制作紧凑型 FM 收音机
  11. DIY 集水坑液位监测仪 - Arduino Nano、MPXV5010DP 与 OLED 显示
  12. 自制 Arduino 遥控保时捷赛车:从改装底盘到手机 App 控制全攻略