Sketch that responds to certain commands, how is it done? - c

Alright I have a half complete Arduino sketch at the moment. Basically the sketch below will blink an LED on a kegboard-mini shield if a string of chars equals *{blink_Flow_A}* However the LED only blinks once with the current sketch loaded on the Arduino. I will like the Arduino to blink repeatedly until the "stop" command is sent to the Arduino. I would eventually like to open a valve, keep it open until the valve receives to the close command then close the valve. The sketch looks like the following,
/*
* kegboard-serial-simple-blink07
* This code is public domain
*
* This sketch sends a receives a multibyte String from the iPhone
* and performs functions on it.
*
* Examples:
* http://arduino.cc/en/Tutorial/SerialEvent
* http://arduino.cc/en/Serial/read
*/
// global variables should be identified with _
// flow_A LED
int led = 4;
// relay_A
const int RELAY_A = A0;
// variables from sketch example
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
void setup() {
Serial.begin(2400); // open serial port, sets data rate to 2400bps
Serial.println("Power on test");
inputString.reserve(200);
pinMode(RELAY_A, OUTPUT);
}
void open_valve() {
digitalWrite(RELAY_A, HIGH); // turn RELAY_A on
}
void close_valve() {
digitalWrite(RELAY_A, LOW); // turn RELAY_A off
}
void flow_A_blink() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for one second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
void flow_A_blink_stop() {
digitalWrite(led, LOW);
}
void loop() {
// print the string when newline arrives:
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
if (inputString == "{blink_Flow_A}") {
flow_A_blink();
}
}
//SerialEvent occurs whenever a new data comes in the
//hardware serial RX. This routine is run between each
//time loop() runs, so using delay inside loop can delay
//response. Multiple bytes of data may be available.
void serialEvent() {
while(Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
If it makes any difference someone on IRC told me to research state machines scratches head

To blink a Led without blocking the program, i suggest you use Timer (and the TimerOne library). I make a quick sample code :
#include "TimerOne.h" //Include the librart, follow the previous link to download and install.
int LED = 4;
const int RELAY_A = A0;
boolean ledOn;
void setup()
{
pinMode(LED, OUTPUT)
Timer1.initialise(500000) // Initialise timer1 with a 1/2 second (500000µs) period
ledOn = false;
}
void blinkCallback() // Callback function call every 1/2 second when attached to the timer
{
if(ledOn){
digitalWrite(LED,LOW);
ledOn = false;
}
else{
digitalWrite(LED,HIGH);
ledOn = true;
}
}
void open_valve() {
digitalWrite(RELAY_A, HIGH); // turn RELAY_A on
}
void close_valve() {
digitalWrite(RELAY_A, LOW); // turn RELAY_A off
}
void serialEvent() {
while(Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '\n') {
stringComplete = true;
}
}
}
void loop()
{
// print the string when newline arrives:
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
if (inputString == "{blink_Flow_A}") {
Timer1.attachInterupt(blinkCallback); //Start blinking
}
if (inputString == "{stop}") {
Timer1.detachInterrupt(); //Stop blinking
}
if (inputString == "{open_valve}") {
open_valve();
}
if (inputString == "{close_valve}") {
close_valve();
}
}
Note :
Consider putting the tag 'c' or 'java' to have syntax highlighting on the code.

A state machine (at it's simplest - it can be lots more complicated) can be just a set of conditional statements (if/else or switch/case) where you do certain behaviors based on the state of a variable, and also change that variable state. So it can be thought of as a way of handling or progressing through a series of conditions.
So you have the state of your LED/valve - it is either blinking (open) or not blinking (closed). In pseudo code here:
boolean LED_state = false; //init to false/closed
void loop(){
if (checkForCorrectCommand() == true){ //
if (LED_State == false){
open_valve();
LED_State = true;
} else {
close_valve();
LED_State = false;
}
}
}
The blinking LED part should be easy to implement if you get the gist of the code above. The checkForCorrectCommand() bit is a function you write for checking whatever your input is - key, serial, button, etc. It should return a boolean.

Perhaps something like the 'blink without delay' example in the IDE. You check the time and decide to when and how to change the LED/Digital out.
// Variables will change:
int ledState = LOW; // ledState used to set the LED
long previousMillis = 0; // will store last time LED was updated
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000; // interval at which to blink (milliseconds)
void setup(){
// Your stuff here
}
void loop()
{
// Your stuff here.
// check to see if it's time to blink the LED; that is, if the
// difference between the current time and last time you blinked
// the LED is bigger than the interval at which you want to
// blink the LED.
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}

Let me offer a suggested sketch with a few changes. Bastyen's idea of using a timer is quite good and makes the code much easier. The approach I would suggest is to have the timer pop forever at a fixed interval (100 milliseconds in my sketch). If the LED should not be blinking it stays off. If the LED should be blinking, it switches from off to on or vice versa each time the timer goes off.
#include "TimerOne.h"
/*
* kegboard-serial-simple-blink07
* This code is public domain
*
* This sketch sends a receives a multibyte String from the iPhone
* and performs functions on it.
*
* Examples:
* http://arduino.cc/en/Tutorial/SerialEvent
* http://arduino.cc/en/Serial/read
*/
// global variables should be identified with _
// flow_A LED
int led = 4;
// relay_A
const int RELAY_A = A0;
// variables from sketch example
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
boolean shouldBeBlinking = false;
boolean ledOn = false;
void setup() {
Serial.begin(9600); // open serial port, sets data rate to 2400bps
Serial.println("Power on test");
inputString.reserve(200);
pinMode(RELAY_A, OUTPUT);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
Timer1.initialize(100000);
Timer1.attachInterrupt(timer1Callback);
}
void loop() {
if (!stringComplete)
return;
if (inputString == "{blink_Flow_A}")
flow_A_blink_start();
if (inputString == "{blink_Flow_B}")
flow_A_blink_stop();
inputString = "";
stringComplete = false;
}
void timer1Callback() {
/* If we are not in blinking mode, just make sure the LED is off */
if (!shouldBeBlinking) {
digitalWrite(led, LOW);
ledOn = false;
return;
}
/* Since we are in blinking mode, check the state of the LED. Turn
it off if it is on and vice versa. */
ledOn = (ledOn) ? false : true;
digitalWrite(led, ledOn);
}
void flow_A_blink_start() {
shouldBeBlinking = true;
open_valve();
}
void flow_A_blink_stop() {
shouldBeBlinking = false;
close_valve();
}
void close_valve() {
digitalWrite(RELAY_A, LOW); // turn RELAY_A off
}
void open_valve() {
digitalWrite(RELAY_A, HIGH); // turn RELAY_A on
}
//SerialEvent occurs whenever a new data comes in the
//hardware serial RX. This routine is run between each
//time loop() runs, so using delay inside loop can delay
//response. Multiple bytes of data may be available.
void serialEvent() {
if (stringComplete)
return;
while(Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString unless it is a newline
if (inChar != '\n')
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
else {
stringComplete = true;
}
}
}
A few notes:
The setup function establishes the timer with a 100 millisecond interval and attaches the callback routine. Based on my testing, this only needs to be done once.
The main loop just ignores everything unless an input string is complete. If an input string is ready, then the input string is checked for two known values and the appropriate steps are taken. The input string is then discarded.
The timer callback routine forces the LED off, if we are not in blinking mode. Otherwise, it just toggles the state of the LED.
The flow on and flow off routines set the blinking state as need be and control the valve
The serial event routine has two changes. First, input is ignored (and kept in the buffer) if an input string is already complete. This will preserve commands that are being sent to the Arduino while the current command is being processed. Second, the newline character is not added to the input string. This makes checking the input string slightly easier.

Related

Is there a way to calculate -time interval- using Esp32 timers?

I want to calculate time interval with timers. I'm using arduino ide. Also i can not decide which library to useful.
I just tried something following code.
I'm using this library
#include <ESP32Time.h>
int a;
int b;
int ldrValue;
#define LDR 0
/* create a hardware timer */
hw_timer_t * timer = NULL;
int timeThatPast;
/* motor pin */
int motor = 14;
/* motor state */
volatile byte state = LOW;
void IRAM_ATTR onTimer(){
state = !state;
digitalWrite(motor, state);
}
void setup() {
Serial.begin(115200);
pinMode(motor, OUTPUT);
/* Use 1st timer of 4 */
/* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
timer = timerBegin(0, 80, false);
/* Attach onTimer function to our timer */
timerAttachInterrupt(timer, &onTimer, true);
//********************ALARM*******************
/* Set alarm to call onTimer function every second 1 tick is 1us
=> 1 second is 1000000us */
/* Repeat the alarm (third parameter) */
timerAlarmWrite(timer, 7000000, false);
//********************************************
/* Start an alarm */
timerAlarmEnable(timer);
Serial.println("start timer");
}
void loop() {
int ldrValue = analogRead(LDR);
ldrValue = map(ldrValue, 0, 4095, 0, 10000);
if(ldrValue > 8500){
a = timerRead(timer);
digitalWrite(motor,HIGH);
while(1){
int ldrValue = analogRead(LDR);
ldrValue = map(ldrValue, 0, 4095, 0, 10000);
if(ldrValue < 8500){
b = timerRead(timer);
digitalWrite(motor,LOW);
Serial.print("Entering Loop");
Serial.println(a);
Serial.println("**********");
Serial.println("**********");
Serial.print("Exiting loop");
Serial.println(b);
int difference = b - a;
Serial.println("Difference");
Serial.println(difference);
break;
}
}
}
}
Use millis or micros if you need more precise timing.
Here is an example sketch:
long lastDoTime = 0;
void setup(){
Serial.begin(115200);
delay(1000);
Serial.println("Hello! We will do something at every ms");
}
void doThisAtEvery(int ms){
if( millis() - lastDoTime >= ms ){
// Must save the lastDoTime
lastDoTime = millis();
// Do some stuff at every ms
}
}
void loop(){
// It will do the thing in every 100 ms.
doThisAtEvery(100);
}
If you want to toggle a pin let's say every 100 microsec
long lastToggleTime = 0;
int motorPin = 14;
boolean lastPinState = LOW;
void setup(){
Serial.begin(115200);
}
void togglePinEvery(int micros){
if( micros() - lastToggleTime >= micros ){
lastToggleTime = micros();
digitalWrite(motorPin,!lastPinState);
lastPinState = !lastPinState;
}
}
void loop(){
togglePinEvery(100);
}
EDIT Since you wanted timers only.
Here is a detailed explanation about timers: https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
Code example:
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer);
}
void loop() {
if (interruptCounter > 0) {
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
totalInterruptCounter++;
Serial.print("An interrupt as occurred. Total number: ");
Serial.println(totalInterruptCounter);
}
}

