×

远方典当开源分享

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

李泳瑜

分享资料个

描述

项目原因

在我访问和生活过的许多国家,公园里都有带棋盘的桌子。游客们习惯在那儿下棋,经常和不知名的对手下棋。

作为一个国际象棋爱好者,我第一次看到几个棋手享受户外新鲜空气,公园里阳光明媚的一天,以及一场精彩的国际象棋挑战时,给我留下了深刻的印象。

在您看到两名棋手在下棋的地方,您还会看到一小群国际象棋爱好者跟随比赛并对棋步进行评论。

与偶然的对手下棋

如今,由于社会疏远规则,这种做法不再可能或非常困难。这就是我决定考虑如何找到一种低成本且可靠的方法来解决这个问题的原因。诞生了“远方典当”项目。

Playing in the Post-COVID Era

为了保持与保持社交距离的对手在任何地方下棋成为可能,每个玩家都将使用单独的棋盘。

每个棋盘格都有一个传感器,能够检测棋子的拾取和放置移动,以跟踪两个玩家的棋子;当一个玩家在他的棋盘上移动时,同样的移动被发送到对手的棋盘,这将使棋子在正确的位置上移动并形成自己的棋子。

以此类推,直到游戏结束。

解决方法

该解决方案基于两个 MKR WiFi 1010 和一些额外的硬件。

注意:由于难以在合理的时间内找到我计划在原始设计中使用的霍尔效应传感器,我使用 Omron 的超小型微动开关更改了棋子移动检测。棋盘格阅读方法保持不变。

(1) 从原型到生产——根据整个系统的设计,潜在的产品版本将使用霍尔效应传感器进行棋子检测。这具有在不影响设计的情况下简化硬件设计的优点。该方法的工件检测可以在工件底座内部使用小磁铁(用直径3毫米的钕测试,效果满意)或直接使用金属工件进行检测。

The Game Workflow

  • 当棋子在游戏过程中被放置或移除时,它会被检测到。
  • Arduino MKR1010 检测所有棋子的位置并验证移动或生成错误消息并且不接受移动。
  • RGB LED 以不同颜色显示游戏状态,例如等待移动(绿色)、等待对手移动(红色)、系统启动(蓝色)、链接启用(青色)等。
  • 游戏遵循标准规则。当棋子被移动时(如果不是错误的移动),玩家有义务使用该棋子进行移动。
  • Arduino MKR1010 验证移动并更新两个玩家的显示。
  • Arduino MKR1010 考虑到两个玩家的状态以及每一步棋子在棋盘上的位置;它还可以作为经典国际象棋计时器中通常存在的每一步和其他功能的游戏验证器。
  • 两个 Arduino MKR1010 通过点对点 WiFi 连接连接在一起:两个设备之一设置为 AP(接入点),而另一个可以连接到它。

IMPORTANT NOTE: THE OFFICIAL PROTOTYPE TEST WILL BE ON THE SECOND MID OF THE MONTH OF SEPTEMBER 2020 IN A SMALL TOURNAMENT OUTDOOR – RESPECTING THE SOCIAL DISTANCE.

THE EVENT WILL BE DOCUMENTED AND FILMED.

TO READ MORE IN-DEPTH THE STORY BEHIND THIS PROJECT, UPDATES AND MORE HOW-TO MATERIAL, AS WELL AS THE LAST UPDATES, FOLLOW THE DETAILS ON THE PROJECT WEBSITE WE-ARE-BORG.COM

棋盘广场

poYBAGOYHvmAMy-OAAEL2PcwyCQ94.jpeg
棋盘方模块引用草图
 

拿到微动开关后,根据上面的草图,我用Fusion360设计了游戏板的方形模块,嵌入了微动开关,如下图所示:

然后用 Elegoo Saturn 3D 打印机打印出正方形。

 
 
 
poYBAGOYHwaAW4AEAAC0h5yeqOQ835.png
 
1 / 4用于 8x8 方格棋盘的国际象棋游戏板模块
 

在下图中,内部带有微动开关的威廉希尔官方网站 板的第一个原型。

 
 
 
pYYBAGOYH0uACg3IAAsh6K7JR5I861.jpg
 
1 / 8第一个内置欧姆龙微动开关的方形板原型。使用 Elegoo Saturn 4K LCD 3D 打印机打印。
 

制作两个原型棋盘

 

