control structures in relation to keyboard.print query

my current project involves using the keyboard.press function to trigger sounds from my computer keyboard using a keyboard sample mapper taking values from a range finder. Here is my code.

int configPin = 13;                 //Set the sonar Calibration Pin
void setup() {                    //begin of program
  Serial.begin(9600);             //serial baud rate 9600
  pinMode(configPin,OUTPUT);


}


void loop(){                     //looping of program
  digitalWrite(configPin,HIGH);    //raise the reset pin high
  delay(120);                      //start of calibration ring
  float sensorvalue = analogRead(0); //get analog sensor value from pin 0
  float inchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches
  Serial.println("Sensed a-d value:"); //print a-d text
  Serial.println(sensorvalue);       //print a-d value
  Serial.println("Inch value=");      //print inch text
  Serial.println(inchvalue);        //print inch value
  delay(100);                      //optional delay 1 second
  digitalWrite(configPin,LOW);      //turn off Calibration ring and sensor
  delay(100);                      //delay 1 second


  if (inchvalue >9.00 && inchvalue <=20.00) {

    Keyboard.press ('g');
    Serial.println (inchvalue); 


  }

}

what I’m finding though is that it will print g only once: the first time I break the beam (sorry to be scientifically inaccurate) in the specified range. I’ve experimented with .press and release and delays but what I’m hoping is that there is a solution where by if the value returned is in the specified range it will print g once , then not again until the value moves outside of that range and returns to it. I’ve looked at the control structure reference page but being a complete novice wasn’t quite sure what I needed. I also don’t understand why i’m not getting a continuous string of g’s which i thought would be my problem.

help would be great

thanks

sam

That code looks to me as if it will attempt to repeat the keypress very frequently while the distance remains in that range. Since it doesn't, it may be that the sketch is failing in some way at the first keypress.

I suggest you tackle this two ways:

Replace the code to send the keypress with code that just prints a trace message, and update your sketch so that it does this when you want it to. Probably, you'll want to incorporate some edge detection logic so that it only executes that code when the distance enters that range.

Secondly, write some code that just send the keys you want (e.g. in a fixed sequence or at a fixed rate) and ensure that this mechanism works correctly before you try to use it in your complete sketch.

I'm sorry I made a grievous error , I thought I had used .print but I had used .press which is why it would only print g once , because the button was virtually depressed. with that revision my code now does print a long sting of g's when within specified range which is still not the desired effect.

I also took heed of your second comment just to be on the safe side.

void setup ()
{
}

void loop (){
Keyboard.print ("d");
delay (300)
}

which works fine. I don't understand what a trace message is though ?

thank you

sam

I suppose to be specific what i'm asking is is there a way to , I apologise for really bad terminology from here , to have the result of the condition occur only once after the condition has been met and not again until the condition has ceased to have been met and has been met a second time , I thought there would be some sub-branch in the if statement reference that would allow for this but if it's there i haven't seen it or very likely have seen it and failed to understand it.

basically the guy iIm doing this for wants the functionality where by the sample starts playing when the beam is broken but can be restarted by the beam being unbroken and broken again in the same range which is why I'm asking about the functionally I'm asking about (thats just how the key mapper were using works). sorry just felt the need to explain myself there.

I’ve realised my problem it’s