Arduino Interrupt with One Button

I am using Arduino Uno, I try to run servo constantly from 0 to 45 degrees when the interrupt button is pressed it should go to -30 degree and wait here. When the same button is pressed again, it should resume the constant action, which is swiping 0 to 45 degrees without <servo.h> library.
I tried to run like this:
const int servo = 11;
const int led = 13;
const int buttonPin = 2;
volatile int buttonState = 1;
void setup() {
Serial.begin(57600);
pinMode(led, OUTPUT);
pinMode(servo, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(buttonPin),Button,CHANGE);
}
void loop() {
digitalWrite(led,HIGH);
for(int i=0;i<30;i++)
{
digitalWrite(servo,HIGH);
delayMicroseconds(1500);
digitalWrite(servo,LOW);
delayMicroseconds(18500);
}
delay(2000);
for(int i=0;i<30;i++)
{
digitalWrite(servo,HIGH);
delayMicroseconds(1000);
digitalWrite(servo,LOW);
delayMicroseconds(19000);
}
delay(2000);
}
void Button()
{
digitalWrite(led,LOW);
for(int i=0;i<30;i++)
{
digitalWrite(servo,HIGH);
delayMicroseconds(1833);
digitalWrite(servo,LOW);
delayMicroseconds(18167);
}
}
I have no problem coding my own PWM for each case but it turns out, the problem is a bit complicated than I was expecting because when we try to resume, I need to disable the interrupt function when pressing the same an interrupt button somehow.
Is it possible in this way or is there a better way to implement it?