两个棋盘的原型是3D打印128个方格,涂漆,然后用氰基丙烯酸酯胶粘在一起。这部分工作需要大量的时间,对Elegoo Saturn LCD 3D打印机以及大约2、5L的感光树脂进行了强大的性能测试。

 
 
 
poYBAGOYH1OAfYoKAALR9JUlZaw28.jpeg
 
1 / 2
 

上面的图片显示了我是如何将他画的正方形组装和粘合在一起的。

为了制作微动开关的连接网格,我要感谢Element14 社区的朋友Baldengineer ,他发表了一篇关于如何使用 Arduino 管理开关网格的精彩文章(来源:Arduino Keyboard Matrix Code)。

(2) 从原型到生产- 使用上述方法制作棋盘非常适合原型制作,但对于生产来说并不可靠。如果使用 3D 打印机进行原型制作留下了很多可能来修改设计、进行实验并找到解决方案的最佳方法,如果这款游戏将投入生产,那么应该选择更高效、更快速的方式来创建棋盘。实际上,大多数取决于单元的数量;对于市场测试预生产,使棋盘激光切割可能是一个不错的选择。我已经评估了如何采用一种有效的方法来创建具有两种颜色之一的棋盘底,并带有用于替代颜色方块的插图。

制作棋子

下面是用 Elegoo Saturn LCD 打印机 3D 打印并上色的棋子的第一个系列(两个对手)的画廊。

 
 
 
poYBAGOYH1eADlXeAACLjC84xEA452.jpg
 
1 / 4
 

这些作品来自Thingiverse ,感谢作者FunFunBoy ,他在 CC 许可下许可了 STL 文件。

硬件游戏控制器

组装硬件非常简单。考虑到 Arduino MKR1010 的外形尺寸,我做了一个小型定制屏蔽来承载 Oled 128x64 I2C 显示器和用于警报的 RGB LED。

poYBAGOYH1qAdd5RAACbn8WjV8Q695.jpg
为该项目制造的 MKR1010-shield 的组件
 

链接到 I2C Oled 显示器我还连接了两个基于 8 针双向 GPIO 扩展器PCF8574的小板(固定在棋盘的底部)

我已经使用了两个预制板来节省时间,而不是使用 IC 组件制作(简单)板,因为我担心总线协议的数据传输中的潜在问题。

pYYBAGOYH6SAcbH8AAsF4wuF0gI942.jpg
面包板测试连接到 Arduino MKR1010 的 I2C 组件
 

