用 Arduino 做一只会撒娇的狐狸:小主休息一下吧~


MAKER: ReinKTH/译:趣无尽 Cherry(转载请注明出处)
这是一只会撒娇求安抚的绯红狐狸。用萌动得让你难以忽视的姿势撩你,提醒你给它安抚。
在它的央求下,你暂时放下手上的枯燥工作,和它来个互动、小憩一下,你原本机械的工作状态也平添了几分乐趣和安慰……(有创造力的朋友当然可以发挥一下,直接做个小姐姐也没有什么不可以。)

咳……进入正题。这只可爱的小狐狸会像动物一样呼吸。当你开始工作时,轻轻地抚摸它,表示你开始工作了。当你工作许久后,小狐狸就会躁动起来,呼吸好像会变得沉重。发生这种情况,你得再次抚摸它,可以让它恢复平静。你也会马上意识到自己也需要休息调剂一下,喝个茶、吃点东西亦或是起身做个瑜伽。

经过短暂休憩,你可以再次轻轻地抚摸狐狸,告诉它你将继续工作。当你再次忽略它的时候,它会再次来讨你的宠爱,十分乖巧!

先看一段视频吧!

材料清单


Arduino pro micro ×1
micro USB转USB电缆×1
步进电机×1
电机驱动器×1
小面包板×2
彩色LED灯带×2
电线×若干
10M电阻×1
100M电阻×2
9伏电池×1
9伏电极夹×1
人造革×1
胶合板×1
纸板×1
铝箔纸×1
胶水×1
针和线×若干

操作预警:使用的人造革确保它不含任何PVC成分。人造皮将经过激光切割,如果含有PVC,切割时会释放氯化物的有毒气体。如你不能确定所用皮革是否含有PVC,可用剪刀来切割线条。

切割原材料



根据模板用激光切割机切割所有材料。如图所示,所有红线都需要切割,所有黑线需要雕刻。根据自己的要求设置好激光切割机。我建议,可先用一张人造革测试一下,以测定雕刻部件的深度是否足够。
如果没有激光切割机,也可以在纸上打印模板并手动切割所有模板,只是会花费更长的时间。
切割文件可在本项目文件库中下载。
http://make.quwj.com/project/81

将皮革粘贴到纸板上




纸板用作皮革的支撑材料,方便弯曲。除六边形外,皮革的每个表面都有匹配的纸板。根据皮革的形状将它们粘在皮革上。边缘处的纸板之间应该预留大约3mm的空间向外折叠,在向内折叠的纸板之间几乎没有空间。
同时,向内折叠的地方用工具刀稍微切割一下皮革,使皮革更容易折叠。确保你没有彻底切断它!

将铝箔纸粘合到内面



创建一个触摸传感器,感应是否有人正在触摸或抚摸狐狸。将4层铝箔纸粘贴在里面以便制作成电容式传感器。对于 Arduino 电容式触控开关原理可以参考这里
将长边缝合在一起然后将铝箔纸粘在纸板上。确保内部折叠部分留出一些空间,以便铝箔纸不会破裂。预留一个地方连接到 Arduino 的接线处。

搭建电路并上传代码


代码可在本项目文件库中下载。
http://make.quwj.com/project/81

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/**
   capacitive sensing code with servo motor for Crimson Fox
*/
 
#include <Servo.h>
#include <CapacitiveSensor.h>
#include <HampelFilter.h>
#include <Filters.h>
 
#define dir 5
#define stp 6
#define capin 8
#define capout 9
#define ledWork 14
#define ledPanic 15
 
 
//Initializing touch sensor
CapacitiveSensor   cap_sense = CapacitiveSensor(capin, capout);       // 10 megohm resistor between pins capin & capout
 
//Initialiying Filters
HampelFilter dataBuffer = HampelFilter(0.00, 3, 3.50);
FilterOnePole lowpassFilter( LOWPASS, 5);
 
//Initialiying threasholding for touch
int upperThreashold = 8000;
int lowerThreashold = 8000;
int baseline = 100;
int summedThreashold = 16000;
int csSum = 0;
long dynThreasholdCount = 0;
long dynThreasholdTimeout = 6000;
 
//Initializing Motor
int pos = 0;    // variable to store the servo position
bool exhale = false; // false for inhale, true for exhale
int breathDepthTop;
int breathDepthBottom;
int breathDelay;
 
//Initializing session and fox status
enum WorkingStatus {
  pause,
  work,
  panic,
  standby
};
WorkingStatus foxStatus;
bool touched = false; // status if touch was detected
 
//Initialize Timing
long sessionStart; //time at session start
long sessionLength = 30000; //180000ms = 3min, time after which fox panics, one hour would be 3600000, 30 min would be 1800000
long REACTIVITYDELAY = 2000;
long lastTouchTime;
long breathStepStart;
 
void setup()
{
  cap_sense.set_CS_AutocaL_Millis(0xFFFFFFFF);     // turn off autocalibrate on channel 1 - just as an example
  Serial.begin(9600);
 
  pinMode(stp, OUTPUT);
  pinMode(dir, OUTPUT);
 
  pinMode(ledWork, OUTPUT);
  pinMode(ledPanic, OUTPUT);
 
  enterPauseStatus();
  breathStepStart = millis();
  lastTouchTime = millis();
}
 