trying to work with strings and serial port on arduino, my sketch skips characters for some reason

I've been trying to achieve serial communication between my arduino-based project and my pc ,i need to send commands to arduino over serial and use "if and else" to call desired function (in parseMessage() function).
I can't use delay() since I'm using interrupts for multiplexing and bit-angle modulation so i had to do serial communication another way around, this is closest I've got to succeess but still I'm getting character skips and unstability in general. and as you know coding is all great except for when you don't know what's wrong with your code, so help me please gods of the internet! ;)
The reason I'm using '#' as end of the string declearation is that I can't be sure that all characters of my command sent to arduino is there when Serial.read() asks for it, there might be more on the way and since atmega328 is faster than serial port Serial.available() might actually return -1 in middle of transmission.
ps : oh, and I can't use String class, It's very expensive, this atmega328 is already sweating under 8x8 RGBLED multiplexing and 4bit-angle modulation and he is gonna have to do even more in future.
ps : and I'm still learning English so pardon me if there is something wrong with the grammer I'm using.
void setup() {
Serial.begin(9600);
}
bool dataRTP = false; // data ready to parse
void loop() {
readSerial();
}
char message[64];
int index = 0;
void readSerial() {
if (Serial.available() > 0)
while (Serial.available() > 0)
if (Serial.peek() != '#') // i'm using '#' as end of string declearation.
message[index++] = Serial.read();
else {
message[index++] = '\n';
dataRTP = true;
break;
}
while (Serial.read() != -1) {} // flushing any possible characters off of
if (dataRTP) // UARTS buffer.
parseMessage();
}
void parseMessage() { // just testing here, actual code would be like :
Serial.print(message); // if (!strcmp(message, "this expression"))
index = 0; // callthisfunction();
dataRTP = false; // else ... etc
}
Just managed to fix this code, seems flushing data off of serial UART wasn't a good idea after all. It's all solved. Here's how code looks now:
void setup() {
Serial.begin(9600);
}
bool dataRTP = false;
void loop() {
readSerial();
}
char message[64];
int index = 0;
void readSerial() {
if (Serial.available() > 0)
while (Serial.available() > 0)
if (Serial.peek() == '#') {
message[index++] = Serial.read();
message[index++] = '\0';
dataRTP = true;
break;
}
else
message[index++] = Serial.read();
if (dataRTP)
parseMessage();
}
void parseMessage() {
Serial.println(message);
index = 0;
dataRTP = false;
}

