I'm a beginner and I am starting a project where I am building an automated plant watering system.
I have written most of the code and designed the circuit. All in all its pretty simple. There are some soil moisture sensors which return an integer like a potentiometer. I simply set the threshold value I want. I am now thinking about creating a graphical control and monitoring system using Processing. I want to be able to change the desired threshold for watering on each sensor individually.
void openValves() { //Opens the valves if they are not already open
for (int i = 0, i < sensorArraySize, i++)
{
if (sensorValue[i] <= setValue[i] && valveState[i] != "OPEN") {
digitalWrite(valvePin[i], HIGH);
valveState[i] = "OPEN";
}
}
}
The code above is an example of the valve opening function. The valve pin goes to a transistor which turns on current to open a solenoid valve. sensorValue[] is an array which stores the last read value from one of any arbitrary number of sensors. For the value read from any sensor, there is a corresponding set value which is the decided threshold for whether or not the valve opens to allow water to flow. I want to be able to set the various values in the setValues[] array from a running processing sketch.
I need a way to identify and sort bytes coming in from Processing. The following process is what I imagine:
A string is sent to the arduino such as "setValue1"
The arduino looks at the string, if it says "setValue1" then look to the next available byte which will be an integer i and then make setValue[0] = i.
Theres a few things I do not understand about the serial buffer. If processing runs a line like port.write("x");, is that one byte? Then if it runs another similar line, is that the second line the second byte? Is the order preserved? If so, then can I simply do:
Using this I would simply make the processing sketch send the identifying string, followed by the new set value for that index. Would this work?
Any other suggestions on how I can do it which would be more... eloquent? It seems like a crude way to do it, because if I had hundreds of attributes which I could be changing and I wanted to check the first byte to categorize the second I would have to write hundreds of if statements.
Have a look at the examples in serial input basics, especially the 3rd example and the parse example.
The simplest solution would be to send all the values every time and in the same order. That way the Arduino program know the first number is for valve1, the second for valve2 etc.
I see, thanks for the help. I think I get it now. I can just read strings into an array of strings, where the data always comes in a specific order such as "metainformation1, metainformation2, information". So I have made an array of size 2, because I will receive "metainformation, information" and used a for loop to read the two bytes into the array as characters.
Then, because I know the 0 position in the array contains the info about where the number goes, I check with another for loop to see which position in the setValues[] array the received string is referring to. Then, convert inChar[1] (which contains the new set value) to an integer with .toInt and make it the new setValue for the corresponding index. Lastly, wipe the string array (is this not useful? It doesn't seem useful, just a last minute idea).
void receiveNewSetValue() {
//Identifies setValue array position and stores next byte as corresponding set value
char inChar[2];
if (Serial.available > 0) {
for (int i = 0, i < 2, i++)
{
inChar[i] = Serial.read();
}
for (int i = 0, i < sensorArraySize, i++) {
if (inChar[0] = "setValue" + i) {
setValue[i] = inChar[1].toInt();
}
}
inChar[] = {null, null};
}
}
Ah... I see where I am screwing up. I am telling it to run a for loop which reads a byte, and then reads another byte. Yes. I read the examples. Bare with me, I've been doing this for only a few days.
So what I understand I am missing is that I need a function which fills up an array and waits for a character that says the complete set of bytes for that array has been sent. Then, send that array to another function which does something with it.
Currently I am just basically telling it to read a byte if it's available. Because the loop happens so much faster than bytes can be sent, even if I send two consecutive bytes, the for loop will run multiple times before the second byte comes in.
^This in particular is very helpful to me. I can tell that switch statements are very useful.
I used that example and then wrote my own processData function. I am having a little trouble with it.
Here's what I'm trying to do:
Take in the array populated by the processIncomingByte() function
Take the current index of a for loop, cast it as a char, add that char to "setValue" and check to see if it equals the first byte in the recently received byte array (inputArray[0]). I would be sending data in the form of two bytes, first byte is "setValueX", so I am checking to see which value of X I have.
Then, the next byte in the array (inputArray[1]) will be the value I want to set in the 'X' position of the setValue[X] array. I am attempting to cast that char to an int and assign it to setValue[X].
const int MAX_INPUT = 2;
const int sensorArraySize = 6;
void processData(char inputArray)
{
for (int i = 0; i < sensorArraySize; i++)
{
char indexChar = char(i);
if (inputArray[0] == "setValue" + indexChar)
{
setValue[i] = int(inputArray[1]);
}
//Else instructions may go here in the future
//end if statement
} //end for loop
} //end processData
void processIncomingByte (const byte inByte)
{
static char input_line[MAX_INPUT];
static unsigned int input_pos = 0;
switch (inByte)
{
case '\n': // end of text
input_line[input_pos] = 0; // terminating null byte
// terminator reached! process input_line here ...
processData(input_line[]);
// reset buffer for next time
input_pos = 0;
break;
case '\r': // discard carriage return
break;
default:
// keep adding if not full ... allow for terminating null byte
if (input_pos < (MAX_INPUT - 1))
input_line[input_pos] = inByte;
input_pos++;
break;
} // end of switch
} // end of processIncomingByte
However, I get the following errors:
Arduino: 1.6.4 (Windows 7), Board: "Arduino Uno"
SmartGarden1.0.ino: In function 'void processData(char)':
SmartGarden1.0:91: error: invalid types 'char[int]' for array subscript
SmartGarden1.0:93: error: invalid types 'char[int]' for array subscript
SmartGarden1.0.ino: In function 'void processIncomingByte(byte)':
SmartGarden1.0:113: error: expected primary-expression before ']' token
invalid types 'char[int]' for array subscript
This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
It seems that the issue is that I cannot use char(i) to turn the value of 'i' into a char. Is this the issue? If so why can't I do this? The reference on char() says that char(x) takes any value of x and converts it into a char.
void openValves() { //Opens the valves if they are not already open
for (int i = 0, i < sensorArraySize, i++)
{
if (sensorValue <= setValue && valveState != "OPEN") { _ digitalWrite(valvePin*, HIGH); valveState = "OPEN"; } }[/quote]* This code is unlikely to actually work. If your valveState variable represents a valve which is either on, or off, then use a bool variable which is true or false, or some integer type which is 1 or 0, to represent that. Using a string is both cumbersome and inefficient, and more seriously, won't actually work !_
That's not an array. My example had a pointer to char, which effectively is an array:
// here to process incoming serial data after a terminator received
void process_data (const char * data)
{
// for now just display it
// (but you could compare it to some value, convert to an integer, etc.)
Serial.println (data);
} // end of process_data
I roughly know what a pointer is, but don't know much about how to deal with them. Do you have a basic example of them? Can I call a position in (char * data) like a normal array? For example: char X = data[1];
michinyon:
This code is unlikely to actually work. If your valveState variable represents a valve which is either on, or off, then use a bool variable which is true or false, or some integer type which is 1 or 0, to represent that. Using a string is both cumbersome and inefficient, and more seriously, won't actually work !
void openValves() { //Opens the valves if they are not already open
for (int i = 0; i < sensorArraySize; i++)
{
if (sensorValue[i] <= setValue[i] && valveOpen[i] == false) {
digitalWrite(valvePin[i], HIGH);
valveOpen[i] = true;
}
}
}
void closeValves() { //Reads sensors and closes valves if sensor reading is high enough
for (int i = 0; i < sensorArraySize; i++)
{
if (sensorValue[i] >= setValue[i] + offset && valveOpen[i] == true) {
digitalWrite(valvePin[i], LOW);
valveOpen[i] = false;
}
}
}
How's that? valveOpen is an array of boolean values which all start off as false. Thanks for the tip.