Nesting Loops, subloops and all that it implies

I am completely new to Arduino as of 3 weeks ago. I decided that this is the platform that best suits my kids and me for purposes of learning to code, performing science experiments and engineering problems and solutions.

I’m having a bear of a time wading through a project that I never thought would take this long, but what was I thinking? :smile:

Conceptually, my project seems easy enough to follow, but it’s implementation is vexing me.

I have created a very simple magnetometer (coil of wires with two leads) and have attached its two leads to the ground and signal clips on a LittleBits Proto Module. To the LIttleBits Arduino Module I have connected this to a0. I have the Little Bits USB Power Module connected to d0.

Pictured is the LB Arduino with the Magnetotmeter Proto attached to a0. Below the LB Arduino you can see the opaque white copper wire spool with a large 1"diameter Nd magnet on its immediate right.

I have created the following Sketch, which successfully reads the voltage generated by a magnet sweeping across the magnetometer every 25ms.


/*
AnalogMagnetometerReadSerial
Reads an analog magnetometer input on pin 0, prints the result to the serial monitor.

This example code is in the public domain.
*/

// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
// loop for reading the input on analog pin 0:

float sensorValue = analogRead(A0);

//analogRead command senses from 1.0-5.0 volts
//but displays these values from 1 - 1,240.
//I assigned “float” (instead of “int”) because I know that
//ultimately I will be converting this back to volts
//by dividing the “sensorValue” by 256.
//This answer will need a decimal point or it will
//be rounded to the nearest integer (int). So, I
//declared that this variable (sensorValue) is a “float”.

Serial.println(sensorValue/256.00);
//this prints out sensorValue/256.0 in volts.00
//In greater detail, I’m dividing up to 1,240
//(analog max reading)
//by 256 to come up with voltage
//then I tack on decimal and two “0’s”
//so that the final answer adds a decimal and 100ths,
//hence, it is more precise than an integer.

delay(25);
// this delay is added inbetween reads for stability,
// which prevents serial monitor from becoming overwhelmed
}

The problem now is that I am trying to nest a loop within this loop. But, it is a constant epic fail from the compiler’s standpoint. I know that this has to be simple, but I’m missing something in the syntax or do not know the right command that says something like “sub loop”.

Within this overarching loop that senses the analog values on my makeshift magnetometer I do not know the right way to insert an additional loop stating something to the effect. Since, I’m a total newbie at this, I’ll make a quick butcher job of the general way in which I wish this sketch to proceed. Forgive the mockery I will now make of your native tongue.

