本帖最后由 hnyzcj 于 2021-2-19 10:06 编辑
【项目源起】 军棋的玩法通常有三种:明棋、暗棋和翻棋,其中暗棋是一种知己不知彼的玩法,每人使用一种颜色的棋子,立起来,正面朝向自己摆放,布置自己喜欢的阵法。然后按照规定的行棋方式走棋。想要吃棋的时候,并不知道对面是什么棋,也不能看。这时候,需要第三个人来担任裁判。裁判查看双方的棋子,比大小,小的一方被吃,拿出棋盘(拿出棋盘后也不能暴露是什么棋),大的一方留在棋盘上,直到分出胜负。于是我们决定设计制作一套智能军棋,只需两个玩家对战,不仅解脱裁判的尴尬与无聊,更能让玩家专注局势的博弈,不受裁判影响,极大提升玩家体验,如图1-3所示。
【功能简介】 (1)智能识别:智能军棋通过Huskylens视觉识别传感器扫描放置于擂台上军棋标签,对双方的棋子进行准确识别。 (2)智能评判:智能军棋通过内置算法判断双方出棋等级高低,从而给出胜负的判定。 (3)声光效果:智能军棋搭配音效搭配LED光效,紧张刺激又烧脑,增加玩家的代入感。 (4)磁力吸附:棋子的底部设计有三枚强磁铁,与擂台上的磁铁相互吸附,避免错误摆放。
【硬件材料】 【制作过程】 1.系统设计 在进行系统设计前,我们先来了解下传统军棋的玩法。 (1)吃子规则 一副军旗双方共含有50个棋子,两方各有25个棋子,分别是司令、军长、师长、旅长、团长、营长、连长、排长、工兵、地雷、炸弹、军旗。司令→军长→师长→旅长→团长→营长→连长→排长→工兵,小棋遇大棋被吃,相同棋子相遇,则同归于尽;工兵能排除地雷,其它棋子不能排雷;炸弹与任何棋子相遇时同归于尽,也就是说,在军棋中,司令是最大的,就是司令可以吃一切的棋子。 (2)棋子识别 本作品最初设计时,是想在每枚棋子中放置不同阻值的电阻来予以区分,但通过串口读取数据发现数据误差较大。因此放弃这种方案,采用AprilTag标签进行标识,Huskylens视觉识别传感器进行识别的方案。同时为了防止对方记棋,我们对每一颗棋子都标记了AprilTag,这样一套棋子就需要50个AprilTag标签。这样问题就转换成Huskylens识别标签了问题了。 (3)棋子PK算法 依据军棋的吃子规则,我们对于两个上擂台棋子的PK,只要以下几类问题: ▲军衔PK:这类棋子属于进攻型棋子,只需按照上述军衔等级高低判断胜负,等级相同同归于尽。 ▲工兵拆雷:工兵遇到地雷,则工兵拆除地雷。 ▲工兵扛旗:军棋必须在棋盘中两个大本营中的其中之一,且不可移动。工兵可扛旗,结束棋局。 ▲炸弹处理:防御型棋子,此棋子在棋盘上不可动,只能被动接受PK,任何可动棋子与之相遇两者同归于尽。 ▲地雷处理:防御型棋子,此棋子在棋盘上不可动,只能被动接受PK,除工兵以外的棋子与之相遇两者同归于尽。 针对上述问题进行算法设计,作为双方PK的核心算法。通过Huskylens识别出棋子的ID来判断棋子PK的胜负。 (4)声光效果 为了增加棋局的娱乐性,我们在系统中增加的了声光效果,用绿色光代表胜利,红色光代表失败,并配以适当的音效。
2.结构设计 本次作品结构设计涉及两部分:一部分是棋盘结构,使用LaserMaker绘制结构图。另一部分是3D打印棋子结构件。 (1)棋盘结构件设计(松木板) 首先以3mm厚的松木板为原料,使用“快速造盒工具”,生成一个盒体。然后删除盒体左右两侧,并在盒体顶部,添加“棋盘”图片,并绘制蜂鸣器、Huskylens安装孔位和擂台孔位。具体设计如下图8-9所示。 其次依据上步生成盒体宽(内部)的尺寸绘制棋子收纳盒,具体设计图如下图10所示。 棋子结构件设计(3D打印) 我们在Fusion 360中,设计绘制棋子外壳结构和擂台结构如下图12-13所示。 电路连线 智能军棋系统电路连接如图14所示。两条灯带分别接D7,D8口,蜂鸣器模块接D4口,Huskylens视觉识别传感器通过I2C口与主控Arduino连接。 代码编写 主程序如下图15所示,包含了两个函数“定位识别”、“判断结果”,其中“定位识别”是通过识别到的两个方框中X的坐标值进行比较从而判断,从而判断所对应ID的两颗棋子左右位置;“判断结果”则依据前面定义的算法对两颗棋子进行胜负判定。
- <font face="微软雅黑" size="4">/*!
- * MindPlus
- * uno
- *
- */
- #include <DFRobot_NeoPixel.h>
- #include <DFRobot_HuskyLens.h>
- #include <DFRobot_Libraries.h>
-
- // 动态变量
- String mind_s_M1, mind_s_M2;
- volatile float mind_n_N1, mind_n_N2;
- // 函数声明
- void DF_DingWeiShiBie();
- void DF_CeLiangZuoBiao();
- void DF_N1DaYuN2();
- void DF_N1XiaoYuN2();
- void DF_PanDuanJieGuo();
- void DF_MingChen();
- void DF_DiLeiChuLi();
- void DF_TongGuiYuJin();
- void DF_ZuoBianSheng();
- void DF_ZhaDanChuLi();
- void DF_YouBianSheng();
- void DF_GongBingChaiLei();
- void DF_KangQi();
- void DF_XiangDeng();
- void DF_LXiaoYuR();
- void DF_LDaYuR();
- // 创建对象
- DFRobot_HuskyLens huskylens;
- DFRobot_NeoPixel neoPixel_7;
- DFRobot_NeoPixel neoPixel_8;
- DFRobot_Tone DFTone;
-
-
- // 主程序开始
- void setup() {
- huskylens.beginI2CUntilSuccess();
- huskylens.writeAlgorithm(ALGORITHM_TAG_RECOGNITION);
- neoPixel_7.begin(7, 6);
- neoPixel_8.begin(8, 6);
- neoPixel_7.setBrightness(255);
- neoPixel_8.setBrightness(255);
- mind_n_N1 = 0;
- mind_n_N2 = 0;
- huskylens.clearOSD();
- delay(1000);
- huskylens.writeOSD(String("system is ok"), 84, 35);
- delay(1000);
- }
- void loop() {
- huskylens.request();
-
- DF_DingWeiShiBie();
-
- DF_PanDuanJieGuo();
- }
-
-
- // 自定义函数
- void DF_DingWeiShiBie() {
- mind_n_N1 = (String(huskylens.readBlockParameterDirect(1).xCenter).toInt());
- mind_n_N2 = (String(huskylens.readBlockParameterDirect(2).xCenter).toInt());
- DF_N1XiaoYuN2();
- DF_N1DaYuN2();
- }
- void DF_CeLiangZuoBiao() {
- huskylens.writeOSD(String((String((String(mind_n_N1) + String("===="))) + String(mind_n_N2))), 103, 21);
- delay(1000);
- }
- void DF_N1DaYuN2() {
- if (((mind_n_N2 - mind_n_N1)<0)) {
- huskylens.clearOSD();
- mind_n_N1 = (String(huskylens.readBlockParameterDirect(2).ID).toInt());
- mind_n_N2 = (String(huskylens.readBlockParameterDirect(1).ID).toInt());
- huskylens.writeOSD(String((String((String(mind_n_N1) + String("-------"))) + String(mind_n_N2))), 20, 130);
- delay(500);
- }
- }
- void DF_N1XiaoYuN2() {
- if (((mind_n_N1 - mind_n_N2)<0)) {
- huskylens.clearOSD();
- mind_n_N1 = (String(huskylens.readBlockParameterDirect(1).ID).toInt());
- mind_n_N2 = (String(huskylens.readBlockParameterDirect(2).ID).toInt());
- huskylens.writeOSD(String((String((String(mind_n_N1) + String("-------"))) + String(mind_n_N2))), 20, 130);
- delay(500);
- }
- }
- void DF_PanDuanJieGuo() {
- // 军棋中军衔高低判定
- if ((((2<mind_n_N1) && (mind_n_N1<41)) && ((5<mind_n_N2) && (mind_n_N2<41)))) {
- DF_XiangDeng();
- DF_LXiaoYuR();
- DF_LDaYuR();
- }
- DF_GongBingChaiLei();
- DF_DiLeiChuLi();
- DF_ZhaDanChuLi();
- DF_KangQi();
- }
- void DF_MingChen() {
- if ((mind_n_N1==1)) {
- mind_s_M1 = "chess:";
- }
- if ((mind_n_N2==2)) {
- mind_s_M1 = "chess:";
- }
- if (((3<=mind_n_N1) && (mind_n_N1<=5))) {
- mind_s_M1 = "engineer:";
- }
- if (((6<=mind_n_N2) && (mind_n_N2<=8))) {
- mind_s_M2 = "engineer:";
- }
- if (((9<=mind_n_N1) && (mind_n_N1<=11))) {
- mind_s_M1 = "platoon:";
- }
- if (((12<=mind_n_N2) && (mind_n_N2<=14))) {
- mind_s_M2 = "platoon:";
- }
- if (((15<=mind_n_N1) && (mind_n_N1<=17))) {
- mind_s_M1 = "Company:";
- }
- if (((18<=mind_n_N2) && (mind_n_N2<=20))) {
- mind_s_M2 = "Company:";
- }
- if (((21<=mind_n_N1) && (mind_n_N1<=22))) {
- mind_s_M1 = "battalion :";
- }
- if (((23<=mind_n_N2) && (mind_n_N2<=24))) {
- mind_s_M2 = "battalion:";
- }
- if (((25<=mind_n_N1) && (mind_n_N1<=26))) {
- mind_s_M1 = "regimental ";
- }
- if (((27<=mind_n_N2) && (mind_n_N2<=28))) {
- mind_s_M2 = "regimental: ";
- }
- if (((29<=mind_n_N1) && (mind_n_N1<=30))) {
- mind_s_M1 = "brigade: ";
- }
- if (((31<=mind_n_N2) && (mind_n_N2<=32))) {
- mind_s_M2 = "brigade: ";
- }
- if (((33<=mind_n_N1) && (mind_n_N1<=34))) {
- mind_s_M1 = "teacher:";
- }
- if (((35<=mind_n_N2) && (mind_n_N2<=36))) {
- mind_s_M2 = "teacher:";
- }
- if ((mind_n_N1==37)) {
- mind_s_M1 = "army:";
- }
- if ((mind_n_N2==38)) {
- mind_s_M2 = "army:";
- }
- if ((mind_n_N1==39)) {
- mind_s_M1 = "commander:";
- }
- if ((mind_n_N2==40)) {
- mind_s_M2 = "commander:";
- }
- if (((41<=mind_n_N1) && (mind_n_N1<=43))) {
- mind_s_M1 = "mine:";
- }
- if (((44<=mind_n_N2) && (mind_n_N2<=46))) {
- mind_s_M2 = "mine:";
- }
- if (((47<=mind_n_N1) && (mind_n_N1<=48))) {
- mind_s_M1 = "bomb:";
- }
- if (((49<=mind_n_N2) && (mind_n_N2<=50))) {
- mind_s_M2 = "bomb:";
- }
- }
- void DF_DiLeiChuLi() {
- if ((((9<=mind_n_N1) && (mind_n_N1<=39)) && ((44<=mind_n_N2) && (mind_n_N2<=46)))) {
- huskylens.writeOSD(String("boom_RD"), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((41<=mind_n_N1) && (mind_n_N1<=43)) && ((12<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("boom_LD"), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((41<=mind_n_N1) && (mind_n_N1<=43)) && ((44<=mind_n_N2) && (mind_n_N2<=46)))) {
- huskylens.writeOSD(String("boom_LRD"), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- }
- void DF_TongGuiYuJin() {
- neoPixel_7.setRangeColor(0, 6, 0xFF0000);
- neoPixel_7.setRangeColor(0, 6, 0xFF0000);
- DFTone.play(4, 131, 500);
- delay(1000);
- neoPixel_7.clear();
- neoPixel_8.clear();
- }
- void DF_ZuoBianSheng() {
- neoPixel_7.setRangeColor(0, 6, 0x00FF00);
- neoPixel_7.setRangeColor(0, 6, 0xFF0000);
- DFTone.play(4, 196, 500);
- delay(1000);
- neoPixel_7.clear();
- neoPixel_8.clear();
- }
- void DF_ZhaDanChuLi() {
- if ((((47<=mind_n_N1) && (mind_n_N1<=48)) && ((6<=mind_n_N2) && (mind_n_N2<=46)))) {
- huskylens.writeOSD(String("boom-LZ"), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((3<=mind_n_N1) && (mind_n_N1<=46)) && ((49<=mind_n_N2) && (mind_n_N2<=50)))) {
- huskylens.writeOSD(String("boom_RZ"), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((47<=mind_n_N1) && (mind_n_N1<=48)) && ((49<=mind_n_N2) && (mind_n_N2<=50)))) {
- huskylens.writeOSD(String("boom_LRZ"), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- }
- void DF_YouBianSheng() {
- neoPixel_7.setRangeColor(0, 6, 0xFF0000);
- neoPixel_7.setRangeColor(0, 6, 0x00FF00);
- DFTone.play(4, 262, 500);
- delay(1000);
- neoPixel_7.clear();
- neoPixel_8.clear();
- }
- void DF_GongBingChaiLei() {
- if ((((3<=mind_n_N1) && (mind_n_N1<=5)) && ((44<=mind_n_N2) && (mind_n_N2<=46)))) {
- huskylens.writeOSD(String("L-CHAI"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if ((((41<=mind_n_N1) && (mind_n_N1<=43)) && ((6<=mind_n_N2) && (mind_n_N2<=8)))) {
- huskylens.writeOSD(String("R_CHAI"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- }
- void DF_KangQi() {
- if (((1==mind_n_N1) && ((6<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R-winner"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- if (((2==mind_n_N2) && ((3<=mind_n_N1) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("L-winner"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- }
- void DF_XiangDeng() {
- if ((((3<=mind_n_N1) && (mind_n_N1<=5)) && ((6<=mind_n_N2) && (mind_n_N2<=8)))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((9<=mind_n_N1) && (mind_n_N1<=11)) && ((12<=mind_n_N2) && (mind_n_N2<=14)))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((15<=mind_n_N1) && (mind_n_N1<=17)) && ((18<=mind_n_N2) && (mind_n_N2<=20)))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((mind_n_N1==21) || (mind_n_N1==22)) && ((mind_n_N2==23) || (mind_n_N2==24)))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((mind_n_N1==25) || (mind_n_N1==26)) && ((mind_n_N2==27) || (mind_n_N2==28)))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((mind_n_N1==29) || (mind_n_N1==30)) && ((mind_n_N2==31) || (mind_n_N2==32)))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if ((((mind_n_N1==33) || (mind_n_N1==34)) && ((mind_n_N2==35) || (mind_n_N2==36)))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if (((mind_n_N1==37) && (mind_n_N2==38))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- if (((mind_n_N1==39) && (mind_n_N2==40))) {
- huskylens.writeOSD(String("====="), 5, 10);
- delay(1000);
- DF_TongGuiYuJin();
- }
- }
- void DF_LXiaoYuR() {
- if ((((3<=mind_n_N1) && (mind_n_N1<=5)) && ((12<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- if ((((9<=mind_n_N1) && (mind_n_N1<=11)) && ((18<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if ((((15<=mind_n_N1) && (mind_n_N1<=17)) && ((23<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- if ((((21<=mind_n_N1) && (mind_n_N1<=22)) && ((27<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- if ((((25<=mind_n_N1) && (mind_n_N1<=26)) && ((31<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- if ((((29<=mind_n_N1) && (mind_n_N1<=30)) && ((35<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- if ((((33<=mind_n_N1) && (mind_n_N1<=34)) && ((38<=mind_n_N2) && (mind_n_N2<=40)))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- if (((mind_n_N1==37) && (mind_n_N2==40))) {
- huskylens.writeOSD(String("R"), 5, 10);
- delay(1000);
- DF_YouBianSheng();
- }
- }
- void DF_LDaYuR() {
- if ((((9<=mind_n_N1) && (mind_n_N1<=11)) && ((6<=mind_n_N2) && (mind_n_N2<=8)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if ((((15<=mind_n_N1) && (mind_n_N1<=17)) && ((6<=mind_n_N2) && (mind_n_N2<=14)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if ((((21<=mind_n_N1) && (mind_n_N1<=22)) && ((6<=mind_n_N2) && (mind_n_N2<=20)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if ((((25<=mind_n_N1) && (mind_n_N1<=26)) && ((6<=mind_n_N2) && (mind_n_N2<=24)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if ((((29<=mind_n_N1) && (mind_n_N1<=30)) && ((6<=mind_n_N2) && (mind_n_N2<=28)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if ((((33<=mind_n_N1) && (mind_n_N1<=34)) && ((6<=mind_n_N2) && (mind_n_N2<=32)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if (((mind_n_N1==37) && ((6<=mind_n_N2) && (mind_n_N2<=36)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- if (((mind_n_N1==39) && ((6<=mind_n_N2) && (mind_n_N2<=38)))) {
- huskylens.writeOSD(String("L"), 5, 10);
- delay(1000);
- DF_ZuoBianSheng();
- }
- }
- </font>
复制代码
设备组装 第一步:3D打印棋子外壳结构件如下图25-27所示,取出 3颗强磁铁,将其安装在3个孔位。 第二步:取出切割好的棋子表面,将其安装在棋子外壳上,如下图28所示。 第三步:3D打印出擂台结构件,并拿出6颗强磁铁安装在对应的孔位上,如图30所示。具体安装磁铁的级性要与蓝橙色棋子匹配。例如,一侧擂台外露为N极,则对应棋子外露为S极;另一侧擂台外露为S极,则对应棋子外露为N极。安装后以后,使用棋子测试。 第四步:为Huskylens加装支架和铜柱,如下图32所示。 第五步:将Huskylens、蜂鸣器、擂台固定在棋盘上,如下图33所示。 第六步:用热熔胶将LED灯带安装固定到指示灯区域,如下图34所示。 第七步:将上步中的棋盘于底板侧板组合安装,主控固定在底板对应孔位,从而完成安装如图35所示。另外使用热熔胶将棋子收纳盒,粘贴完成如下图36所示。 第八步:启动MaixPy.ide编程软件,选择“工具”——“机器视觉”——“AprilTag生成器——TAG36H11”生成相应的标签如图37所示。 第九步:从生成标签中选取其中的50个标签,用热敏打印机打印出来,如下图38所示。 第十步:分配标签,以下表为依据将生成的标签依次分配给蓝方和橙方对应棋子。并将打印出的标签粘贴在棋子的顶部,如下图39所示。 6.系统测试 在测试前,先要完成对50个棋子标签的学习,嗯,这是个力气活,而且需要有耐心!具体操作这里不再赘述。系统加电对其进行测试,分别军衔PK(大于、等于、小于)、工兵拆雷、炸弹处理、地雷处理、工兵扛旗的所有情况进行测试,验证其结果的有效性。
|