10736浏览
查看: 10736|回复: 12

用小小的滚轮,丈量你周围的“天下”

[复制链接]
本帖最后由 川山甲的壳 于 2017-8-21 13:54 编辑

Arduino UNO——小型测距轮
现在打开百度地图,输入起点和终点,两地之间的距离马上显示在手机屏幕上。相比以往的地图,现在的电子地图,地理信息量更大。距离计算的更加精确。可这么大的面积,是怎么测量出来的呢?卫星、卷尺还是其他的。卫星能勘探地形、地面资源。但所测距离的精确度不高;卷尺灵活性不够,所测的距离不够长。排除以上两种还有其他测距工具吗?前段时间在马路上看见有人手持一个滚轮沿着马路边滚动,觉得很是新奇,上前询问,原来他是地图工作者,现在正在绘制路线,并测量两地之间的距离。原来他所用的就是用测距轮。这种测距工具,方便携带,灵活性高,测量精准度高。回来之后自己也制作了一个小型的测距轮。






测距轮相比传统的卷尺,可以随意滑动,可测正负(向左滑动为正,向右滑动负)。
下面就来看看做的怎么样吧。


配件图


【主要配件】


测距轮的主板我采用的DFRobot最新推出的DFRduino UNO R3的主板,他完全兼容Arduino UNO R3版本。性价比也比较高,相比之下,我更钟意DFRduino UNOR3。因为它采用沉金工艺,外观精致,在追求质量的同时,也提高了颜值 。制作测距尺,还需要一个强大的配件,那就是编码器,这样才能计数。


在这里我采用增量式光电旋转编码器,它能有效的兼容Arduino,PLC等各类主控器。它具有AB两相输出,可以通过旋转的光栅盘和光耦产生可识别方向的计数脉冲信号。其电路输出的类型为NPN集电极开路输出,这样的输出类型可以和内部带上拉电阻的单片机连接,然后实现转速、角度、角速度等数据的测量。
注意:编码器在不接设备的情况下,集电极开路输出,在没有上拉电阻的时候,是没有电压输出的,如要要示波器示波请在AB两相输出上加上两个上拉电阻。如果实际运用,就不需要加上拉电阻了。
用小小的滚轮,丈量你周围的“天下”图2
示波器信号

【部分配件】
电路接线图


实物连接图


【效果图】
Reset:此模式为复位模式,切换到此模式,可以清零所测的数据。这样又可以重新开始测距取值了。

Detection:此模式为测距模式,切换到此模式,可以开始你的表演了,随意测距,上下左右随便滚动,完全无压力。往左滚测得是数值为正,往右滑数值为负(当测距数值为正得时候,往右滑可以看见数值随着减小)。



Lock:此模式为锁定,当你测得一定的距离后,选择到此模式可以锁定数据,随意你怎么滚动,数据都不会改变了,这样你就可以记录数据了。方便吧,按三下按键就可以了哦。
用小小的滚轮,丈量你周围的“天下”图1


为了让携带方便,外观漂亮。我用3D打印机打印了外壳。方方正正的,是不是看起来有点呆板。没办法,我能想到的只是如此了。相信朋友们肯定有更好的创意。3D打印的文件我以附件的形式放在文末了。
注意:因为自己找的轮毂尺寸都不合适,后面自己用3D打印机制作了一个80mm的轮毂。而轮胎还是用的高品质环保ABS硅胶车轮外的轮胎

程序:
[mw_shl_code=cpp,true]#include <Wire.h>
#include "DFRobot_RGBLCD.h"

DFRobot_RGBLCD lcd(16, 2);


//rgb_lcd lcd;

#define A 3
#define B 4
#define Key  12//key

#define D 79 //Diameter 79mm

float C = 0; //perimeter
unsigned int Distance;
int VA = 0;
int VB = 0;
unsigned long Count = 0;//count
unsigned int Count_1 = 0; //Negative count
unsigned char flag = 1, Mark = 0;
unsigned long lasttime = 0, Modetime = 0;

//Length measurement range is ± 6 M
void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.setRGB(255, 255,0);
  lcd.setCursor(2, 0 );
  lcd.print("M:");
  lcd.setCursor(2, 1 );
  lcd.print("D:");
  lcd.setCursor(12, 1 );
  lcd.print("cm");
  pinMode(A, INPUT_PULLUP); //Pull-up input
  pinMode(B, INPUT_PULLUP);
  pinMode(Key, INPUT);
  attachInterrupt(1, interrupt, RISING);
  C = D * PI;
}