void loop() {
 
  //read and filter touch sensor signal
  long total1 =  lowpassFilter.input(cap_sense.capacitiveSensor(30));//30
  dataBuffer.write(total1);
 
/*
  if(!(foxStatus == standby)){
    Serial.print(lastTouchTime);
    Serial.print(", ");
    Serial.print(millis());
    Serial.print(", ");
    Serial.println(lastTouchTime + REACTIVITYDELAY - millis());
  }*/
   
  if ((lastTouchTime + REACTIVITYDELAY - millis()) > 4294000000) {
    //Serial.println("checking status");
    // state machine
    if (foxStatus == pause) {
      //enter work status if touched
      if (detectTouch(total1)) {
        enterWorkStatus();
      }
    } else if (foxStatus == work) {
      //inter pause status if touched
      if (detectTouch(total1)) {
        enterPauseStatus();
      }
      //check if it is time to panic
      if ((millis() - sessionStart) > sessionLength) {
        enterPanicStatus();
      }
    } else if(foxStatus == panic) { //panic
      //enter work status if touched
      if (detectTouch(total1)) {
        enterWorkStatus();
      }
    }
  }
 
  if(foxStatus != standby){
      breathing();
  }
 
  if(Serial.available() > 0){
    String userInput = Serial.readString();
    Serial.print(userInput);
    userInput.trim();
    if(userInput.equals("q") || userInput == "quit"){
      exhaleAndDie();
      foxStatus = standby;
    }else{
      Serial.println(userInput + " could not be recogninzed use 'q' or 'quit' to shut down the fox.");
    }
  }
 
}
 
bool detectTouch(int cs) {
  bool touchTriggered = false;
  if (!dataBuffer.checkIfOutlier(cs)) {
    Serial.print(cs);
    Serial.print("\t");
    if (cs > upperThreashold) {
      csSum += cs;
      Serial.print(cs);
      Serial.print("\t");
      if (csSum >= summedThreashold) //c: This value is the threshold, a High value means it takes longer to trigger
      {
        Serial.print("Trigger: ");
        Serial.print(csSum);
        touchTriggered = true;
        if (csSum > 0) {
          csSum = 0;  //Reset
        }
        //cs_7_8.reset_CS_AutoCal(); //Stops readings
      }
    } else if (cs < lowerThreashold) {
      csSum = 0; //Timeout caused by bad readings
    }
    Serial.println("");
  }
  return touchTriggered;
}
 
void breathing() {
  //Serial.println(millis()-breathStepStart);
   
  /*if(!(foxStatus == standby)){
    Serial.print(breathStepStart);
    Serial.print(", ");
    Serial.print(millis());
    Serial.print(", ");
    Serial.println(millis()-breathStepStart);
  }*/
   
  //if(breathDelay < (millis()-breathStepStart)){
    breathStepStart = millis();
     
    if (pos > breathDepthTop) {
      exhale = true;
    } else if (pos <= breathDepthBottom) {
      exhale = false;
    }
   
    //set motor direction
    if (exhale) {
      pos = pos - breathDelay;
      digitalWrite(dir, LOW);
    } else {
      pos = pos + breathDelay;
      //Serial.println(pos);
      digitalWrite(dir, HIGH);
    }
   
    //do a breath step before returning to measuring touch again
    for(int i = 0; i < breathDelay; i++){
      digitalWrite(stp, HIGH);
      delayMicroseconds(1);
      digitalWrite(stp, LOW);
      delayMicroseconds(1);
    }
 
  //}
}
 
void enterWorkStatus() {
  Serial.println("Enter work");
  sessionStart = millis();
  touched = false;
  foxStatus = work;
  breathDelay = 6;
  breathDepthTop = 800;
  breathDepthBottom = 0;
  digitalWrite(ledWork, HIGH); //TODO turn on again
  digitalWrite(ledPanic, LOW);
  lastTouchTime = millis();
}
 
void enterPanicStatus() {
  Serial.println("Enter panic");
  touched = false;
  foxStatus = panic;
  breathDelay = 10;
  breathDepthTop = 1500;
  breathDepthBottom = 1000;
  digitalWrite(ledWork, LOW);
  digitalWrite(ledPanic, HIGH);
}
 
void enterPauseStatus() {
  Serial.println("Enter pause");
  touched = false;
  foxStatus = pause;
  breathDelay = 2;
  breathDepthTop = 800;
  breathDepthBottom = 0;
  digitalWrite(ledWork, LOW);
  digitalWrite(ledPanic, LOW);
  lastTouchTime = millis();
}
 
void exhaleAndDie(){
  digitalWrite(dir, LOW);
  while(pos > 0){   
    digitalWrite(stp, HIGH);
    delayMicroseconds(1);
    digitalWrite(stp, LOW);
    delayMicroseconds(1);
    pos--;
  }
}
 
void handleThreashold(){
   
}
}

粘合下部并连线



1、将齿轮粘连到步进电机和胶合板的下面,并将步进电机粘在上面。
2、使用针和线,每个角内折叠,形成狐狸的形状。
3、将电线缠绕步进电机本两圈,然后稍微拉紧一下。另外,确保可逆时针旋转。

组装所有部件



部件布局如下:
1、底部预留9伏电池的地方。
2、中间为步进电机。
3、顶部为Arduino pro micro和电机驱动器。
4、将皮革的开口边缘缝合在一起。

最后,将所有剩余的开口侧缝合在一起,项目就完成了。
你还可以连上 USB 数据线,对小狐狸重新编程做一番个性化的调整!

http://www.quwj.com/2018/11/28/crimson-fox-raising-awareness-to-take-a-break-whil.html



坐沙发

发表评论