前言
这次的这个抢红包机器人是某天果壳的人说他们在策划一个这样的活动,然后我当时觉得很有意思就说要不和柴火的会员做一个吧,但是问题来了,就是这个活动办的时候我已经不在深圳了,然后最近要过年,也不是有很多会员过来。。。所以基本上只有杜传和我一直在做这个项目。(这里一定要感谢下杜传,我总结了下,基本上和你做东西的时候就没顺利的做出来过-_-!!!!)
先介绍下果壳提供了一个他们的机器人的demo,大致上,是张这个样子的:
我当时的感觉就是这太低效了,而且可靠性也有点问题。然后我想起了大约是去年的时候,当时流传过一个这样的东西。。
总的来说,他用光敏电阻识别是不是有树枝落下来,然后决定点击屏幕左边还是右边。这是他的项目的地址https://github.com/vheun/ArduinoPlaysTimberman
还有电路连接图。。。不得不说这个原作真的是。。。什么都没有写。。原理步骤一概没有,只有arduino程序。。。
模仿手指触摸屏幕
最初杜传和我的计划是用铜箔或者锡纸,柴火的铜箔有点窄,要几个拼起来才行,然后我们订了必胜客。。。(不知道给报销不)
但是最后发现有些不好用,最初因为我们发现大量的时候屏幕被按下但是没有抬起来,所以我们怀疑可能是导线太长,屏幕把导线识别成了手指,所以我们剪短了导线,但是后来发现成功率还是只有50%左右。。。后来杜传微信发了我一个youtube连接,发现有另外一个人做了一个类似的东西,用的是硬币,我在想也有可能是我们之前做的东西没有重量,所以有些接触不良。
然后改完方案以后成功率上升不少,大致就是这样的。。。
然而最后还是不行,工作的时候不稳定,就是不知道什么时候就会不工作。然后在过年那天晚上终于让我爹帮我做出来了。。。说起来我爸真的是一个神奇的人物设定,具体的以后有机会再慢慢说吧。。。
总的来说,我之前觉得因为人体是一个导体,所以连接屏幕的部分一定要是一个导体,而铜箔纸常见的都是单面的,另外一面是不导电的胶,所以如果我把胶贴在屏幕上的话应该是不起作用的,但是事实上其实因为屏幕是电容屏,电信号是交流的,所以中间有一部分是绝缘体也是可以通过的。。。最后就是直接把铜箔粘上去就行了。。。
传感器布局
恩,然后开始做传感部分,基本上就是用了光敏电阻,然后用蓝丁胶粘在屏幕上,下面是我测试的一些数据,我选取了屏幕上的5个点,分布如下图。
各种情况下传感器的数值变化
这次我第一次用了早就听说过的firmata,可以给processing写代码然后processing控制arduino对应的引脚,具体可以看这里https://github.com/firmata
然后我发现firmata不能通过串口绘图,而我需要实时的知道对应ADC数值,然后又找到这个基于firmata制作的processing程序arduinoscope,github的地址是https://github.com/konsumer/arduinoscope
可以看到变化还是非常明显的,不过记得要把屏幕亮度调到最高,不然可能会因为环境光屏幕自动调低所有的亮度导致误差。。
(这个图和我最终使用的传感器布局可能有些不同,主要是为了体现传感器在不同页面下的数值)
电路连接
程序
所有define里sensor_val的部分都要在每次把传感器取下来后再次运行前标定,val1、2、3分别为三个画面电阻的阻值。
/*
--------------------------------------
| |
| |
| 5 |
| |
| 3 |
| --------------------- |
| | | |
| | | |
| | | |
| --------------------- |
| |
| |
| --------------------- |
| | | 4 |
| | | |
| | | |
| --------------------- |
| |
| |
| --------------------- |
| | | |
| | 1 | 2 |
| | | |
| --------------------- |
| |
--------------------------------------
*/
#define STATUS_ERRO -1
#define STATUS_RECV 1
#define STATUS_OPEN 2
#define STATUS_RSUT 3
#define STATUS_WAIT 4
#define SENSOR_PIN1 A4
#define SENSOR_PIN2 A3
#define SENSOR_PIN3 A2
#define SENSOR_PIN4 A1
#define SENSOR_PIN5 A0
#define TOUCH_PIN1 4
#define TOUCH_PIN2 3
#define TOUCH_PIN3 2
#define SENSOR1_VAL1 697
#define SENSOR1_VAL2 724
#define SENSOR1_VAL3 549
#define SENSOR1_VAL4 567
#define SENSOR2_VAL1 626
#define SENSOR2_VAL2 711
#define SENSOR2_VAL3 559
#define SENSOR2_VAL4 649
#define SENSOR3_VAL1 962
#define SENSOR3_VAL2 724
#define SENSOR3_VAL3 596
#define SENSOR4_VAL1 993
#define SENSOR4_VAL2 993
#define SENSOR4_VAL3 645
#define SENSOR5_VAL1 945
#define SENSOR5_VAL2 693
#define SENSOR5_VAL3 543
#define SENSOR_THRESHOLD 30
void setup()
{
pinMode(SENSOR_PIN1, INPUT);
pinMode(SENSOR_PIN2, INPUT);
pinMode(SENSOR_PIN3, INPUT);
pinMode(SENSOR_PIN4, INPUT);
pinMode(SENSOR_PIN5, INPUT);
pinMode(TOUCH_PIN1, OUTPUT);
pinMode(TOUCH_PIN2, OUTPUT);
pinMode(TOUCH_PIN3, OUTPUT);
digitalWrite(TOUCH_PIN1, LOW);
digitalWrite(TOUCH_PIN2, LOW);
digitalWrite(TOUCH_PIN3, LOW);
Serial.begin(115200);
}
void loop()
{
switch (getStatus()) {
case STATUS_WAIT:
new_come = 1;
break;
case STATUS_RECV:
touchScreen(TOUCH_PIN1);
delay(500);
break;
case STATUS_OPEN:
touchScreen(TOUCH_PIN2);
delay(500);
break;
case STATUS_RSUT:
touchScreen(TOUCH_PIN3);
delay(1000);
break;
}
delay(100);
}
void touchScreen(int pinNum){
digitalWrite(pinNum, HIGH);
delay(150);
digitalWrite(pinNum, LOW);
delay(100);
}
int getStatus(){
int sensor_value1,sensor_value2,sensor_value3,sensor_value4,sensor_value5;
sensor_value1 = analogRead(SENSOR_PIN1);
sensor_value2 = analogRead(SENSOR_PIN2);
sensor_value3 = analogRead(SENSOR_PIN3);
sensor_value4 = analogRead(SENSOR_PIN4);
sensor_value5 = analogRead(SENSOR_PIN5);
if((abs(sensor_value1 - SENSOR1_VAL1) < SENSOR_THRESHOLD) &&
(abs(sensor_value2 - SENSOR2_VAL1) < SENSOR_THRESHOLD) &&
(abs(sensor_value4 - SENSOR4_VAL1) < SENSOR_THRESHOLD))
{
Serial.println("STATUS_RECV");
return STATUS_RECV;
}
if((abs(sensor_value2 - SENSOR2_VAL2) < SENSOR_THRESHOLD) &&
(abs(sensor_value3 - SENSOR3_VAL2) < SENSOR_THRESHOLD))
{
Serial.println("STATUS_OPEN");
return STATUS_OPEN;
}
if((abs(sensor_value3 - SENSOR3_VAL3) < SENSOR_THRESHOLD) &&
(abs(sensor_value4 - SENSOR4_VAL3) < SENSOR_THRESHOLD) &&
(abs(sensor_value5 - SENSOR5_VAL3) < SENSOR_THRESHOLD))
{
Serial.println("STATUS_RSUT");
return STATUS_RSUT;
}
if((abs(sensor_value1 - SENSOR1_VAL4) < SENSOR_THRESHOLD) &&
(abs(sensor_value2 - SENSOR2_VAL4) < SENSOR_THRESHOLD) &&
(abs(sensor_value4 - SENSOR4_VAL1) < SENSOR_THRESHOLD))
{
Serial.println("STATUS_WAIT");
return STATUS_WAIT;
}
Serial.print(sensor_value1);
Serial.print(" , ");
Serial.print(sensor_value2);
Serial.print(" , ");
Serial.print(sensor_value3);
Serial.print(" , ");
Serial.print(sensor_value4);
Serial.print(" , ");
Serial.println(sensor_value5);
return STATUS_ERRO;
}
PS:写标题的时候突然想起来这个解题报告这个名字,当初学OI的时候没做一道题都把思路写下来,觉得特别有成就感,更神奇的地方是我好像基本上都写在了qq空间。。。那以后5、6年的时间没有以这个词为标题了。。。好像这次还挺合适这个题目的。。。
UPDATE:
鲁大师的人说想让我再做一个,时隔一年,把坑又重踩了一边。。。。
新的心得是,屏幕有一个防水算法,就是如果遇到了一个东西放在屏幕上发现一直是按下不能抬起来的话,那么说明屏幕把他识别成了水,关闭屏幕重开就好了。
然后迭代了一版,现在只需要三个传感器就行了。然后开机会自校准。
/*
release note
v2: 精简了传感器的数量
--------------------- | ||
--------------------- | ||
2 | ||
--------------------- | ||
--------------------- | ||
1 | ||
--------------------- | ||
| |
| |
| 3 |
| |
--------------------- | ||
--------------------- | ||
2 | ||
--------------------- | ||
--------------------- | ||
1 | ||
--------------------- | ||
收到 打开 结果 等待
1 红 黑 白 黑
2 黑 红 白 黑
3 -- 黑 红 黑
*/
define STATUS_ERRO -1
define STATUS_RECV 1
define STATUS_OPEN 2
define STATUS_RSUT 3
define STATUS_WAIT 4
define SENSOR_PIN1 A4
define SENSOR_PIN2 A3
define SENSOR_PIN3 A2
define TOUCH_PIN1 3
define TOUCH_PIN2 4
define TOUCH_PIN3 5
define CALI_PIN 8
define LED_PIN 13
define SENSOR_THRESHOLD 30
int SENSOR1_VAL1 = 0;
int SENSOR1_VAL2 = 0;
int SENSOR1_VAL3 = 0;
int SENSOR1_VAL4 = 0;
int SENSOR2_VAL1 = 0;
int SENSOR2_VAL2 = 0;
int SENSOR2_VAL3 = 0;
int SENSOR2_VAL4 = 0;
int SENSOR3_VAL1 = 0;
int SENSOR3_VAL2 = 0;
int SENSOR3_VAL3 = 0;
int SENSOR3_VAL4 = 0;
void setup()
{
pinMode(SENSOR_PIN1, INPUT);
pinMode(SENSOR_PIN2, INPUT);
pinMode(SENSOR_PIN3, INPUT);
pinMode(TOUCH_PIN1, OUTPUT);
pinMode(TOUCH_PIN2, OUTPUT);
pinMode(TOUCH_PIN3, OUTPUT);
digitalWrite(TOUCH_PIN1, LOW);
digitalWrite(TOUCH_PIN2, LOW);
digitalWrite(TOUCH_PIN3, LOW);
Serial.begin(115200);
Serial.println("cali begin");
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
pinMode(CALI_PIN, INPUT);
digitalWrite(CALI_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
while(digitalRead(CALI_PIN) == HIGH);
digitalWrite(LED_PIN, LOW);
SENSOR1_VAL1 = analogRead(SENSOR_PIN1);
SENSOR2_VAL1 = analogRead(SENSOR_PIN2);
SENSOR3_VAL1 = analogRead(SENSOR_PIN3);
delay(1000);
digitalWrite(LED_PIN, HIGH);
while(digitalRead(CALI_PIN) == HIGH);
digitalWrite(LED_PIN, LOW);
SENSOR1_VAL2 = analogRead(SENSOR_PIN1);
SENSOR2_VAL2 = analogRead(SENSOR_PIN2);
SENSOR3_VAL2 = analogRead(SENSOR_PIN3);
delay(1000);
digitalWrite(LED_PIN, HIGH);
while(digitalRead(CALI_PIN) == HIGH);
digitalWrite(LED_PIN, LOW);
SENSOR1_VAL3 = analogRead(SENSOR_PIN1);
SENSOR2_VAL3 = analogRead(SENSOR_PIN2);
SENSOR3_VAL3 = analogRead(SENSOR_PIN3);
delay(1000);
digitalWrite(LED_PIN, HIGH);
while(digitalRead(CALI_PIN) == HIGH);
digitalWrite(LED_PIN, LOW);
SENSOR1_VAL4 = analogRead(SENSOR_PIN1);
SENSOR2_VAL4 = analogRead(SENSOR_PIN2);
SENSOR3_VAL4 = analogRead(SENSOR_PIN3);
delay(1000);
digitalWrite(LED_PIN, LOW);
Serial.println("inin finished");
}
void loop()
{
switch (getStatus()) {
case STATUS_WAIT:
break;
case STATUS_RECV:
touchScreen(TOUCH_PIN1);
delay(500);
break;
case STATUS_OPEN:
touchScreen(TOUCH_PIN2);
delay(500);
break;
case STATUS_RSUT:
touchScreen(TOUCH_PIN3);
delay(1000);
break;
}
delay(100);
}
void touchScreen(int pinNum){
Serial.print("Pressing No.");
Serial.println(pinNum);
digitalWrite(pinNum, HIGH);
delay(150);
digitalWrite(pinNum, LOW);
delay(100);
}
int getStatus(){
int sensor_value1,sensor_value2,sensor_value3;
sensor_value1 = analogRead(SENSOR_PIN1);
sensor_value2 = analogRead(SENSOR_PIN2);
sensor_value3 = analogRead(SENSOR_PIN3);
Serial.print(sensor_value1);
Serial.print(" , ");
Serial.print(sensor_value2);
Serial.print(" , ");
Serial.print(sensor_value3);
if((abs(sensor_value1 - SENSOR1_VAL1) < SENSOR_THRESHOLD) &&
(abs(sensor_value2 - SENSOR2_VAL1) < SENSOR_THRESHOLD))
{
Serial.println();
Serial.println("STATUS_RECV");
return STATUS_RECV;
}
if((abs(sensor_value1 - SENSOR1_VAL2) < SENSOR_THRESHOLD) &&
(abs(sensor_value2 - SENSOR2_VAL2) < SENSOR_THRESHOLD) &&
(abs(sensor_value3 - SENSOR3_VAL2) < SENSOR_THRESHOLD))
{
Serial.println();
Serial.println("STATUS_OPEN");
return STATUS_OPEN;
}
if((abs(sensor_value1 - SENSOR1_VAL3) < SENSOR_THRESHOLD) &&
(abs(sensor_value2 - SENSOR2_VAL3) < SENSOR_THRESHOLD) &&
(abs(sensor_value3 - SENSOR3_VAL3) < SENSOR_THRESHOLD))
{
Serial.println();
Serial.println("STATUS_RSUT");
return STATUS_RSUT;
}
if((abs(sensor_value1 - SENSOR1_VAL4) < SENSOR_THRESHOLD) &&
(abs(sensor_value2 - SENSOR2_VAL4) < SENSOR_THRESHOLD) &&
(abs(sensor_value3 - SENSOR3_VAL4) < SENSOR_THRESHOLD))
{
Serial.println();
Serial.println("STATUS_WAIT");
return STATUS_WAIT;
}
Serial.print(" ");
Serial.print("SENSOR_VAL1: ");
Serial.print(SENSOR1_VAL1);
Serial.print(" , ");
Serial.print(SENSOR2_VAL1);
Serial.print(" , ");
Serial.print(SENSOR3_VAL1);
Serial.print(" ; ");
Serial.print("SENSOR_VAL2: ");
Serial.print(SENSOR1_VAL2);
Serial.print(" , ");
Serial.print(SENSOR2_VAL2);
Serial.print(" , ");
Serial.print(SENSOR3_VAL2);
Serial.print(" ; ");
Serial.print("SENSOR_VAL3: ");
Serial.print(SENSOR1_VAL3);
Serial.print(" , ");
Serial.print(SENSOR2_VAL3);
Serial.print(" , ");
Serial.print(SENSOR3_VAL3);
Serial.print(" ; ");
Serial.print("SENSOR_VAL4: ");
Serial.print(SENSOR1_VAL4);
Serial.print(" , ");
Serial.print(SENSOR2_VAL4);
Serial.print(" , ");
Serial.print(SENSOR3_VAL4);
Serial.println();
return STATUS_ERRO;
}
目前的样子是这样的。