Int THRESHOLD = 5;
Int COUNTER = 0;
if (sensorValue >= THRESHOLD) {

COUNTER = COUNTER + 1;

if COUNTER = 100 then // some kind of OUTPUT
and COUNTER = 0

The “COUNTER” starts at 0 and counts up to a set point of “COUNTER RESET”. Let’s say “COUNTER RESET” = 100. Then “COUNTER” = 0. And, starts all over.

When 100 is reached an output is triggered.

Hi astronomique!

I tried writing and testing some code for you with straight up littleBits.

First try this circuit: power + dimmer (or any analog sensor) + a0 Analog + led on d5. Then when the code works how you like it, change THRESHOLD to match your magnetometer’s output and make whatever other changes that suit your needs.

I hope this helps!

-Jude

Here’s the code:

void setup() {
pinMode (A0, INPUT); // place power + dimmer on A0 for testing the code
pinMode (5, OUTPUT); // place an led on d5
Serial.begin(9600);
}

void loop() {
float THRESHOLD = 2.0; // in volts. You might want this lower for your magnetometer
int sensorValue;
float volts;
for (int counter=0;counter<100;counter++){
sensorValue = analogRead(A0);
volts = (sensorValue*5.0)/1024.0;
if (volts >=THRESHOLD)
{
digitalWrite(5, HIGH);
delay (300);
counter = 100; // This exits the for loop.
}
Serial.print("Volts = ");
Serial.println(volts);
delay(1);
}

delay(25);
digitalWrite(5, LOW);
}

Jude,

Outstanding!

I used your sketch and it was very helpful. Along the way I also learned how to create columns in the print monitor and do carriage returns with serial.println.

I have added this print code to your sketch so that I can watch the original analog reading vs the calculated voltage and the counter ticking off the cycles. Here is the sketch:


//I have adjusted an original sketch by Jude from LB Forum
//to display not only voltage, but the original sensor and counter values

void setup() {
pinMode (A0, INPUT); // place power + dimmer on A0 for testing the code
pinMode (5, OUTPUT); // place an led on d5
Serial.begin(9600);
}

void loop() {
float THRESHOLD = 2.0; // in volts. You might want this lower for your magnetometer
int sensorValue;
float volts;
for (int counter=0;counter<100;counter++){
sensorValue = analogRead(A0);
volts = (sensorValue*5.0)/1024.0;
if (volts >=THRESHOLD)
{
digitalWrite(5, HIGH);
delay (300);
counter = 100; // This exits the for loop.
}

Serial.print(“Sensor = “); //I wish to see actual sensor value, too
Serial.print(sensorValue);
Serial.print(”\t”); //create a column
Serial.print(“Volts = “);
Serial.print(volts);//I wish to see the actual voltage
Serial.print(”\t”); //create a column
Serial.print(“Counter =”);
Serial.println(counter); //I wish to see the actual counter value
//and, I also used println to create a carriage
//return (new line) in the print monitor
//at the end of each loop.

delay(25);

}
digitalWrite(5, LOW);
}

I have noticed a few things.

  1. This sketch does a great job of measuring the signal from the slide pot that I’m using.
  2. This sketch gives a great calculated voltage.
  3. I want this sketch to sketch to count +1 for only trip through the loop where the voltage exceeds 2.0, but it is counting every loop regardless.
  4. I want this sketch to count to 100 (basically count how many loops where the voltage has exceeded 2.0v up to 100.
  5. This sketch activates the LED every time the sensor voltage exceeds 2.0v. But, I’d like to see this sketch activate the LED only every 100 times that that the voltage exceed 2.0v.

I will continue to work on this sketch as best as I am able to get it to achieve my goals.
Feel free to chime in at any time. Your help is invaluable.

Another observation:
6) When the slide pot is raised to 2.0v and above, the serial monitor totally slows down and only prints data only once every 100 loops. The LED remains “on” during this time.
When the slide pot is then lowered below 2.0v, the LED turns “off” and the serial monitor then displays all of the data every loop (25ms intervals).

Jude and Manitou,

I have fused elements of your sketches with mine to make a near complete sketch for my purposes. This FrankenSketch senses an input, currently a slide pot, and when the slide pot reaches 2.0 v, then the LED and servo are simultaneously activated. Both stay activated for one back and forth sweep of the servo. Wow, that’s cool.

Yet to be successfully accomplished is the use of a counter variable that counts the # of times that the slide pot hits a predefined potential (in this case 2.0v) and then THAT variable is used to activate the LED and Servo after a predefined number of counts (threshold excesses) have been achieved.

I’ll keep chugging away, but I smell success approaching! Thanks for all the support and time you two have put in with me on this.

//Manitou on the LB Forum helped me greatly on
//The Servo (output) parts of the sketch. He taught me the
//about the noise generated signals that are created in the conversion
//of analog to digital and digital to analog.
//he showed me that the LB Servo requires anaolg input, not PWM.
//he showed me that to use arduino to drive the servo
//that the servo must be disconnected from its LB module
//hence, disconnected from its MCU. And, that in order to
//use the LB Servo with Arduino that it must be connected instead
//to the LB Proto Module.

#include <Servo.h> //I begin this sketch by calling up the servo library

int servoPin = 1;//Servo to be connected to the non-PWM output pin on LB Arduino

Servo myservo;//I create a variable for the Servo

int angle = 0; // servo position in degrees
//==========================================================

//I have adjusted an original sketch by Jude from LB Forum who is helping
//me to create the input or sensing loop.
//My serialPrint adjustments allow me to display not only voltage,
//but the original sensor (magnetotmeter) and counter values

void setup() {
myservo.attach(servoPin); //telling the arduino to be aware of the servo

pinMode (A0, INPUT); // place power + dimmer on A0 for testing the code
//in lieu of the magnetometer which will also be on
//A0, but with power attached to d0 as the
//magnetometer is a possive sensor
pinMode (5, OUTPUT); // place an led on d5 for a visual effect indicating
//that the servo is “on”
Serial.begin(9600);//turn on the comm to the serial monitor
}

void loop() {
float THRESHOLD = 2.0; // in volts. You might want this lower for your magnetometer
int sensorValue;
float volts;
for (int counter=0;counter<100;counter++){
sensorValue = analogRead(A0);
volts = (sensorValue*5.0)/1024.0;
if (volts >=THRESHOLD)
{
digitalWrite(5, HIGH);//led “on” when threshold exceeded

delay (300);
counter = 100; // This exits the for loop for the activated LED.
}
if (volts >= THRESHOLD)//this is the servo sweep loop, activated by
//the counter reaching 100 (ideally, but so far
//it is activated automatically by the voltage threshold
//instead of a counter)
{
// scan from 15 to 170 degrees
for(angle = 15; angle < 170; angle++)
{
myservo.write(angle);
delay(30);
}

// now scan back from 170 to 15 degrees
for(angle = 170; angle > 15; angle–)
{
myservo.write(angle);
delay(30);
}
}

Serial.print(“Sensor = “); //I wish to see actual sensor value, too
Serial.print(sensorValue);
Serial.print(”\t”); //create a column
Serial.print(“Volts = “);
Serial.print(volts);//I wish to see the actual voltage
Serial.print(”\t”); //create a column
Serial.print(“Counter =”);
Serial.println(counter); //I wish to see the actual counter value
//and, I also used println to create a carriage
//return (new line) in the print monitor
//at the end of each loop.

delay(25);

}

digitalWrite(5, LOW);//this turns off the LED after the servo sweep loop has ended
}

Glad to be of help. Parse through this and continue FrankenSketch - ing …

void setup() {
pinMode (A0, INPUT); // place power + dimmer on A0 for testing the code
pinMode (5, OUTPUT); // place an led on d5

Serial.begin(9600);
}

void loop() {
int counter = 0;
float THRESHOLD = 2.0; // in volts. You might want this lower for your magnetometer
int sensorValue;
float volts;

while (counter <= 99) // In C++, we count from 0. So if you want 100 data points, they will be from 0 through 99.
{
sensorValue = analogRead(A0);
volts = (sensorValue*5.0)/1024.0;
if (volts >=THRESHOLD)
{
Serial.print(“Sensor = “); //I wish to see actual sensor value, too
Serial.print(sensorValue);
Serial.print(”\t”); //create a column
Serial.print(“Volts = “);
Serial.print(volts);//I wish to see the actual voltage
Serial.print(”\t”); //create a column
Serial.print(“Counter =”);
Serial.println(counter); //I wish to see the actual counter value
counter++;
delay(10); //Slows down the data stream somewhat.
}
}
digitalWrite(5, HIGH); // This only turns on the 100th time the sensorValue exceeds THRESHOLD
delay (300);
digitalWrite(5, LOW);
delay (100);
counter = 0;

}

Thanks Jude,

While I’m parsing and integrating, I have a question.
I have immediately noticed that a difference, perhaps the key difference between your original sketch and your updated sketch is that you have changed the “for” loop into a “while” loop.

This gets to the heart of this topic’s title, and reflects my near complete ignorance of what the various loop types are, how they work, and when to apply them. I find the Arduino Reference Library a bit cryptic for my level but, more importantly, it does not provide near enough examples to help me flesh out these issues.

If you have time, could your please explain to me why the substitution, why does it work?

Meanwhile, I’ll get back to work.

It is confusing! While statements are typically used when there is a condition to be met, yours being that you wanted to know when A0 met THRESHOLD 100 times. For loops are typically used for a known number of iterations.

However, with a few logical statements, you can code them to do effectively the same thing.

Here I would like to show you an example of a for and a while that are doing the same thing. The while I’m showing you here is pragmatically incorrect, but logically correct. Hook up a button to A0.

void setup(){
pinMode (A0, INPUT);
Serial.begin(9600);
}
void loop(){
for (int i=0;i<99;i++)
{Serial.print(“i = “);
Serial.println(i);
if (digitalRead(A0))
{
Serial.println(” A0 IS HIGH. LET’S EXIT FOR LOOP”);
i = 100;
}
delay(50);
}
delay(250);
int j = 0;
while (j<99)
{Serial.print(“j = “);
Serial.println(j);
if (digitalRead(A0))
{
Serial.println(” A0 IS HIGH. LET’S EXIT WHILE”);
j = 100;
}
delay(50);
j++;
}
delay(250);
}

Thanks Jude.

At first it didn’t work well because I had the power connected to d0 still. But after connecting it WITH the pushbutton on a0, it all made sense.

I see that the two loops work similarly.

The first loop, the “for” loop counts to i=98 unless the button is pressed. If the button is pressed, the program exits the “for” loop and enters the “while” loop and counts to j=98 unless the button is pressed again. In which case it exits “while” and reenters the “for” loop.
Repeat.

Another question. Is there any way to continue accessing the sensor while the program is trapped in the servo loop?

@astronomique Yes, it is possible if you stick another analogRead in there and maybe print that info to the serial monitor. However, I think it would help if you were to first draw a logical diagram for what you want. Google “flowchart for coding”, and try sketching your ideas with shapes and good old paper and pencil. :slight_smile:

@astronomique I want you to know that I submitted a module to Bitlab this week (you might see it next week after littleBits reviews it), which will help remove the coding required to perform these functions we are discussing. I think the idea of THRESHOLD and COUNTER are useful for all of us. Now today I see that they have a “threshold” module coming soon… http://littlebits.cc/bits/threshold

Yum!

Quick thing for arduino:
multiline comments, i noticed you have lots of comments which is good, but theres an easier way!

EX.

/* Owen

  • Intensive Robotics
  • 11/3/16
    */