在继续制作 MKR1010 扩展板之前,我测试了两个 GPIO 扩展器,但没有任何效果:(不仅是当我试图更改 I2C 地址的板跳线设置时,整个 Arduino 板都短路了。

Weird!

测试表明,这些板只有在设置默认 I2C 地址时才能正常工作,对应于所有三个连接到 GND 的跳线。尝试任何其他配置会使微控制器短路。所以我决定牺牲其中一块板子,清洗威廉希尔官方网站 (幸运的是,它只是双面PCB),看看电线的路径。结果:无论地址跳线设置如何,威廉希尔官方网站 始终将所有三个引脚连接到 GND。如果其中一个跳线设置为 VCC,则会产生短路。

pYYBAGOYH9SAT0mqAAlWomx3IXQ476.jpg
手工制作的 I2C GPIO 扩展板新版本。
 

我想这些在亚马逊上出售的“原装”板只是假的;谁克隆了这个非常简单的威廉希尔官方网站 完全失败了。很难找到这个问题,因为每块板在测试时都可以正常工作;只有在更改 I2C 地址时才会出现 I2C 问题。

已经将威廉希尔官方网站 板放在我的桌子上,而且时间很少,我破解了其中一些,破坏了设置跳线引脚之间的 PCB 轨道。板子终于可以使用任何地址配置了!

poYBAGOYH9uAOP74AACZCmp_Eh0750.jpg
两个 Arduino MKR1010 已组装好防护罩,并且 GPIO 的行/列连接器(黄色)在安装在棋盘上之前会扩展。
 

在无法对其进行测试之前,我一直非常关注最后一个潜在问题。如上图所示组装屏蔽后,我不确定 I2C 总线信号的质量是否足够——考虑到将两个 GPIO 扩展器连接到另一个 I2C 组件的 20 厘米电线——所以我用示波器检查了;如下图所示,结果非常令人满意,也好于预期。

 
 
 
poYBAGOYH92AfEXkAACOlOSygQ8517.bmp
 
1 / 6I2C 总线信号(SCL 黄色、SDA 蓝色)质量和稳定性测试
 

关于软件的简短说明

虽然构建硬件非常容易,但软件的逻辑几乎是复杂的。它分为四个主要部分:

  • OLED显示屏显示重要消息、最后玩家移动和游戏历史。它是一个消息专用类,包括管理显示游戏状态的 RGB LED 的方法。
  • 棋局控制逻辑它是一个专门的类,用于跟踪移动、验证移动并检查棋子的正确位置。
  • WiFi连接保持打开两个板之间的连接,并通过浏览器将当前游戏公开给连接到 MKR1010 接入点的任何设备。
  • 棋盘扫描仪不断更新程序逻辑使用的所有方块的物理状态。

然后,可以通过 MKR1010 (Serial1) 的 Tx/Rx UART 引脚检查为开发和测试创建的第三部分。

该软件的当前运行版本以及将在未来几周内发布的更新可在 GitHub 存储库上的开源 LGPL 3.0 许可下获得。

使用 Doxygen 创建的软件的完整文档,以及与项目相关的更多材料,可在官方项目页面we-are-borg.com上找到

从原型到生产

我在上面的故事中将这个项目转移到商业产品的假设中必须改变或审查的方面发表了一些评论:我最大的担忧与棋盘和棋子部分有关。我已经回顾了整个项目工作流程,并做了更多的考虑。

Hardware Controller

在我看来,Arduino MKR1010 绝对是解决方案:小尺寸和低功耗。它可以由传统电池供电(不鼓励),但它可以很好地与不可更换的锂离子聚合物电池一起使用传统的 USB 充电器自动充电,以及在使用外部 USB 电池组充电时供电。据我所知,如果硬件没有产生输出信号,电池移动电源(大多数)会停止充电,因为它们是为智能手机充电而设计的。我已经通过简单的代码修改修改了这种潜在的问题:在未使用的引脚上生成的脉冲(这里我们有几个)使外部电池充电器保持活动状态。

pYYBAGOYIA-AAQS9AAmvwupFjU0658.jpg
插入棋盘游戏控制器外壳的 Arduino MKR1010 的底视图。底部引脚已被切割,使控制器易于管理并安装在定制设计的外壳中。
 

如上图所示,为了使 Arduino MKR1010 和防护罩紧凑且可在外壳内使用,我已经从 Arduino 上切下了底部的面包板引脚。可以通过制作定制 PCB 来更好地分配组件,以及使控制器具有更小的外形,在该 PCB 上提供插头(或直接焊接)MKR 1010,而无需引脚连接器阵列。PCB 将同时是具有适当设计外壳的小型 Oled 显示器的威廉希尔官方网站 和支架。

关于 Oled 显示器:我担心这么小的设备并不是这种实施的最佳解决方案,大多数情况下都是为户外使用而设计的。相反,看到显示就位——以及使用不同字体大小和样式轻松管理它的可能性——我发现该解决方案是正确的选择。

pYYBAGOYID-AXD7FAAgbM-xanpw324.jpg
128x64 Oled 显示屏在棋盘游戏控制器的顶视图上的高可见性。
 

关于 I2C GPIO 端口扩展器:此外,在这种情况下,应该设计一个小型专用 PCB(带有几个低调连接器)来代替我用来制作原型的预制板。

Redesigning the Chessboard

毫无疑问,棋盘面应该重新设计。探索几种解决方案,我看到了两种可能的选择:

1. 小型预生产(约50件)

对于这种生产,仍然可以使用微动开关解决方案或 - 更好但更昂贵 - 霍尔效应 IC。棋盘的底部(一个带有传感器孔的矩形)可以很容易地从 3 毫米的亚克力板上用激光切割下来,上面粘有 PVC 胶纸,上面印有双色棋子。棋盘的电子底面设计几乎保持不变。

2. 平均和批量生产(100 件以上)

键盘控制器 I2C 将取代 GPIO 端口扩展器。它可以使用 I2C IC 保持当前的软件设计,其优点是大部分按键工作由 IC 本身完成,而不是 Arduino 控制器。

在这种情况下,两层触摸键盘将取代传感器,但应开发定制设计以及构建物理键盘。


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

评论(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);