{"id":28,"date":"2012-01-27T21:11:44","date_gmt":"2012-01-28T02:11:44","guid":{"rendered":"http:\/\/www.mcgurrin.com\/robots\/?p=28"},"modified":"2012-01-30T19:56:23","modified_gmt":"2012-01-31T00:56:23","slug":"move-now-dont-delay-the-metro-libray","status":"publish","type":"post","link":"https:\/\/www.mcgurrin.info\/robots\/28\/","title":{"rendered":"Move now, don&#8217;t delay();  the metro library"},"content":{"rendered":"<p>The classic &#8220;hello world&#8221; of the Arduino world includes something like:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid loop()\r\n{\r\n  digitalWrite(ledPin, HIGH);   \/\/ sets the LED on\r\n  delay(1000);                  \/\/ waits for a second\r\n  digitalWrite(ledPin, LOW);    \/\/ sets the LED off\r\n  delay(1000);                  \/\/ waits for a second\r\n}\r\n<\/pre>\n<p>Simple sample code for robotic vehicles may include something similar, such as<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/Move Forward for 10 seconds\r\nadvance (255,255);\r\ndelay(10000);\r\n<\/pre>\n<p>where the advance function is previously defined. This approach, using delay(), works fine until you want your robot to do something else while moving, like check sensors for obstacles, or see if a button was pushed to turn it off, or updating its position based on sensor input. The problem of course, is that while the delay is running, the cpu does nothing (although it will process interrupts). So clearly using delay() for this purpose is not a good idea.<\/p>\n<p>Rather than having your code sit idle at a point in the loop function, spinning its figurative wheels, you want the software to continue looping through the main loop, but stopping when a set time is reached. One approach is to use a timer interrupt. Have your code continue through the loop, but set an interrupt service routine that sets a flag, signifying the time has elapsed and it&#8217;s time to stop doing what you were doing (e.g., moving forward) and do something else. An introduction to timers and interrupts can be found on the <a href=\"http:\/\/letsmakerobots.com\/node\/28278\">Let&#8217;s Make Robots<\/a> site, and you should also check the <a href=\"http:\/\/www.arduino.cc\/en\/Reference\/AttachInterrupt\">Arudino reference page on interrupts<\/a> .\u00a0 If you&#8217;d like to keep things simpler, there are <a href=\"http:\/\/arduino.cc\/playground\/Code\/Timer1\">Arduino libraries<\/a> for using timer interrupts as well.<\/p>\n<p>An alternative approach is to use the<a href=\"http:\/\/arduino.cc\/playground\/Code\/Metro\"> metro library<\/a>.\u00a0 The metro library provides an alternative to using timer interrupts.\u00a0 Because it does not use interrupts, the code in your loop will need to check to see if the timer has expired or not.\u00a0 The sample code below works on my robot that uses an Arduino-compatible Romeo controller and RP5 chassis.\u00a0 It was based on the example provided by <a href=\"http:\/\/www.dfrobot.com\/\">DFRobot<\/a> but adds a) using switch 1 on the Romeo board as a start\/stop switch and b) instead of using delay(), it uses the Metro library.<\/p>\n<p>The key section of the code is the nextMovement function. It&#8217;s called every time the main loop executes. A timer called movementMetro was already initialized as part of the setup. This nextMovement function checks if the timer has gone off, and if it has, changes the movement case to the next in line and resets the value for the appropriate time. One tricky part is that the timer value is for the NEXT movement, not the one in the movement just completed.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid nextMovement (int next,unsigned long wait) \/\/ Set case and delay for next movement\r\n  {\r\n    if (movementMetro.check() == 1) {\r\n      movement = next;\r\n      movementMetro.interval(wait);\r\n    }\r\n  }\r\n<\/pre>\n<p>Here&#8217;s the full, working code. When run, you need to push button 1 once the code is loaded. The robot then moves forward, turns, move forward, reverses, turns, and reverses again, with pauses between each movement. You can stop and restart the cycle by using switch 1.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &amp;lt;Metro.h&amp;gt;\r\n\r\n\/\/ Setup movement timer using the Metro library\r\nMetro movementMetro = Metro(4000);\r\n\r\n\/\/ Buttons vars\r\n\r\nconst int key_S1_5 = 7;\r\n\r\nint state = false; \/\/ Off if 0, On if 1\r\n\r\nint buttons_check(){\r\n \/\/ This function checks button 1 and returns\r\n \/\/ 0 if no button pressed, 1 if pressed\r\n \/\/ Priorities: S1, S2, S3, S4, S5\r\n int w = analogRead(key_S1_5);\r\n\r\n#define vS2 130\r\n if ( w &amp;lt; vS2\/2 ){\r\n  return 1;\r\n}\r\n return 0;\r\n}\/\/End buttons_check()\r\n\r\n \/\/ Set up for running motors\r\nint E1 = 5;  \/\/ digital output pin sending PWM power to the motor\r\nint E2 = 6;  \/\/ digital output pin sending PWM power to the motor\r\nint M1 = 4;  \/\/ controls is motor moves forward or backwards\r\nint M2 = 7;  \/\/ controls is motor moves forward or backwards\r\n\r\nvoid forward(byte a,byte b)\t\t\/\/Move forward\r\n        {\r\n          analogWrite(E1,a);\r\n          digitalWrite(M1,HIGH);\r\n          analogWrite(E2,b);\r\n          digitalWrite(M2,HIGH);\r\n        }\r\n\r\nvoid stop(void)                    \t\/\/Stop\r\n        {\r\n          digitalWrite(E1,LOW);\r\n          digitalWrite(E2,LOW);\r\n        }\r\n\r\nvoid backward (byte a,byte b)\t\t\/\/Move backward\r\n        {\r\n          analogWrite (E1,a);\r\n          digitalWrite(M1,LOW);\r\n          analogWrite (E2,b);\r\n          digitalWrite(M2,LOW);\r\n}\r\n\r\nvoid Left (byte a,byte b)\t\t\/\/Turn left\r\n        {\r\n          analogWrite (E1,a);\r\n          digitalWrite(M1,LOW);\r\n          analogWrite (E2,b);\r\n          digitalWrite(M2,HIGH);\r\n        }\r\nvoid Right (byte a,byte b)\t\t\/\/Turn right\r\n        {\r\n          analogWrite (E1,a);\r\n          digitalWrite(M1,HIGH);\r\n          analogWrite (E2,b);\r\n          digitalWrite(M2,LOW);\r\n        }\r\nint movement = 1; \/\/ movement controls which movement (forward, turn, etc.)\r\n\r\nvoid nextMovement (int next,unsigned long wait) \/\/ Set case and delay for next movement\r\n  {\r\n    if (movementMetro.check() == 1) {\r\n      movement = next;\r\n      movementMetro.interval(wait);\r\n    }\r\n  }\r\n\r\nvoid setup(){\r\n    for(int i=4;i&amp;lt;=7;i++)\r\n    pinMode(i, OUTPUT);\r\n    Serial.begin(9600);\r\n}\/\/ End setup\r\nvoid loop(){\r\n\r\n\/\/ This section checks button 1, which functions as stop\/start switch, initially stopped\r\n int button = buttons_check();\r\n if ( button == 1 ) {\r\n \/\/ Button 1 has been pressed\r\n  state = !state;\r\n }\r\n Serial.println(state);\r\n\r\n \/\/ Whenstopped after running, reset to original start mode\r\n if (state == false) {\r\n   stop(); \/\/Stop\r\n   movement = 1;\r\n   movementMetro.interval(4000);\r\n }\r\n else {\r\n   Serial.println(movement);\r\n\r\n \/\/ Each case sets movement command, signals next movement, and resets timer for duration OF NEXT MOVEMENT\r\n   switch (movement) {\r\n     case 1:\r\n       forward(255,255); \/\/Forward at full speed\r\n       nextMovement(2, 5000);\r\n       break;\r\n     case 2:\r\n       stop(); \/\/Stop\r\n       nextMovement(3, 650);\r\n       break;\r\n     case 3:\r\n       Right(255,255);  \/\/Right at full speed\r\n       nextMovement(4, 5000);\r\n       break;\r\n     case 4:\r\n       stop(); \/\/Stop\r\n       nextMovement(5, 4000);\r\n       break;\r\n     case 5:\r\n       forward(255,255); \/\/Forward at full speed\r\n       nextMovement(6, 5000);\r\n       break;\r\n     case 6:\r\n       stop(); \/\/Stop\r\n       nextMovement(7, 4000);\r\n       break;\r\n     case 7:\r\n       backward(255,255); \/\/backward at full speed\r\n       nextMovement(8, 5000);\r\n       break;\r\n     case 8:\r\n       stop(); \/\/Stop\r\n       nextMovement(9, 650);\r\n       break;\r\n     case 9:\r\n       Left(255,255);  \/\/Left at full speed\r\n       nextMovement(10, 5000);\r\n       break;\r\n     case 10:\r\n       stop(); \/\/Stop\r\n       nextMovement(11, 4000);\r\n       break;\r\n     case 11:\r\n       backward(255,255); \/\/backward at full speed\r\n       nextMovement(12, 5000);\r\n       break;\r\n     case 12:\r\n       stop(); \/\/Stop\r\n       nextMovement(1, 4000);\r\n       break;\r\n   }\r\n }\r\n}\/\/ End loop\r\n<\/pre>\n<p>Nothing fancy, but it was my start on getting my project underway and moving beyond using delay().<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The classic &#8220;hello world&#8221; of the Arduino world includes something like: void loop() { digitalWrite(ledPin, HIGH); \/\/ sets the LED on delay(1000); \/\/ waits for a second digitalWrite(ledPin, LOW); \/\/ sets the LED off delay(1000); \/\/ waits for a second &hellip; <a href=\"https:\/\/www.mcgurrin.info\/robots\/28\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[3,14,15,12,4,10],"_links":{"self":[{"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/posts\/28"}],"collection":[{"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/comments?post=28"}],"version-history":[{"count":10,"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/posts\/28\/revisions"}],"predecessor-version":[{"id":63,"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/posts\/28\/revisions\/63"}],"wp:attachment":[{"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/media?parent=28"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/categories?post=28"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mcgurrin.info\/robots\/wp-json\/wp\/v2\/tags?post=28"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}