void loop()
{
  if (millis() - 150 > lasttime)//Detect keys once every 150ms
  {
    if (digitalRead(Key) == HIGH)
      if (digitalRead(Key) == HIGH)
        Mark += 1;
    if (Mark > 2)
      Mark = 0;

    while (digitalRead(Key) == HIGH);
    lasttime = millis();
  }

  if (millis() - 100 > Modetime)//Refresh the data every 100ms
  {
    if (Mark == 0) //Cleared
    {
      lcd.setCursor(6, 0 );
      lcd.print("Reset    ");
      Distance = C * Count / 40;
      flag = 3;
      lcd.setCursor(11, 0 );
      lcd.print("     ");
    }

    if (Mark == 1) //Calculate the measured value
    {
      lcd.setCursor(6, 0 );
      lcd.print("Detection");//
      lcd.setCursor(4, 1 );
      if (Count > 0 && Count < 0xffff)//Determine whether the length is positive
      {
        lcd.print('-');//The length is negative
        Distance = C * Count / 40;
      }

      else if (Count == 0 && Count_1 == 0 )//Determine whether the length is zero
      {
        lcd.setCursor(4, 1 );
        lcd.print(' ');
        Distance = C * Count / 40;
      }

      else//Length is positive
      {
        lcd.print('+');
        Distance = Count_1 * C  / 40;
      }
    }

    else if (Mark == 2) //lock
    {
      lcd.setCursor(6, 0 );
      lcd.print("Lock     ");
      Count = 0;
      Count_1 = 0;
    }

    Modetime = millis();
  }



  lcd.setCursor(5, 1 );//Displays the value of Distance
  lcd.print(Distance / 10000);
  lcd.print((Distance / 1000) % 10);
  lcd.print((Distance / 100) % 10);
  lcd.print('.');
  lcd.print((Distance / 10) % 10);
  lcd.print(Distance % 10);
}

void interrupt()//Interrupt handler
{
  VB = digitalRead(B);
  if (Mark == 1)//Detects whether the current mode is a measurement
  {
    if (VB == 1)//To determine whether the positive measurement
    {
      flag = 1;
      
      if (Count > 0xffff)
      {
        Count_1 -= 1;
      }

      Count += 1;
    }
   
    else//Reverse measurement
    {
      flag = 0;
      Count -= 1;
      
      if (Count > 0xFFFF)
      {
        Count_1 += 1;
      }
    }
   
    //Count is cleared over the range
    if (Count < 0xFFFF && Count > 0x294A)
      Count = 0;

    else if (Count < 0xFFFFD6B5 && Count > 0xFFFF)
      Count = 0;
  }
}[/mw_shl_code]


测距尺的3D文件.rar

327.89 KB, 下载次数: 2952

hnyzcj  版主

发表于 2017-8-14 13:00:41

这个有意思
回复

使用道具 举报

Forgotten  版主

发表于 2017-8-14 17:10:10

厉害了 轮子没有自己造
回复

使用道具 举报

mickey  NPC

发表于 2017-8-15 17:20:11

400个脉冲的编码器做测距轮,精度是相当的高啊!
回复

使用道具 举报

Rockets  NPC

发表于 2017-8-16 14:25:28

做个把手也好啊……
回复

使用道具 举报

胡秩通  高级技师

发表于 2017-8-18 21:46:29

厉害了库!!!
回复

使用道具 举报

玛斯唐  学徒

发表于 2017-8-19 19:18:13

有几个问题请教,最大测量长度为何是6米啊。int的最大范围是32768,距离=32768*0.079*3.14/40=203米啊?  描述中说按键3次是锁定模式,函数里面有mark>2,mark=0,也就是说按3次mark是0,函数还说 if (Mark == 0) //Cleared ,这个不是清屏的意思么。另外VA是不是没用到啊。最后正负方向怎么判断的啊,是说VB只要是高电平,就是正转么?谢谢
回复

使用道具 举报

川山甲的壳  初级技匠
 楼主|

发表于 2017-8-21 16:41:36

本帖最后由 川山甲的壳 于 2017-8-21 16:47 编辑
玛斯唐 发表于 2017-8-19 19:18
有几个问题请教,最大测量长度为何是6米啊。int的最大范围是32768,距离=32768*0.079*3.14/40=203米啊?   ...

在测量长度的问题上,可以将“unsigned int Distance;”修改成“unsigned long Distance;”;“if (Count < 0xFFFF && Count > 0x294A)”修改成“if (Count < 0xFFFF && Count > 0x8000)”,在lock模式,是当mark==2为锁定。函数if (Mark == 0) 这一块为清零,则清除所有的数据,重新开始测数值,也可以说是清屏。在程序中VA是没有用到。手持滚轮尺,向右为正,向左为负。VB是高电平为正。
回复

使用道具 举报

aeroboy  学徒

发表于 2017-8-24 22:26:23

用5000的编码器精度还能保证吗?
回复

使用道具 举报

miaoichi  见习技师

发表于 2017-8-29 10:08:25

厉害了 顶一个
回复

使用道具 举报

wyu  学徒

发表于 2017-10-16 06:20:41

这个文件下载到芯片有错误的语句
回复

使用道具 举报

川山甲的壳  初级技匠
 楼主|

发表于 2017-10-16 09:10:21

wyu 发表于 2017-10-16 06:20
这个文件下载到芯片有错误的语句

那里有错误?
回复

使用道具 举报

flame  初级技师

发表于 2019-6-22 13:05:27

本帖最后由 flame 于 2019-6-22 13:10 编辑

为什么不用360度霍尔式角度传感器(工业级)呢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail