Project 6: Light Theremin Error in Arduino Projects Book

Maybe this has already been covered but I can't find it. I'm new to programming and electronics but have always wanted to learn, so I'm working through the examples. In Project 6: Light Theremin on page 75, the book states that the variables should be set at

2. int sensorLow = 1023;
3. int sensorHigh = 0;

When I use these values the system does not calibrate correctly, and I get a weird result. It seems to me the initial variable settings should be:

2. int sensorLow = 0;
3. int sensorHigh = 1023;

I can monitor the High and Low values by introducing a Serial.begin(115200); and then printing the values. I've used the higher baud rate because the higher baud rate is undetectable to the human ear so it still sounds like a theremin. Here is what my code looks like now and it seems to work. With adjustments to the code the Low and High outputs in the serial monitor are 0 to 1023 which is what I would expect. When you use the code in the book the Low and High outputs are ~750 to 753 which is a pretty narrow range. Any suggestions?

//Light Theremin
int sensorValue;
int sensorLow = 0;
int sensorHigh = 1023;
const int ledPin = 13;

void setup() {
 
 Serial.begin(115200);
 pinMode(ledPin, OUTPUT);
 digitalWrite(ledPin, HIGH);
 
 while (millis() < 5000){
   sensorValue = analogRead(A0);
   if (sensorValue > sensorHigh){
     sensorHigh = sensorValue;
   }
   if (sensorValue < sensorLow){
     sensorLow = sensorValue;
   }
 }
 
 digitalWrite(ledPin, LOW);
}

void loop() {
 sensorValue = analogRead(A0);
 int pitch = map(sensorValue, sensorLow, sensorHigh, 1, 4000);
 tone(9, pitch, 20);
 delay(10);
 Serial.println("Sensor Values");
 Serial.print("SensorLow = ");
 Serial.print(sensorLow);
 Serial.print(", SensorHigh = ");
 Serial.print(sensorHigh);
 Serial.print(", Sensor Value= ");
 Serial.println(sensorValue);
}

So you first tried using the code exactly as it is in the book? When I used it, I had no problems at all.

The book worked fine for me as well. Did you properly calibrate it after turning it on by moving your hand over the sensor as per the book?

Definitely an error in the book.

These settings do not work. The math is backwards.

int sensorLow = 1023;
int sensorHigh = 0;

They should be as scoleman wrote:

int sensorLow = 0;
int sensorHigh = 1023;

You could make them work by typing this line:

int pitch = map(sensorValue, sensorLow,sensorHigh, 50, 4000);

like this:

int pitch = map(sensorValue, sensorHigh, sensorLow, 50, 4000);

(flipping the sensorHigh and sensorLow range definitions).

Hi all,

I just wanted to leave a reply to anyone who found this thread from a search engine to let you know there is definitely no mistake in the code in the book!

While the code:

int sensorLow = 1023;
int sensorHigh = 0;

May seen counter-intuitive at first, it is in fact, correct.

We are purposely setting the "wrong" high and low values so that our calibration loop in setup can assign the proper range for sensitivity.

Let's walk through the calibration code loop for setting the highest possible sensor value (for when there is the most light on the sensor)

sensorValue = analogRead(A0);
if (sensorValue > sensorHigh) {
     sensorHigh = sensorValue;
    }

The first line here is just getting the sensorValue and putting it into the variable "sensorValue"

We then say, is this value greater than what we set as "sensorHigh" (which the book says should be 0) - so the answer to this is yes and on the next line:

The new "max light" setting for the sensor becomes equal to whatever the sensor was reading.

This is repeated and anytime the sensor detects more light, sensorHigh is updated to say "for the purposes of what we are measuring, this is 100% of light", this serving the function of calibration. The same applies, vice-versa to the sensorLow variable.

Now for this that say the sensorHigh should be set to 1023 at the start of the program, consider what happens when you are saying:

if (sensorvalue > sensorHigh)

You're essentially saying:

if (sensorvalue > 1023)

Now 1023 is the maximum possible value for the sensor so it is NEVER going to be > 1023, which means the conditions in both loops (is it greater than 1023 and is it less than 0) will never be met - so there is absolutely no point in the calibration loop!

If you are having problems with the project, I would recommend using Serial.print to make sure that your sensor is working correctly and everything is wired okay.

This code will print out your live sensor values in the serial terminal for you:

int sensorValue;
int sensorLow = 1023;
int sensorHigh = 0;

const int ledPin = 13;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  while (millis() < 5000) {

    sensorValue = analogRead(A0);
    if (sensorValue > sensorHigh) {
      sensorHigh = sensorValue;
    }

    if (sensorValue < sensorLow) {
      sensorLow = sensorValue;
    }
    Serial.print("Sensor Value = ");
    Serial.println(sensorValue);
    delay(5);
  }

  digitalWrite(ledPin, LOW);
}

void loop() {
  sensorValue = analogRead(A0);
  Serial.print("Sensor Value = ");
  Serial.println(sensorValue);
  delay(5);

  int pitch = map(sensorValue, sensorLow, sensorHigh, 50, 4000);

  tone(8,pitch,20);

  delay(10);
}

Good luck!

1 Like

I am fairly new to Arduino & this project didn't initially work with my gear, that being a cheap Arduino Starter Kit from Aliexpress plus separate buzzers (passive) also bought from Aliexpress. I work in a state secondary school so have a tight budget.

Anyway, after hunting around & checking the specifics of my buzzer, I discovered I needed to connect one buzzer leg to pin 8 rather than pin 12 as in the Arduino example sketch.

I also had to set up the buzzer in the code as pin 8 using "int buzzer = 8".

Here's my code:

/*
  Arduino Starter Kit example
 Project 6  - Light Theremin

 This sketch is written to accompany Project 6 in the
 Arduino Starter Kit

 Parts required:
 photoresistor
 10 kilohm resistor
 piezo

 Created 13 September 2012
 by Scott Fitzgerald

 http://www.arduino.cc/starterKit

 This example code is part of the public domain
*/

// variable to hold sensor value
int sensorValue;
// variable to calibrate low value
int sensorLow = 1023;
// variable to calibrate high value
int sensorHigh = 0;
int buzzer = 8 ;// setting controls the digital IO foot buzzer
// LED pin
const int ledPin = 13;

void setup() {
  // Make the LED pin an output and turn it on
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  // calibrate for the first five seconds after program runs
  while (millis() < 5000) {
    // record the maximum sensor value
    sensorValue = analogRead(A0);
    if (sensorValue > sensorHigh) {
      sensorHigh = sensorValue;
    }
    // record the minimum sensor value
    if (sensorValue < sensorLow) {
      sensorLow = sensorValue;
    }
  }
  // turn the LED off, signaling the end of the calibration period
  digitalWrite(ledPin, LOW);
}

void loop() {
  //read the input from A0 and store it in a variable
  sensorValue = analogRead(A0);

  // map the sensor values to a wide range of pitches
  int pitch = map(sensorValue, sensorLow, sensorHigh, 1, 4000);

  // play the tone for 20 ms on pin 8
  tone(8, pitch, 20);

  // wait for a moment
  delay(10);
}

I hope that is useful to someone!

thetafferboy:
We are purposely setting the "wrong" high and low values so that our calibration loop in setup can assign the proper range for sensitivity.

Good luck!

Thanks! The book doesn't explain this. It makes a lot of sense. I originally thought the reason it was reversed was because we are "flipping" the values of the sensor.

1 Like

I want to warp the sound with a Potentiometer, while raising and lowering my hand over Photoresistor.
Do I put the two pins facing the resistor and the jump lead? See pages 72 and 73.
As I do not want to burn the Potentiometer out.

thetafferboy:
Hi all,

I just wanted to leave a reply to anyone who found this thread from a search engine to let you know there is definitely no mistake in the code in the book!

While the code:

int sensorLow = 1023;

int sensorHigh = 0;




May seen counter-intuitive at first, it is in fact, correct.

We are purposely setting the "wrong" high and low values so that our calibration loop in setup can assign the proper range for sensitivity.

Let's walk through the calibration code loop for setting the highest possible sensor value (for when there is the most light on the sensor)



sensorValue = analogRead(A0);
if (sensorValue > sensorHigh) {
    sensorHigh = sensorValue;
    }




The first line here is just getting the sensorValue and putting it into the variable "sensorValue"

We then say, is this value greater than what we set as "sensorHigh" (which the book says should be 0) - so the answer to this is yes and on the next line:

The new "max light" setting for the sensor becomes equal to whatever the sensor was reading.

This is repeated and anytime the sensor detects more light, sensorHigh is updated to say "for the purposes of what we are measuring, this is 100% of light", this serving the function of calibration. The same applies, vice-versa to the sensorLow variable.

Now for this that say the sensorHigh should be set to 1023 at the start of the program, consider what happens when you are saying:



if (sensorvalue > sensorHigh)




You're essentially saying:



if (sensorvalue > 1023)




Now 1023 is the maximum possible value for the sensor so it is NEVER going to be > 1023, which means the conditions in both loops (is it greater than 1023 and is it less than 0) will never be met - so there is absolutely no point in the calibration loop!

If you are having problems with the project, I would recommend using Serial.print to make sure that your sensor is working correctly and everything is wired okay.

This code will print out your live sensor values in the serial terminal for you:



int sensorValue;
int sensorLow = 1023;
int sensorHigh = 0;

const int ledPin = 13;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

while (millis() < 5000) {

sensorValue = analogRead(A0);
    if (sensorValue > sensorHigh) {
      sensorHigh = sensorValue;
    }

if (sensorValue < sensorLow) {
      sensorLow = sensorValue;
    }
    Serial.print("Sensor Value = ");
    Serial.println(sensorValue);
    delay(5);
  }

digitalWrite(ledPin, LOW);
}

void loop() {
  sensorValue = analogRead(A0);
  Serial.print("Sensor Value = ");
  Serial.println(sensorValue);
  delay(5);

int pitch = map(sensorValue, sensorLow, sensorHigh, 50, 4000);

tone(8,pitch,20);

delay(10);
}




Good luck!

Thank youuuuuuuuu!