String commands for Arduino sketch kind of working but not really

So I have an Arduino sketch that reads serial commands (a string of chars) and then have the sketch do something based on the command it receives. As of right now I have two commands,
{open_valve}
{close_valve}
When I send the command, {open_valve} to the Arduino, the valve opens fine, but the valve is not closing when I send the command {close_valve} to the Arduino. The sketch looks like the following,
// flow_A LED
int led = 4;
// relay_A
const int RELAY_A = A0;
// variables from sketch example
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
// variables from SO thread
boolean LED_state = false;
boolean vavle_open = false;
// flowmeter shit
unsigned long totalCount = 0;
unsigned long previousCount = 0;
int pin = 2;
unsigned long duration;
// storage variable for the timer
unsigned long previousMillis=0;
int interval=1000; //in milliseconds
// counters for each flowmeter
unsigned long countA = 0;
void setup() {
Serial.begin(115200); // open serial port, sets data rate to 115200bps
Serial.println("Power on test");
inputString.reserve(200);
pinMode(RELAY_A, OUTPUT);
// flowmeter shit
pinMode(pin, INPUT);
}
void open_valve() {
digitalWrite(RELAY_A, HIGH); // turn RELAY_A on
// set the boolean value for "vavle_open" to true
//valve_open = true;
Serial.println("Valve Open");
}
void close_valve() {
Serial.println("2");
digitalWrite(RELAY_A, LOW); // turn RELAY_A off
//valve_open = false;
Serial.println("3");
Serial.println("Vavle Closed");
}
void controlValve(bool open)
{
}
void flow_A_blink() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for one second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
void flow_A_blink_stop() {
digitalWrite(led, LOW);
}
void getFlow() {
duration = pulseIn(pin, HIGH);
Serial.print(duration);
Serial.println("");
delay(200);
}
/*
* Main program loop, runs over and over repeatedly
*/
void loop() {
if(checkForCorrectCommand("{open_valve}") == true) {
open_valve();
Serial.println("OPENING");
getFlow();
}
else if(checkForCorrectCommand("{close_valve}") == true)
{
close_valve();
Serial.println("CLOSING");
}
}
bool checkForCorrectCommand(String cmd) {
//Serial.println(inputString);
//Serial.println(cmd);
if(inputString == cmd) {
// reset String variables for serial data commands
Serial.println("1");
inputString = "";
stringComplete = false;
return true;
// reset String variables for serial data commands
inputString = "";
stringComplete = false;
return false;
}
}
//SerialEvent occurs whenever a new data comes in the
//hardware serial RX. This routine is run between each
//time loop() runs, so using delay inside loop can delay
//response. Multiple bytes of data may be available.
void serialEvent() {
while(Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
Your code should not compile as pasted here. The checkForCorrectCommand function does not have a return value for both the match and unmatch. Your code shows you intend to empty the inputString buffer for both the match and non matched case. If the string match is not true, you want to leave the input buffer unchanged so that the following test cases can run.
bool checkForCorrectCommand(String cmd) {
if(inputString == cmd) {
// for match case, the string is consumed from the buffer
inputString = "";
stringComplete = false;
return true;
}
else {
// for the non-match case, leave the buffer for further Rx or further tests
return false;
}
So I modified my sketch with the following code, and now it seems to processing the serial commands the way I want it too.
// flow_A LED
int led = 4;
// relay_A
const int RELAY_A = A0;
// variables from sketch example
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
// variables from SO thread
boolean LED_state = false;
boolean vavle_open = false;
// flowmeter shit
unsigned long totalCount = 0;
unsigned long previousCount = 0;
int pin = 2;
unsigned long duration;
// storage variable for the timer
unsigned long previousMillis=0;
int interval=1000; //in milliseconds
// counters for each flowmeter
unsigned long countA = 0;
void setup() {
// initialize serial
Serial.begin(9600); // open serial port, sets data rate to 115200bps
// Serial.println("Power on test - println");
// line below is for iPhone testing
// Serial.write("Power on test - write");
inputString.reserve(200);
pinMode(RELAY_A, OUTPUT);
// flowmeter shit
pinMode(pin, INPUT);
}
void open_valve() {
digitalWrite(RELAY_A, HIGH); // turn RELAY_A on
// Serial.println("Valve Open");
Serial.write("{valve_open}");
}
void close_valve() {
digitalWrite(RELAY_A, LOW); // turn RELAY_A off
// Serial.println("Vavle Closed");
Serial.write("{valve_close}");
}
void flow_A_blink() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for one second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
void flow_A_blink_stop() {
digitalWrite(led, LOW);
}
void getFlow() {
duration = pulseIn(pin, HIGH);
Serial.print(duration);
Serial.println("");
delay(200);
}
/*
* Main program loop, runs over and over repeatedly
*/
void loop() {
//print the string when a newline arrives:
if(stringComplete) {
// Serial.println(inputString);
if(inputString.equals("{open_valve}\n")) {
// Serial.println("opening valve.");
open_valve();
}
if(inputString.equals("{open_valve}")) {
// Serial.println("opening valve.");
open_valve();
}
if(inputString.equals("{close_valve}\n")) {
// Serial.println("close vavle.");
close_valve();
}
if(inputString.equals("{close_valve}")) {
// Serial.println("close vavle.");
close_valve();
}
// clear the string:
inputString = "";
stringComplete = false;
}
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
while(Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
// Serial.println(inputString.length());
}
}
The note from jdr5ca is quite correct. The checkForCorrectCommand routine needed an else clause with a separate return statement. The solution devised by Chris is good. It is clearly better to only process the contents of inputString if it is complete and discard it (the contents of inputString) after checking for the valid commands. I would like to offer a minor change to serialEvent.
The serialEvent routine should not keep adding characters to a string that is already complete. Instead it should leave them in the buffer to help form the next command. See the code below.
void serialEvent() {
if (stringComplete)
return;
while(Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

Move robot set number of steps (Arduino)

I want to move my robot a set number of steps and then have it stop. However the loop just seems to run on infinitely. Is there a mistake in the way that I am using void loop() or perhaps in the way that I have written my 'for' loop?
// walkerForward.pde - Two servo walker. Forward.
// (c) Kimmo Karvinen & Tero Karvinen http://BotBook.com
// updated - Joe Saavedra, 2010
#include <Servo.h>
Servo frontServo;
Servo rearServo;
int centerPos = 90;
int frontRightUp = 75;
int frontLeftUp = 120;
int backRightForward = 45;
int backLeftForward = 135;
void moveForward(int steps)
{
for (int x = steps; steps > 0; steps--) {
frontServo.write(centerPos);
rearServo.write(centerPos);
delay(100);
frontServo.write(frontRightUp);
rearServo.write(backLeftForward);
delay(100);
frontServo.write(centerPos);
rearServo.write(centerPos);
delay(100);
frontServo.write(frontLeftUp);
rearServo.write(backRightForward);
delay(100);
}
}
void setup()
{
frontServo.attach(2);
rearServo.attach(3);
}
void loop()
{
moveForward(5);
}
the loop() function is executed within an infinite loop (if you check the main cpp file that ships with the Arduino IDE, you'll see something like this:
int main()
{
setup();
for (;;) {
loop();
}
return 0;
}
So either put the call to your moveForward() function to setup() and make loop() an empty function, or call exit(0); from within loop() after moveForward(). The first approach looks like this:
void setup()
{
frontServo.attach(2);
rearServo.attach(3);
moveForward(5);
}
void loop()
{
}
And the second one looks like this:
void setup()
{
frontServo.attach(2);
rearServo.attach(3);
}
void loop()
{
moveForward(5);
exit(0);
}
Since you probably will want to eventually do more than move the robot just 5 steps, I'd suggest using a variable flag to hold the robot state. It only executes the movement routine when the flag has been set to true.
If you are using serial, when a move command is received (and the number of steps, direction perhaps?) you set the flag to true and then issue the move command. If you are using sensors or buttons, the same logic applies.
You will need some logic to handle an incoming movement command while a movement is occurring (though with your tight movement loop you actually won't be able to respond to incoming commands unless you use interrupts - but you want to consider this sort of thing if you are planning to build out a full movement bit of firmware).
boolean shouldMove;
void setup()
{
shouldMove = true;//set the flag
}
void loop()
{
if (shouldMove){
moveForward(5);
}
}
void moveForward(int steps)
{
shouldMove = false; //clear the flag
for (int x = steps; steps > 0; steps--) {
// tight loop controlling movement
}
}
}

Resources