×

隐藏迷宫映射器开源硬件

消耗积分:0 | 格式:zip | 大小:1.85 MB | 2022-12-16

李俊

分享资料个

描述

哦,我是不是又买了更多的东西

我前段时间购买了一些磁性位置传感器,打算在另一个有趣的项目中使用它们。由于缺乏时间和灵感,该项目仍处于搁置状态。前几天清理我的桌子时,我看到了传感器,并想我至少应该尝试一下。我以前从未尝试过类似的东西,所以未来有新的学习!

找到一个“问题”来解决!

在平行宇宙中,有很多人对各种可以想象的谜题感兴趣。一种类型的谜题是隐藏的圆柱形迷宫。这些有很多实现,从便宜的 3D 打印(示例)到独家机加工金属(如REVOMAZE )。由于其中一些谜题的复杂性,求解器需要超越记忆并开始映射谜题。映射可以通过多种方式完成,最常见的是笔和纸以及测量旋转和平移。

作为一个拼图和创客极客,我看到了构建自动绘图设备的绝佳机会!

 

我从 OpenSCAD 开始,虽然我打算为拼图和磁性编码器制作一个漂亮的 3D 打印支架。有一段时间很有趣,但是当我弄清楚如何对轴的平移进行编码时,我陷入了细节之中。乐高来救场!在对乐高积木进行了短暂的挖掘之后,我找到了我需要的东西。

pYYBAGOYr1uANyenAACRxOAnCT0338.png
这是一个死胡同
 

CAD 时间并没有完全白费,我仍然需要小磁铁支架。你看,显然磁性编码器需要让磁场垂直于传感器。我拥有的所有小磁铁都是圆柱形的,一面朝北,一面朝南。3D打印机来救援!

 
 
 
poYBAGOYr2mAKhfhAAWfv2dWb2Q841.jpg
 
1 / 2磁铁垂直仪!
 

乐高积木是一个带有小传感器汽车的简单坡道!

poYBAGOYr4KAAC8lAAdXOmq1Ixw301.jpg
感应车!
 

3D 打印的磁铁支架在触摸时将 8 毫米磁铁与传感器相距 1 毫米,这似乎工作得很好。现在把它们放在一起:

 
 
 
pYYBAGOYr52AVzy8AAfDh4Mmh3U647.jpg
 
1 / 3钻机
 

嗯,这就是整个构建。几乎。当然还有一些事情要做......

电子产品和 Arduino 代码

磁性旋转位置传感器使用 I2C 接口,易于连接。互联网上有大量示例代码。但是,有一个但是要连接相同的编码器,我需要一个 I2C 多路复用器,因为无法更改它们的地址,而 Arduino 只有一个 I2C 总线可用。真可惜。

poYBAGOYr6CADD7zAABbOWqlRwE612.png
2个你想要的!然后你会想要更多!:-)
 

由于我没有这样的多路复用器,我开始考虑构建一个,但后来我想一定有一种方法可以在常规 GPIO 引脚上执行 I2C?是的你可以。SlowSoftI2CMaster来救援!10 分钟后,我从 Arduino Uno 读取了两个传感器。

电气连接对于图表来说太简单了。3.3v 和 GND 连接到两个传感器,A2/A3 连接到一个,A4/A5 连接到第二个(选择 Ax 引脚只是因为默认的 I2C 引脚是 A4/A5)。也许某处应该有一个上拉电阻,但是嘿-it-works-tm。:-)

Arduino上的代码很简单。读取传感器,串行打印:

#include 

SlowSoftI2CMaster si1 = SlowSoftI2CMaster(A4, A5, true);
SlowSoftI2CMaster si2 = SlowSoftI2CMaster(A2, A3, true);
 
#define I2C_7BITADDR 0x36 //AS5600

#define RAW_ANG_HI 0x0c
#define RAW_ANG_LO 0x0d
  
void setup(void) {
  Serial.begin(115200);
  
  if (!si1.i2c_init()) Serial.println("I2C init 1 failed");
  if (!si2.i2c_init()) Serial.println("I2C init 2 failed");
}

int readAngle(SlowSoftI2CMaster si) {
  if (!si.i2c_start((I2C_7BITADDR<<1)|I2C_WRITE)) {
      Serial.println("I2C device busy");
      delay(500);    
      return -1;
  }
  
  si.i2c_write(RAW_ANG_HI);
  si.i2c_rep_start((I2C_7BITADDR<<1)|I2C_READ);
  byte val_hi = si.i2c_read(true);

  si.i2c_write(RAW_ANG_LO);
  si.i2c_rep_start((I2C_7BITADDR<<1)|I2C_READ);
  byte val_lo = si.i2c_read(true);

  si.i2c_stop();

  return val_hi<<8 | val_lo;  
}

void loop(void){
  
  long val1 = readAngle(si1);
  long val2 = readAngle(si2);

  Serial.print("Sensor1=");
  Serial.print(val1);
  Serial.print("  Sensor2=");
  Serial.println(val2);
    
  delay(10);
}

电脑上的软件

我在我的笔记本电脑上做了一个可视化软件。简而言之,它是这样工作的:

  • Arduino 在串行端口上输出线路,如“Sensor1=1234 Sensor2=456”。值是原始传感器值 0-4095。
  • 我通过“sudo cu -l /dev/cu.usbmodem14101 -s 115200 > /tmp/cu_out.txt”将串行数据读入常规文件(这适用于 MacOS)
  • 我有一个 Java 程序,我通过管道将文件作为输入。该程序获取每个读数并将其转换为屏幕坐标,并将最近的读数涂成红色,将所有历史读数涂成绿色。
  • 这个程序写得太差了,我会把你从代码中拯救出来。有穿线。我用 AWT 来取笑。坐标系变换完全混乱。任何具有任何编码经验的人都应该能够立即更好地编写此代码,或者能够学会这样做。我不会分享这段代码。对不起。
poYBAGOYr8CAYY44AAnIV6lYVwM776.jpg
这就是它的外观。注意左下角发生的一些错位。乐高汽车不是 100% 与迷宫的轴线对齐,并且在急速解决时轮胎有时会打滑。
 

学习

  • “Grove - 12 位磁性旋转位置传感器/编码器 (AS5600)”太棒了!
  • I2C 易于使用,但类似设备的寻址可能会出现问题。如果您想要 I2C,请为自己准备一个带有多路复用器的分线板!
  • 我学会了如何从我的 Mac 上的串口读取数据!一个简单的命令,我就有了一个文件中的数据,可以被任何语言编写的任何程序使用。使用奇怪的串口库等零复杂性。使用“tail -f”进行调试。美丽的!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'隐藏迷宫映射器开源硬件',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);