void loop(){                     //looping of program
  digitalWrite(configPin,HIGH);    //raise the reset pin high
  delay(120);                      //start of calibration ring
  float sensorvalue = analogRead(0); //get analog sensor value from pin 0
  float inchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches
  Serial.println("Sensed a-d value:"); //print a-d text
  Serial.println(sensorvalue);       //print a-d value
  Serial.println("Inch value=");      //print inch text
  Serial.println(inchvalue);        //print inch value
  delay(100);                      //optional delay 1 second
  digitalWrite(configPin,LOW);      //turn off Calibration ring and sensor
  delay(100);

So the sensor is reseting every 100 milliseconds to take a new value (digital write config pin high , digital write config pin low). I suppose I need to find//write some code for the range finder which is contained in void setup ?

to have the result of the condition occur only once after the condition has been met and not again until the condition has ceased to have been met and has been met a second time ,

Read the value Compare it to the previous value If they are different, and the new value is what you are waiting for, take the required action and save current value as the previous value, otherwise go back and read the value again.

I’m sorry I don’t quite know how to go about doing that , could you point me in the right direction? Also would that stop the desired action (keyboard.press “g”) being executed repeatedly while the conidiction for it’s execution was being met ?

Some pseudo code for you to turn into real code

declare variables including oldValue and newValue
set up pin modes etc

start of loop
  read the value from input
  if oldValue not equal to newValue          //value has changed
    if newValue equals value to be acted on  //is it what we are looking for ?
      perform action(s)
      set oldValue equal to newValue         //save the value so we can spot when it changes
    end of if
  end of if
end of loop

If the condition is met the action(s) will be performed but they won't be performed again if the value remains unchanged. In fact, they will not be performed until the value has changed and then changed back to the value that you are looking for.

ah thank you so much heli bob I'll get writing that code tonight

thanks very much

sam

I had a go but I can’t qiute get my head around the logic of it or what language I should be using. the way I interpreted it old value and new value are ranges of inchvalue but I can’t shake the feeling that thats wrong? Also I don’t really know how I would code

eqauls value to be acted upon

or

set new value to old value

.

heres what I wrote

int configPin = 13;                 //Set the sonar Calibration Pin
int oldval;
int inchvalue;
int newvalue;

void setup() {                    //begin of program
Serial.begin(9600);             //serial baud rate 9600
pinMode(configPin,OUTPUT);
pinMode(led, OUTPUT);
oldval = (inchvalue >0.00 && inchvalue <=10.00);
newvalue = (inchvalue >11.00 && inchvalue <=20.00);
}


void loop(){                     //looping of program
digitalWrite(configPin,HIGH);    //raise the reset pin high
delay(120);                      //start of calibration ring
float sensorvalue = analogRead(0); //get analog sensor value from pin 0
float inchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches
Serial.println("Sensed a-d value:"); //print a-d text
Serial.println(sensorvalue);       //print a-d value
Serial.println("Inch value=");      //print inch text
Serial.println(inchvalue);        //print inch value
delay(100);                      //optional delay 1 second
digitalWrite(configPin,LOW);      //turn off Calibration ring and sensor
delay(100);                      //delay 1 second
}

if (oldval != newval)
if

I dont’t really know hoe to proceed though or if what I’ve written so far is even correct. Thanks for the help though sorry if i’m not getting it?.

Have a look at this

void loop()
{
  float sensorvalue = analogRead(0); //get analog sensor value from pin 0
  float newInchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches

  if (oldInchvalue != newInchvalue) //the value has changed
  {
    if (newInchvalue > 9.00 && newInchvalue <= 20.00) //and it is in range
    {
      Keyboard.press ('g');
      oldInchvalue = newInchvalue;  //save value for next time
    }
  }
}

To make it clearer I have only left in the code that show the logic of what I suggested. You will need to put back any code that controls the sensor such as the control lines.

A couple of points. You may find that the readings are too sensitive as they don’t have to change much to be regard as having changed. Consider using ints for the inchValue variables so that the distance has to vary by a whole inch before a change is detected. Secondly, your delay(100); lines only delay by 0.1 of a second not a whole second. Using delay() is almost certainly not the best way to do what you want but I suggest that you solve the distance reading logic problem first.

sorry I still don’t get it. I tried

int configPin = 13;                 //Set the sonar Calibration Pin
int inchvalue;
int newinchvalue;
int oldinchvalue;


void setup() {                    //begin of program
Serial.begin(9600);             //serial baud rate 9600
pinMode(configPin,OUTPUT);

oldinchvalue = (inchvalue >0.00 && inchvalue <=10.00);
newinchvalue = (inchvalue >11.00 && inchvalue <=20.00);
}


void loop(){                     //looping of program
digitalWrite(configPin,HIGH);    //raise the reset pin high
delay(120);                      //start of calibration ring
 //get analog sensor value from pin 0

Serial.println("Sensed a-d value:"); //print a-d text

Serial.println("Inch value=");      //print inch text
Serial.println(inchvalue);        //print inch value
delay(100);                      //optional delay 1 second
digitalWrite(configPin,LOW);      //turn off Calibration ring and sensor
delay(100);                      //delay 1 second



 float sensorvalue = analogRead(0); //get analog sensor value from pin 0
  float newinchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches
  
  if (oldinchvalue != newinchvalue) //the value has changed
  {
    if (newinchvalue > 11.00 && newinchvalue <= 20.00) //and it is in range
    {
      Keyboard.print ('g');
      oldinchvalue = newinchvalue;
     //save value for next time
    }
  }
}

And still got a continuos string of g’s. could it be that the readings are too sensitive? Also was I right to think oldinchvalue and newinchvalue refereed to those ranges I declared in setup ?. befor that I also tried this code because I though that float newInchvalue = (254.0/1024.0) *2.0* sensorvalue; . would mean a redefinition error as I had named newinchvalue as a range earlier but as I found in the above that was not the case.

int configPin = 13;                 //Set the sonar Calibration Pin


void setup() {                    //begin of program
Serial.begin(9600);             //serial baud rate 9600
pinMode(configPin,OUTPUT);



}


void loop(){                     //looping of program
digitalWrite(configPin,HIGH);    //raise the reset pin high
delay(120);                      //start of calibration ring
delay(100);                      //optional delay 1 second
digitalWrite(configPin,LOW);      //turn off Calibration ring and sensor
delay(100);                      //delay 1 second



  float sensorvalue = analogRead(0); //get analog sensor value from pin 0
  float newInchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches
  
  if (oldInchvalue != newInchvalue) //the value has changed
  {
    if (newInchvalue > 9.00 && newInchvalue <= 20.00) //and it is in range
    {
      Keyboard.print ('g');
      oldInchvalue = newInchvalue;  //save value for next time
    }
  }
}

here I could not figure out what oldinchvalue was referring to. I tried substituting in for sensor value and adding the line

float oldinchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches

but to no avail. think I just taking stabs in the dark though sorry.

It looks like you are nearly there.
Ditch these lines. They are doing nothing for you.

  oldinchvalue = (inchvalue >0.00 && inchvalue <=10.00);
  newinchvalue = (inchvalue >11.00 && inchvalue <=20.00);

and this line  Serial.println(inchvalue);        //print inch valuebecause inchvalue never changes. By all means print newInchvalue after you have read the sensor, but see below.

Based on your original code it looks like you now have got the analogRead() in the wrong place. It was originally after you put the config pin high and before you put the config pin low. In your latest code it is before both. I am not familiar with the sensor that you are using but your current program does not match your original. It may be that you are not getting a proper reading from the sensor now.

oldInchvalue holds the value of the previous distance reading. newInchvalue holds the new reading. This is so they can be compared. Despite the names they actullly have nothing to do with the inchvalue variable in your program. They could just as well be called bill and ben but their meaning would not be so obvious.

Suggestions
Put the analog.Read() in the same place as the original program if it worked there
Print the value of newInchvalue just after you read the sensor and make sure that it gives you sensible values.

ok I feel like I’m coming closer. heres my code now.

int configPin = 13;                 //Set the sonar Calibration Pin
int inchvalue;
int newinchvalue;
int oldinchvalue;


void setup() {                    //begin of program
Serial.begin(9600);             //serial baud rate 9600
pinMode(configPin,OUTPUT);

}


void loop(){                     //looping of program
digitalWrite(configPin,HIGH);    //raise the reset pin high
delay(120);                      //start of calibration ring
 float sensorvalue = analogRead(0);//get analog sensor value from pin 0
Serial.println (newinchvalue);
                    //optional delay 1 second
digitalWrite(configPin,LOW);      //turn off Calibration ring and sensor
delay(100);                      //delay 1 second




  float newinchvalue = (254.0/1024.0) *2.0* sensorvalue; //convert to inches
  
  if (oldinchvalue != newinchvalue) //the value has changed
  {
    if (newinchvalue > 6.00 && newinchvalue <= 30.00) //and it is in range
    {
      Keyboard.print ('g');
      oldinchvalue = newinchvalue;
     //save value for next time
    }
  }
}

after checking my serial monitor I can confirm it is just printing 0s. I think that is a superficial problem though because it will still print g only when I break the beam in the specified range , so the sensor is working fine Ive just told it to print the wrong thing/in the wrong place. I do still get the continuos string of g’s though and thats with the range finder inside a box (so a supposedly unchanging reading)

any thoughts ?

thanks for helping btw

You have 2 different variables named newinchvalue

You create a new float variable with that name each time through loop() and you already have a global in variable of the same name. When the program does the comparison  if (oldinchvalue != newinchvalue) which one is it using ? It will use the one declared locally which means that you are comparing a float with an int (oldinchvalue) then later on you copy the float to an int.

Remove the declaration of the float newinchvalue so that the global int is used and see what happens.

ok I removed that line so my codes now

int configPin = 13;                 //Set the sonar Calibration Pin
int inchvalue;
int newinchvalue;
int oldinchvalue;


void setup() {                    //begin of program
Serial.begin(9600);             //serial baud rate 9600
pinMode(configPin,OUTPUT);

}


void loop(){                     //looping of program
digitalWrite(configPin,HIGH);    //raise the reset pin high
delay(120);                      //start of calibration ring
 float sensorvalue = analogRead(0);//get analog sensor value from pin 0
Serial.println (newinchvalue);
                    //optional delay 1 second
digitalWrite(configPin,LOW);      //turn off Calibration ring and sensor
delay(100);                      //delay 1 second




  
  if (oldinchvalue != newinchvalue) //the value has changed
  {
    if (newinchvalue > 6 && newinchvalue <= 30) //and it is in range
    {
      Keyboard.print ('g');
      oldinchvalue = newinchvalue;
     //save value for next time
    }
  }
}

it seems like now though that theres no line converting the sensor value into an inch value ? the result is g does not print at all. I was looking at some code for reed switches and I saw that it used something called int counter to count the amount of times the switched had been opened. could I maybe count the number of times g had been printed and then tell it to stop after 1? just a thought.

My fault for expressing myself badly. What I meant to say was remove the word float from that line so that the program uses the previously declared global newinchvalue rather than the local one.

ah thank you so much I think it's working , very sensitive but it is working!. this has been a really big help I'm doing this for an arts festival and I don't know what i would have done without this forum.

you mentioned ealirler in the thread a way of using an ints to make it more sensitive ? is there a way of declaring larger units like

newinchvalue = (80.0/1024.0) *2.0*

or something else?

thanks again.

sam

The reason that it is sensitive is because the distance only has to change by one inch for the old and new distances to be different. Using int values helps with this but does not solve the problem. The best way to solve this would be to subtract the smaller of the old/new values from the larger then , if the result is greater than some value the distance has changed enough to be regarded as significant. This is easy to do but we don't know which one is larger. So, try this if (abs(oldinchvalue - newinchbalue) > 2)instead of the direct comparison. The abs() function gives the numeric result of the subtraction as a positive number no matter whether the result is positive or negative. Change the 2 to suit your requirements of course.

thanks worked a treat. I do have more questions though , the one problem I have now is that if the same value is given ( a value that after the abs creates a positive integer larger than 2) g will not print again ? I know that is logically what should happen I was just wondering if there was a way round it. I tried taking out

 if (newinchvalue > .00 && newinchvalue <= 30.00) //and it is in range

so that now will g will simply print whenever there is a value change , which is fine expect that it will obviously print twice. I thought of taking away the abs but then i’d just get lower and lower negative integers?

So what i’m asking is : is there a method by which g will print once when the beam is broken the first time (in any range) then not when the new value is given after the hand has been withdrawn then again when the beam is broken again ?

cheers

sam

p.s sorry for not getting back to you sooner I had a really mild tonsillitus infection.