神圣的抉择!公平的对决!一种抢答器,可广泛用于“谁去拿快递”“谁叫外卖”“谁来埋单”等一系列令人深思的场景。
0.序言
本作品是和几名工业设计专业的同学在十一月一起做的一个workshop产物,有相关的Arduino课程。
我则是纯去凑了热闹。
拖了这么久才攒文章,惭愧惭愧~
主要的分工,我来写代码,调试程序,排布器件。工业设计的同学做了模型和实体。
这篇文章是我稍带演绎的一篇纪录~
成品做出来好漂亮,工设的大触都是心灵手巧的人啊~
1.理念和需求
workshop的主题是做一个儿童向的互动玩具,用于抢答情景。我觉得这个情景不局限于自身,在以下场景中:
- “谁去拿快递?”
- “谁叫外卖?”
- “谁来埋单?”
都可以获得广泛的应用。所以我想了想,把它叫做
囚徒困境抢答器-《命运女神的抉择》(大雾)
——最棘手的问题,名字问题就算是解决了。
将需求分列出来,大概如下:
|
需求及对应的设计都写在这里 1 抢答场景:定然有两个按键输入。用于比谁更快速 2 输出的指示: 有一个输出的灯光指示,用于给予开始抢答的信号。 3 输出的指示: 有若干计分灯光,用于计分。这部分和工设联动,设计成了一个灯光爬山的效果。 4 胜利条件: 谁抢到山顶的“灯”谁就胜利! 5 输入: 用于reset\start |
2 作品设计
2.1 外观设计
外观是一座山,模拟两个人攀比登峰,谁先到山顶,谁便胜利。手工制作实体,和输入按键。可以看到我排的led灯在山的两侧
2.2 硬件设计
主控当然选用Arduino,因为workshop要求就是用它来当主控。
输入我选用了3端入口,为了节省不太富裕的io口。一个用于start\reset,另外两个是抢答端。
输出的话依赖灯光。选用了4+4+1的设计,正好用足了所有的io口。因为没必要加外部元件用于专门的灯光管理。索性直接用Arduino驱动。
另外说一句,pullup功能可以自带拉高点评。因此输入端不需要人工布线拉高电平。
workshop产品就直接用杜邦线桥接的方式,一方面将led灯珠引脚直接穿透纸板,另一方面插入杜邦线,过短的地方用面包板线桥接,用胶带固定即可。
2.3 逻辑设计:
红灯用于指示抢答。
状态1:所有led跑马灯,等待红色按钮输入开始信号。
状态2:开始抢答,红灯亮起。若干秒后熄灭,开始按钮抢答输入
状态3:成功抢答的一端判断为胜利。计数加1,蓝灯或绿灯亮起。亮满4个最终胜利
状态4:重新循环状态1
2.4 代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/* 趴会儿Project项目集 http://steinslab.xyz/archives/752 No.002 详见http://steinslab.xyz/archives/1008 囚徒困境抢答器-《命运女神的抉择》 SPtuan@steinslab.xyz */ int A[4]={10,11,12,13}; int B[4]={6,7,8,9}; int info = 5; int Ain = 4; int Bin = 3; int Cin = 2; volatile int flag=0; int Aflag=0,Bflag=0,ix=0,jx=0; int Atemp=Aflag; int Btemp=Bflag; void setup() { Serial.begin(9600); for(ix=0;ix<4;ix++) { pinMode(A[ix],OUTPUT); digitalWrite(A[ix],LOW); pinMode(B[ix],OUTPUT); digitalWrite(B[ix],LOW); } pinMode(Ain,INPUT_PULLUP); pinMode(Bin,INPUT_PULLUP); pinMode(Cin,INPUT_PULLUP); pinMode(info,OUTPUT); digitalWrite(info,LOW); attachInterrupt(0,signal0,RISING); } void signal0() { if(flag==0) flag = 1; } void wait() { digitalWrite(info,HIGH); delay(3000); digitalWrite(info,LOW); } void display0() { digitalWrite(B[Bflag-1],HIGH); digitalWrite(A[Aflag-1],HIGH); } void display1() { if(Aflag==4) { for(ix=0;ix<3;ix++) { for(jx=0;jx<4;jx++) { digitalWrite(A[jx],HIGH); digitalWrite(B[jx],LOW); } delay(500); for(jx=0;jx<4;jx++) { digitalWrite(A[jx],LOW); } delay(500); } } else if(Bflag==4) { for(ix=0;ix<3;ix++) { for(jx=0;jx<4;jx++) { digitalWrite(B[jx],HIGH); digitalWrite(A[jx],LOW); } delay(500); for(jx=0;jx<4;jx++) { digitalWrite(B[jx],LOW); } delay(500); } } } void loop() { Atemp=Aflag=Btemp=Bflag=0; do { for(ix=0;ix<4;ix++) { digitalWrite(A[ix],HIGH); digitalWrite(B[ix],HIGH); delay(300); if(flag==1) break; } for(ix=0;ix<4;ix++) { digitalWrite(A[ix],LOW); digitalWrite(B[ix],LOW); delay(300); if(flag==1) break; } }while(flag==0); for(ix=0;ix<4;ix++) { digitalWrite(A[ix],LOW); digitalWrite(B[ix],LOW); } delay(1000); do { do{ wait(); Atemp=Aflag; Btemp=Bflag; do{ if(digitalRead(Ain)==LOW) { delay(20); if(digitalRead(Ain)==LOW) Aflag++; Serial.print("Aflag"); while(digitalRead(Ain)==LOW); } else if(digitalRead(Bin)==LOW) { delay(20); if(digitalRead(Bin)==LOW) Bflag++; Serial.print("Bflag"); while(digitalRead(Bin)==LOW); } }while((Atemp==Aflag)&&(Btemp==Bflag)); display0(); if(Bflag<4) digitalWrite(B[3],LOW); if(Aflag<4) digitalWrite(A[3],LOW); }while((Aflag!=4)&&(Bflag!=4)); display1(); flag = 0; }while(flag==1); } |
注:后来我也思考了一下。这个代码还是有相当的改进余地的。
对于抢答按钮的输入,使用了循环扫描的方法,势必会有一个优先级的问题,一旦一个持续按下,就会触发bug必赢。
可以改用中断,套用几个flag变量,综合判断真正在抢答器结束后按击的人。或者提前按下的人直接判负。
3 展示
3.1 成果
我和小崔在原形上就玩得不亦乐乎……生生玩了一晚上……
视频大小2MB(原型时期录制)
作品最后外观是相当漂亮的~
工设同学做的项目记录总是非常漂亮的,下面是制作过程若干图片
成品图