{"id":2757,"date":"2017-12-07T20:54:39","date_gmt":"2017-12-07T19:54:39","guid":{"rendered":"http:\/\/dronesonen.hibu.no\/?p=2757"},"modified":"2017-12-07T20:54:39","modified_gmt":"2017-12-07T19:54:39","slug":"smart-mirror-arduino-update-on-the-code","status":"publish","type":"post","link":"https:\/\/dronesonen.usn.no\/?p=2757","title":{"rendered":"Smart Mirror &#8211; Arduino: Update on the code"},"content":{"rendered":"<p>\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/Relay\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\nconst int relay = 5;<br \/>\nint relayVal;<br \/>\n\/\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/loadCell\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\n#include &#8220;HX711.h&#8221;<br \/>\n#define zero_factor 555230<br \/>\n#define DOUT 3 \/\/gelb \/ yellow<br \/>\n#define CLK 2 \/\/orange<br \/>\nfloat calibration_factor = ((200000 * 0.00045359237) + 52400);<br \/>\nHX711 scale(DOUT, CLK);<\/p>\n<p>float valueReadLoadCell;<br \/>\nfloat valueLimit;<br \/>\n\/\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/Servo\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\n#include &lt;Servo.h&gt;<br \/>\nServo myservo360; \/\/ continious rotation servo<br \/>\nServo myservo180; \/\/ 180 servo<br \/>\nint direction;<br \/>\nint pos3 = 0;<br \/>\n\/\/int pos1 = 110;<br \/>\nconst int servPin360 = 9;<br \/>\nint speed = 94; \/\/ number &lt; 90: movement clockwise; number &gt; 90: movement counterclockwise; the actual number controles the speed of rotation<br \/>\nconst int servPin180 = 8;<br \/>\n\/\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/Button\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\nconst int butPin = 12;<br \/>\nint butVal;<br \/>\n\/\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/Raspberry\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\nchar receivedChar; \/\/<br \/>\nboolean newData = false;<br \/>\n\/\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\<br \/>\nlong firstMeasure = 0;<br \/>\nlong secondMeasure;<br \/>\nlong interval = 7000;<\/p>\n<p>unsigned long previousMillis = 0;<\/p>\n<p>\/\/_________________________________________________________________________________________<br \/>\n\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-SETUP&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<\/p>\n<p>void setup() {<br \/>\npinMode(butPin, INPUT);<br \/>\npinMode(relay, OUTPUT);<\/p>\n<p>Serial.begin(9600);<\/p>\n<p>scale.set_scale(calibration_factor); \/\/ when u open the serial monitor the value should be between -0.5 and + 0.5: for setting it to 0 we will have to mount it to the box<br \/>\nscale.set_offset(zero_factor); \/\/ Zero out the scale using a previously known zero_factor<br \/>\nSerial.println(&#8220;Reading: &#8220;);<br \/>\ndelay(5000);<br \/>\nvalueReadLoadCell = (scale.get_units()); \/\/ get the initial value of the load cell into the variable. has to happen once in the setup otherwise the first calculation will be 0 + the interval<br \/>\n}<\/p>\n<p>\/\/________________________________________END of SETUP_____________________________________<br \/>\n\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-LOOP&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<\/p>\n<p>void loop() {<br \/>\nrecvInfo();<br \/>\nSerial.print(&#8220;Loop: &#8220;);<br \/>\nSerial.println(scale.get_units()); \/\/ keeps spamming the actual value of the loadCell. should be commented out if the connection is through the pi<\/p>\n<p>checkButton(); \/\/ function to check if the button is pressed<br \/>\nif (butVal == HIGH) {<br \/>\nSerial.println(&#8220;called through button&#8221;);<br \/>\ncButton();<br \/>\n}<br \/>\nif (newData == true) { \/\/ if there is the right input data received from the raspberry PI, then start running the system<br \/>\nSerial.println(&#8220;called through PI&#8221;);<br \/>\ncPI();<br \/>\n}<br \/>\nelse {<br \/>\ndigitalWrite(relay, HIGH); \/\/ disconnect powersupply<br \/>\nrelayVal = HIGH; \/\/ relay works inverse: HIGH = power gets disconnected from system; only the red led on relay is on<br \/>\n}<br \/>\n}<br \/>\n\/\/_____________________END of LOOP_____________________________________________<br \/>\n\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;FUNCTIONS&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\nvoid recvInfo() { \/\/ checks if data is received from the raspberry pi<br \/>\nif (Serial.available() &gt; 0) {<br \/>\nreceivedChar = Serial.read(); \/\/ puts the value into ther variable receivedChar<br \/>\nif (receivedChar = &#8216;s&#8217;) { \/\/ if the value equals s (start)<br \/>\nnewData = true; \/\/ set new data to true, so that the function of starting the system in the loop can get called<br \/>\n}<br \/>\nelse {<br \/>\nnewData = false; \/\/ if its not a s (start) then do nothing<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>void cButton() {<br \/>\nwholeSystemFunction(valueReadLoadCell, valueLimit ); \/\/ calls the function of starting the sytem started by the button<br \/>\n}<\/p>\n<p>void cPI() {<br \/>\nwholeSystemFunction(valueReadLoadCell, valueLimit); \/\/ calls the function of starting the sytem started by the pi<br \/>\nnewData = false; \/\/ after running the system, the variable has to be set to false again<br \/>\ndelay(1000); \/\/ give time to process: found out during testing that without its more liable for mistakes<br \/>\n}<\/p>\n<p>void wholeSystemFunction(float valueReadLoadCell, float valueLimit) {<br \/>\ndelay(1000);<br \/>\nmyservo360.attach(servPin360); \/\/ attach the servo that presses the toothpaste<br \/>\ndelay(500);<br \/>\ndigitalWrite(relay, LOW); \/\/ relay works inverse: LOW = connected to external powersupply; red and green led on relay are on<br \/>\nrelayVal = LOW; \/\/ set the value to its start state with which the servos gets controlled<\/p>\n<p>checkLoadCell(); \/\/ check the measured value on the load cell<br \/>\ncalcNewValue(valueReadLoadCell, valueLimit); \/\/ call the function to calculate a new value<\/p>\n<p>\/\/PUSH TOOTHPASTE<br \/>\nif (relayVal == LOW) { \/\/ run following if the relay is on<br \/>\ndelay(1000);<br \/>\nSerial.print(&#8220;In whole System Function: &#8220;);<br \/>\nSerial.println(valueLimit);<br \/>\npreviousMillis = millis();<br \/>\nwhile (scale.get_units() &lt;= valueLimit &amp;&amp; millis() &#8211; previousMillis &lt;= 8000) { \/\/ keep the servo running as long as the measured value, which is changing all the time, is smaller then the interval (one portion of toothpaste). stop moving if the weight is not reached within 8 seconds.<br \/>\nservo360(speed, valueReadLoadCell); \/\/ call function to move the servo<br \/>\n}<br \/>\nwhile (scale.get_units() &lt;= valueLimit &amp;&amp; millis() &#8211; previousMillis &gt;= 8000) {<br \/>\nreturn;<br \/>\n}<br \/>\nmyservo360.detach(); \/\/ detach the servo to stop it from twitching<br \/>\ndelay(100);<br \/>\n\/\/OPEN DOOR<br \/>\nmyservo180.attach(servPin180); \/\/ connect the second servo<br \/>\nservo180(); \/\/ call the function of the second servo to open the door<br \/>\nmyservo180.detach(); \/\/ detach the servo to stop it from twitching<br \/>\n}<br \/>\n}<\/p>\n<p>int checkButton() { \/\/ gets called in the loop<br \/>\nbutVal = digitalRead(butPin); \/\/ put the state of the button into the butVal variable<br \/>\nreturn butVal; \/\/ return the value<br \/>\n}<\/p>\n<p>int checkLoadCell() { \/\/ function gets called in wholeSystem function<br \/>\nvalueReadLoadCell = (scale.get_units()); \/\/ stores the value of the load cell in this variable<br \/>\nSerial.print(&#8220;Measured Value in loadCell Function: &#8220;);<br \/>\nSerial.println(valueReadLoadCell);<br \/>\nreturn valueReadLoadCell; \/\/ returns the value. this is now a fixed value, which is used in the next function<br \/>\n}<\/p>\n<p>float calcNewValue (float &amp; valueReadLoadCell, float &amp; valueLimit) { \/\/calculate a new variable depending on the measured value + a preset interval<br \/>\nvalueLimit = valueReadLoadCell + 0.3; \/\/ this variable is very important. the load cell is very responsive, so from one go to the next the number levels in at different values. befor the measured value was compared to a fixed number but since the measured value was not stable at all that was a huge liability and the limit value had to be changed all the time. now the servo rotates on base of a not changing interval and not on a uncontrolable difference.<br \/>\nSerial.print(&#8220;Value calculated in calc Function: &#8220;);<br \/>\nSerial.println(valueLimit);<br \/>\nreturn valueLimit;<br \/>\n}<\/p>\n<p>void servo360(int speed, float valueReadLoadCell) {<br \/>\nmyservo180.attach(servPin180); \/\/ connect the door opener. necesserary because it always twitches open<br \/>\nmyservo180.write(110); \/\/ set him to 110 degree, which is the closed position. could be set as a variable<br \/>\ndelay(100); \/\/ give him time to do that<br \/>\nmyservo180.detach(); \/\/ detach him to stop it from twitching<br \/>\ndelay(1000); \/\/ give him time to do that<br \/>\nmyservo360.write(speed); \/\/ start to push toothpaste<br \/>\n}<\/p>\n<p>void servo180() {<br \/>\nopen(); \/\/ call function to open the box<br \/>\nwhile (scale.get_units() &lt; 15) { \/\/ do nothing as long as the weight recognised is smaller then 50 (we still need to find out which number actually makes sense through making a few measurements when the toothbrush gets put into the bracket, thats the number we need here)<br \/>\nSerial.println(scale.get_units());<br \/>\n}<br \/>\nwhile (scale.get_units() &gt; 15) { \/\/ call function close, when toothbrush gets put into the bracket \/ box<br \/>\nclose();<br \/>\n}<br \/>\n}<\/p>\n<p>void open() {<br \/>\ndelay(5000); \/\/ this delay gives the toothpaste a little bit time to settle onto the toothbrush<br \/>\ndirection = 1; \/\/ 1 equals opening direction = clockwise<br \/>\nif (direction == 1) { \/\/ if it is one<br \/>\nfor (int i = 115; i &gt;= 30; i&#8211;) { \/\/ move the servo from its starting position to the open position at 30 degree. can be opened further but 30\u00ba is enough<br \/>\nmyservo180.write(i); \/\/<br \/>\ndelay(50); \/\/ delay determines the speed of opening the door<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>int close() {<br \/>\ndelay(5000); \/\/ this delay is very important, it should be as accurate as possible and be the average time that a person needs to put the toothbrush back into the bracket, and remove his hand, so that the door doesnt close if the hand is still in the door<br \/>\ndirection = 0; \/\/ 0 equals closing direction = counter clockwise<br \/>\nif (direction == 0) { \/\/ if it is zero<br \/>\nfor (int i = 30; i &lt;= 115; i++) { \/\/ move the servo from its opening position to the close position to 115 degree. the closing position was determined through various tests<br \/>\nmyservo180.write(i);<br \/>\ndelay(50); \/\/ delay determines the speed of opening the door<br \/>\n}<br \/>\n}<br \/>\nreturn newData = false; \/\/ set newData to false, again. probably redundant<br \/>\ndelay(5000); \/\/ give time to settle<br \/>\n}<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/Relay\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ const int relay = 5; int relayVal; \/\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/loadCell\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ #include &#8220;HX711.h&#8221; #define zero_factor 555230 #define DOUT 3 \/\/gelb \/ yellow #define CLK 2 \/\/orange float calibration_factor = ((200000 * 0.00045359237) + 52400); HX711 scale(DOUT, CLK); float valueReadLoadCell; float valueLimit; \/\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/Servo\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ #include &lt;Servo.h&gt; Servo myservo360; \/\/ continious rotation servo Servo myservo180; \/\/ 180 servo [&hellip;]<\/p>\n","protected":false},"author":55,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2757","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=\/wp\/v2\/posts\/2757","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=\/wp\/v2\/users\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2757"}],"version-history":[{"count":1,"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=\/wp\/v2\/posts\/2757\/revisions"}],"predecessor-version":[{"id":2760,"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=\/wp\/v2\/posts\/2757\/revisions\/2760"}],"wp:attachment":[{"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2757"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2757"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dronesonen.usn.no\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2757"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}