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
/** 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 数据线,对小狐狸重新编程做一番个性化的调整!
发表评论