Intended operation:
A cow enters the race and breaks both sensor 1 and 2, a timer will start to calculate her speed.
As she moves through the race she will the break sensor 3, which stops the timer and calculates what speed she is traveling.
As she continues to move through the race when either Sensor1 or Sensor 2 is unbroken, depending on the speed calculation, relay 1 or relay 2 will open.
The issues I am having as you will see in the video is that when cows are following close behind each other the relay stays open and it will continuously spray. It will then be followed by the relay opening and shutting faster than normal.
I am not sure whats causing this so any help would be much appreciated. Code is below
const int sensor1 = 6;
const int sensor2 = 9;
const int sensor3 = 5;
const int relay1 = 4;
const int relay2 = 7;
int sensorState;
unsigned long previousMillis_1 = 0;
unsigned long previousMillis_2 = 0; // will store last time LED was updated
// constants won't change:
unsigned long sprayinterval = 500;
boolean sensor1WasHigh = false;
boolean sensor2WasHigh = false;
boolean sensor3WasHigh = false;
boolean relay1On = false;
boolean relay2On = false;
boolean timingFlag = false;
unsigned long timerOff = 0;
unsigned long timerOn;
unsigned long cowSpeed;
unsigned long cowTimer;
void setup() {
pinMode(sensor1, INPUT_PULLUP);
pinMode(sensor2, INPUT_PULLUP);
pinMode(sensor3, INPUT_PULLUP);
pinMode(relay1, OUTPUT);
pinMode(relay2, OUTPUT);
Serial.begin(9600);
}
void loop() {
unsigned long currentMillis = millis(); // capture the latest value of millis()
// read the state of the Sensor 1,2 and set a flag if it is HIGH, Start timer to calculate cow speed:
if (digitalRead(sensor1) == HIGH && sensor1WasHigh == false && digitalRead(sensor2) == HIGH && sensor2WasHigh == false) {
timerOn = millis();
sensor1WasHigh = true;
sensor2WasHigh = true;
timingFlag = true;
//Serial.print("timerOn: ");
//Serial.println( timerOn );
}
// read the state of the Sensor 3, stop timer and set a flag if it is HIGH:
if(digitalRead(sensor3) == HIGH && sensor3WasHigh == false && timingFlag == true)
{
timerOff = millis();
timingFlag = false;
sensor3WasHigh = true;
cowTimer = timerOff - timerOn;
//cowSpeed = 300UL / timerOff;
Serial.print("Time: ");
Serial.println( cowTimer );
timerOff = timerOn;
}
//Fast Speed - Fire Relay 2
if(cowTimer < 1000)
{
if (digitalRead(sensor1) == LOW && sensor1WasHigh || digitalRead(sensor2) == LOW && sensor2WasHigh && digitalRead(sensor3)== HIGH && sensor3WasHigh) {
sensor1WasHigh = false;
sensor2WasHigh = false;
sensor3WasHigh = false;
// Sensor event here
digitalWrite(relay2, HIGH);
relay2On = true;
Serial.println( "Fast Spray" );
}
}
else{
//Normal Speed - Fire Relay 1
if (digitalRead(sensor1) == LOW && sensor1WasHigh || digitalRead(sensor2) == LOW && sensor2WasHigh && digitalRead(sensor3)== HIGH && sensor3WasHigh ) {
sensor1WasHigh = false;
sensor2WasHigh = false;
sensor3WasHigh = false;
// Sensor event here
digitalWrite(relay1, HIGH);
relay1On = true;
Serial.println( "Normal Spray" );
}
}
if (currentMillis - previousMillis_2 >= sprayinterval) {
digitalWrite(relay1, LOW);
digitalWrite(relay2, LOW);
relay1On = false;
relay2On = false;
previousMillis_2 = currentMillis;
}
}
Thanks for those suggestions. I will make those changes and see if it improves.
Regarding it not detecting the second cow when they are walking close together. I don't think that is the case, although it could happen, as the relay will only open if either sensor 1 or sensor 2 is rejoined after being broken. In this case it is opening but not closing.
You have some rather complex if/else logic in that code - please do an autoformat first (press - in the IDE) so at least the indentation is correct. It is too hard to follow this way.
I have the feeling that this logic can also be simplified by using a finite state machine rather than a bunch of if/else statements.
As this happens when cows walk too close together, that's obviously where you have to start looking with your debugging. Add more Serial.print() commands to have a better idea on what your code is doing and where/when/how things break down.
Its difficult (at least for me) to hold all that logic in my heat at one time. If this was my project I would have to draw a flow chart.
I suggest you look at Lucidchart. Its very easy and you can get a free limited account (limit is 3 documents and each has a limit of entries). For me its been a good tool. I not only get to see my project in a manner I can comprehend but I've found a number of areas I could simplify my code.
The timing is hard to understand. It looks to me though that previousMillis_2 is used to time how long the chosen spray relay is on. If that is true, I think it needs to be set when spraying starts and from what I can see, it isn't.
Better names would help me at least, to understand what's happening.
Your video isn't accessible either - that would probably bring some more clarity.
Hello
my proposal works with a different setup of sensors. I will not work with the speed of walking cow. My intentions is to measure the length of a cow using a double photoelectric sensor. This will have the follwing logic:
SensorA | Sensor B || comment
----0-------|-----0------- || now cow in range --> do nothing
----1-------|-----0------- || start of cow --> do nothing
----0-------|-----1------- || end of cow --> sprayer on for time x
----1-------|-----1------- || mid af cow --> do some preparation if nessarry
The arrangement, design and layout of the double photoelectric sensor depends on the environmental condition you have.
In my current configuration there are 2 spray nozzles. A standard nozzle for walking cows and a high volume nozzle for fast moving cows to ensure they are still sprayed. The speed calculation is to determine which nozzle they are sprayed with.
Sensor 1 and 2 are position on a vertical line at the same point in the race. I have 2 sensors here to avoid a false spray from a cows head dipping through the sensor as she enters.
Sensor 3 is set 600mm down the race and is used to calculate the speed but also determind the object moving through the race is large.
Once sensor 1 or sensor 2 return low from high and sensor 3 is high. The nozzle will spray. The vertically set sensor 1 and 2 will also reduce the chance of cows moving through the race close together and there being no gap.
I can see after typing this that sensor 3 can replace sensor 2s function to avoid cows dipping their heads.
I would have thought that you could do a reasonable job with a sensor just before the sprayer. When it sees the cow disappear, you're pointing at the tail and it's time to spray.
If necessary, record the time that sensor saw the cow to calculate speed and choose the sprayer as appropriate.
Hello
and many thanks for your reply and system description. You may build a small "cow race" mock up to study 'all' possible system states by using Play Mobil cows. Might be it usefull to provide names for the sensor1, sensor2 and sensor3 referencing their location and/or task?
Cow bodies... What about a vertical line of sensors maybe 8 or 10 or so. Could even be light detectors. You average them all together to give you a wave form that has high blobs and low blobs. Even if the rear cow gets close, you can see a lower blob because the neck and head are much less area than the cow body.
Two sensor arrays one to measure the length of the incoming cow blob and the second to actually fire the spray.
Kinda' the same logic, but hopefully less error prone?
Well heck might as well use Linear Regression, and ML to create a mathematical model of what is a cow and use the training model to detect "COW". Even better use a Raspberry Pi and TensorFlow to 'say' "COW" and even "COW TEAT" time to spray.