Water Environment
Table of Contents
Week 18









- Completion of soldering (pumps)
- All power supplies plugged in.
- Handling water ripple and splashing. Tested metal mesh which sunk. Tested foam board which still caused splashing. Decided to have tubes push against interior container wall to spill down instead of drip to negate splashing.
- Further tweaking of program speeds and ranges.
Week 17












- Adjusted planter brace from Week 5 to hook onto water container.
- Adjusting pump speeds and sensor ranges.
- Reprinted all pump mount lids with vent holes. Reprinted main lid with white filament to reduce heat retained from sensors/pcb (compared to black filament).
- Splashing from the water surface causes error with water level sensor readings due to rippling. Also poses risk of getting the sensor wet when the water level is high. Considering using mesh to dull ripples or act as a cover directly in front of the sensor.
Week 16









- Recalibrating (new) sensors after resoldering
- Adjusting mounts and covers for pumps (vent holes and lenghtened cover)
- Confirming water level sensor still behaves properly (video)
Week 15
- Altered pump mount from https://www.thingiverse.com/thing:3356513
- Mock set-up of overall project
- Color-coded pump mounts
- Adding ventilation to water container lids to balance humidity
- Damaged sensors due to incorrect voltage provided. Reordered sensors.
Week 14









Extreme Case Main Loop if-else statement snippet. Reordered which extreme cases are checked first as only one can be fulfilled at once (Prioritizing Hydrate/Water Level to avoid overflow). Replaced generalizing function for checking water level condition with direct code due to logic errors in generalization.:
if(hydLowActive){ // case for LOW water level
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = false;
// checkExtremeCaseWaterDist(midWaterDistance);
if(lastWaterDistReading <= midWaterDistance){ // checking for water rising, so it needs to meet at or above it (since water lvl starts already farther dist)
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(hydHighActive){ // case for HIGH water level
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
// checkExtremeCaseWaterDist(midWaterDistance);
if(lastWaterDistReading >= midWaterDistance){ // checking for water lowering, so it needs to meet at or below it (since water lvl starts already shorter dist)
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(socMaxActive){
// set socialize at max behaviors
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
// checkExtremeCaseWaterDist(waterDistToReach);
if(lastWaterDistReading >= waterDistToReach){ // checking for water to reach down to so at or below it
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(socMinActive){
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
// checkExtremeCaseWaterDist(waterDistToReach);
if(lastWaterDistReading >= waterDistToReach){ // checking for water to reach down to so at or below it
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(creMaxActive){ // yellow runs alone at max
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 255;
waterSpeed = 0;
removeWater = true;
}
else if(creMinActive){
magentaSpeed = 255;
cyanSpeed = 255;
yellowSpeed = 0;
waterSpeed = 0;
removeWater = true;
}
else{
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 0;
removeWater = true;
}
}
RGB LED indicator is set when extreme case is set. However, if more than one extreme were to be triggered in the same loop iteration, the last to be called would be set (Socialize-->Hydrate-->Create) even if the extreme case that runs does not match the color coding (Hydrate>Socialize>Create):
void setExtremeState(int delayTime){
extremeCaseActive = true;
pirSonarDelay.stop();
// waterSonarDelay.stop(); // dont use, never stop sonar bc itll be used to determine length of extreme state
floatDelay.stop();
printOutTimer.stop(); // stopped in an extreme case to reflect the cut off of communication in an overwhelmed or underwhelmed system
extremeBlockDelay.start(delayTime);
}
if (socialize > SOCIALIZERANGE) {
// upper bound
socialize = (BASESOCIALIZE * 9) / 10; // reduce to slightly below base 90%
socMaxActive = true;
setExtremeState(0);
// water is going to be removed
if(lastWaterDistReading >= (farthestDistanceToWater - 6)){ // 6mm error; bc water is to be removed, have to check if the water is too low or not
setNormalState(); // water is too low to remove any further, skip extreme case (should trigger water case instead)
}
else{
waterDistToReach = (lastWaterDistReading * 3) / 2;
if(waterDistToReach >= farthestDistanceToWater){
waterDistToReach = farthestDistanceToWater;
}
bufferedOut.println("Max Socialize Set");
digitalWrite(REDPIN, HIGH); //red led
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, LOW);
}
}
else if (socialize < 0) {
// hit the lower bound
socialize = BASESOCIALIZE / 10; // it learned some self love or smth
socMinActive = true;
setExtremeState(0);
// water to be removed
if(lastWaterDistReading >= (farthestDistanceToWater - 6)){ // 6mm error; bc water is to be removed, have to check if the water is too low or not
setNormalState(); // water is too low to remove any further, skip extreme case (should trigger water case instead)
}
else{
waterDistToReach = (lastWaterDistReading * 5) / 4;
if(waterDistToReach >= farthestDistanceToWater){
waterDistToReach = farthestDistanceToWater;
}
bufferedOut.println("Min Socialize Set");
digitalWrite(REDPIN, HIGH); //magenta led
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, HIGH);
}
}
Week 13















Week 12











- Temporary lids printed for testing purposes. Filed-down to fit sensors and pumps due to mis-sizing.
- Makerspace helped resize the original mason jar pump lid by horizontally scaling it, though the holes in the lid have to be sized back to the original lid size.
- Issues with the MB sonar sensor mount due to placement of the sensor and screws. Altered the PIR mount file for the sonar file. Opened back of sensor mount to allow wires to go through.
- Redesigned main tank lid and fixed mason jar lid holes.
Week 11







Adjustments:
- Use a tank larger than the total liquid volume possible for each dye container and main tank as a backup tank holding water that gets added to and removed from the main tank (a 5 gallon water container as opposed to a jar that would have been the same size as the dye containers), in order to avoid an additional sensor for checking for overflow in the backup container.
- Decision to use 64oz mason jars to hold dyes and a tall, narrow vase as the main tank (to allow for the water level to change more given an amount of volume added).
- Alterations to pump mounting lids and sensor mounts for 3D print due to size mismatches and missing features.
Sensor 3D Models:
- PIR Sensor: https://www.thingiverse.com/thing:3251488
- MaxBotix Sonar Sensor: https://www.thingiverse.com/thing:38531
Week 10
Testing MB1644 sensor.Code also corrected for manual button on/off and overflow detection due to misplaced function calls.
Water level measuring code:
int readWaterSonar(){
// hrlv shortrange mb1644
if(waterSonarDelay.justFinished()){ // mb1644
waterSonarDelay.repeat();
int distancemm = (analogRead(WATERSONARPIN) * 6) - 300; // directly from maxbotix doc; mm reading
lastWaterDistReading = distancemm; // always record last reading in global var
return distancemm;
}
else{
return -1;
}
}
Code for extreme cases with escape conditions based on water level or time elapsed (Extreme case main loop if-else statement snippet). Unsuccessful implementation until later testing (See Week 14):
if(socMaxActive){
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
checkExtremeCaseWaterDist();
}
else if(socMinActive){
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
checkExtremeCaseWaterDist();
}
else if(hydLowActive){ // case for LOW water level
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = false;
checkExtremeCaseWaterDist();
}
else if(hydHighActive){ // case for HIGH water level
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
checkExtremeCaseWaterDist();
}
else if(creMaxActive){
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 255;
waterSpeed = 90;
removeWater = true;
}
else if(creMinActive){
magentaSpeed = 255;
cyanSpeed = 255;
yellowSpeed = 0;
waterSpeed = 90;
removeWater = true;
}
else{
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 0;
removeWater = true;
}
Week 9
Ultrasonic Sensor Incorporation into PIR sensor reading function for sensing proximity of visitors (snippet):
void readPIRSonar(){
// read PIR and sonar at the same time
if(pirSonarDelay.justFinished()){
pirSonarDelay.repeat();
int pirState = digitalRead(PIRPIN);
// distance accord to https://maxbotix.com/blogs/blog/arduino-guide
int distance = analogRead(PPLSONARPIN) / 2; // inches, distance
pirSonarInfo[0] = pirState; // 0/1
pirSonarInfo[1] = distance; // inches
}
else{
pirSonarInfo[0] = -1;
pirSonarInfo[1] = -1;
}
}
3D Print Mason Jar Pump Mount: https://www.thingiverse.com/thing:4823002
Week 8











Week 7










Major changes:
- Planning to use short-range ultrasonic sensor for measuring water level instead of calculating in program due to challenging variables in calculating water volume vs. water level mathematically (different shapes of tanks, unideal variations in pumps running).
- Planning to use long-range ultrasonic sensor for detecting proximity of people in the gallery space (for affecting socialization factor/variable) instead of capacitive sensor because it would be more straightforward and precise.
Week 6
Major Change: Shifting code from custom libraries to all written in Arduino IDE with non-blocking delays and continuously running pumps.
Week 5
Week 4
Latest Arduino Code
// from SafeString V3 library https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html#examples
#include "loopTimer.h"
#include "millisDelay.h"
#include "BufferedOutput.h"
// https://youtu.be/lqg_Ze_OiiY?si=H7TvYJQIvozWl-Bi
// #include "CapacitiveSensor.h" // or <CapacitiveSensor.h> ?
createBufferedOutput(bufferedOut, 80, DROP_UNTIL_EMPTY); // buffered use and loop timer from https://www.instructables.com/Simple-Multi-tasking-in-Arduino-on-Any-Board/
// --------VARIABLES/OBJECTS--------
// SERIAL PRINT DATA
millisDelay printOutTimer;
const int PRINTOUTTIME = 5000; // ms, adjust as useful for getting the data read in to mpi
// PAUSE BUTTON
#define PAUSEBUTTON 13
bool programRunning = true;
// EMERGENCY WATER LEVEL SENSOR using sonar? or another sensor as backup
/*
#define WATERLVLPIN 4
// no delay, just constantly run for readings unless need a delay for any built in delays
int waterLvlVal = 0; // need to calibrate to the current environ, any amount of resistance detection counted as actual water touching is sign that program needs to stop
*/
// PIR & SONAR PPL DETECT
#define PIRPIN 12 // sensor input
// millisDelay pirDelay; //
// const int PIRDELAYTIME = 8000; // timedelay+nonreadingdelay (~5s+3s)
int pirSonarInfo[2] = {-1,-1}; // holding whether PIR reads H or L, no new reading is set to -1
millisDelay pirSonarDelay;
const int PIRSONARDELAYTIME = 8000; // timedelay of pir+nonreading delay of pir
// SONAR PPL DETECT
#define PPLSONARPIN A2
// millisDelay pplSonarDelay;
// const int PPLSONARDELAYTIME = 2000; // allow to adjust socialize var even if PIR state is still a prior state but ur then i need to know the prior PIR so maybe i align w PIR unless direct touch
// ex: 8000 ms delay to match w PIRDELAYTIME
// usually direct touch is around 10k return value
int pplSonarDistancein = -1; // default val
// int closePplDistance = 7; //min is 6in measure as closest; max is 254in
// if it got too close and interactive, i think itd be interesting if it shut off bc it was shy
int midPplDistance = 108; // measure by which positive effect can be had --> NOTE: rn the sensor isnt measuring past 40inches... its an ok distance (a lot closer than i wanted 108in)
// table to door 72*3+12 = 19ft (228in)
// (228in(dist to door)-6in (min))/2 (middle)
// WATER LEVEL - Sonar
// mb1644 shortrange ; 2-50cm
#define WATERSONARPIN A1
millisDelay waterSonarDelay;
const int WATERSONARDELAYTIME = 200; // ms, adjust, mb1644 has 100ms read speed, relatively frequent to take note on water level for safety too
int waterSonarDistancemm = -1; // can't measure less than like 5-6in so 0 would be a non-read value
// water distances are farther=lower level; in mm
// going to be based on tank size
// think i need to do calibration
// idk it still measures 396 pew....
int farthestDistanceToWater = 362; //mm; for lowest water level, larger dist to water top --> calculated by callibration and errors
int closestDistanceToWater = 120; //mm; for highest water level, smaller dist to water top
int midWaterDistance = (farthestDistanceToWater + closestDistanceToWater) / 2; // mm; middle of high and low
// water level handling record the last read level
int lastWaterDistReading = 0; // to account for how much water should be removed or not in extreme cases
int waterDistToReach = 0; // setting the water level that the extreme case should be acting on
// FLOAT
#define FLOATPIN A0
millisDelay floatDelay; // just to give some delay between readings so it isn't read too frequently
const int FLOATDELAYTIME = 4000; // ms; arbitrary --> pump needs enough time w a fixed value to actually move water so do a longer delay (based on how the updateCreate func works), whatever works best for the program in consideration of readings being continous for x time before a new reading
int floatDiff = 1024; // the val and threshold is decided in the reading function, only the difference needs to be known globally; tho the threshold could be reflected too somehow
// CONTINUOUS PUMPS
const int MINPUMPSPEED = 85;
const int INCDELAY = 5; // ms
// MAGENTA
#define MAGENTAPIN 3
millisDelay magentaIncDelay;
int magentaSpeed = 0;
int magentaEnVal = 0;
// CYAN
#define CYANPIN 5
millisDelay cyanIncDelay;
int cyanSpeed = 0;
int cyanEnVal = 0;
// YELLOW
#define YELLOWPIN 6
millisDelay yellowIncDelay;
int yellowSpeed = 0;
int yellowEnVal = 0;
// REMOVAL/ADD
#define WATERADDIN 9
#define WATERRMVIN 10
millisDelay waterIncDelay;
int waterSpeed = 0;
// alt option is 3 pins w inputs on reg high low and engage on pwm
int waterAddInVal = 0; // input 1 reg polarity pos
int waterRmvInVal = 0; // input 2 reverse polarity pos
bool removeWater = true; // change for min/max and basic removal stuff
// BEHAVIORS - set a baseline defined by its min/max range
// extremes
bool extremeCaseActive = false;
millisDelay extremeBlockDelay;
// const int SOCMAXDELAYTIME = (INCDELAY*255*2) + 5000; // ms, time to change regular water removal up to 255, plus time calculated based on volume to remove, plus time to slow back down to 0? or average removal speed
bool socMaxActive = false;
bool socMinActive = false;
bool hydLowActive = false;
bool hydHighActive = false;
bool creMaxActive = false;
bool creMinActive = false;
// led indicators
#define REDPIN 7
#define GREENPIN 4
#define BLUEPIN 2
const int SOCIALIZERANGE = 1000; // 0 to 3000; 1/3 of the value is the min to turn on the pump (map to 85)
const int BASESOCIALIZE = (SOCIALIZERANGE / 4); // base value to ref elsewhere in program; base level should always be below 1/3 of the total range to start all the pumps OFF
int socialize = BASESOCIALIZE; // **(need to adjust) baseline start (having smth to gain or lose) ; mapped to magenta
// bool sociallyDrained = false; // max socialize value hit
// millisDelay socialDrainBlockDelay; // prevent updateSocialize() from changing socialize var after maximum socialize val is reached for a time
// const int SOCIALDRAINBLOCKTIME = 5000; // adjust time to go based on if the removal of water has finished or not [basically whichever is longer will allow socialize to be changed again]
// bool lonely = false; // min socialize value hit
// millisDelay lonelyBlockDelay;
// const int LONELYBLOCKTIME = 5000; // again, adjust and consider compared to time for other aspects of the drain to occur first with other delays or booleans (whatever is most appropriate)
int hydrate = 0; // mapped to cyan
int create = 0; // mapped to yellow; 0 is neutral state (not above or below floatDiff threshold)
const int ANALOGMAX = 1023; // max possible value to come from analog pin input sensing
void setup() {
Serial.begin(9600);
// pause button setup
pinMode(PAUSEBUTTON, INPUT_PULLUP);
// extreme and emergency led indicators
pinMode(REDPIN, OUTPUT);
pinMode(GREENPIN, OUTPUT);
pinMode(BLUEPIN, OUTPUT);
digitalWrite(REDPIN, LOW);
// digitalWrite(REDPIN, HIGH); // testing
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, LOW);
// seed for random values
pinMode(FLOATPIN, INPUT); // do i need to set this as input?
randomSeed(analogRead(FLOATPIN));
floatDelay.start(FLOATDELAYTIME); // needs to already be timed out upon first loop run
// magenta pump setup
pinMode(MAGENTAPIN, OUTPUT);
analogWrite(MAGENTAPIN, 0);
// cyan pump setup
pinMode(CYANPIN, OUTPUT);
analogWrite(CYANPIN, 0);
// yellow pump setup
pinMode(YELLOWPIN, OUTPUT);
analogWrite(YELLOWPIN, 0);
// water pump setup
pinMode(WATERADDIN, OUTPUT);
analogWrite(WATERADDIN, 0);
pinMode(WATERRMVIN, OUTPUT);
analogWrite(WATERRMVIN, 0);
// ultrasonic sensor setup
pinMode(WATERSONARPIN, INPUT);
int distancemm = (analogRead(WATERSONARPIN) * 6) - 300; // directly from doc; mm reading
lastWaterDistReading = distancemm; // give a default value that tech should be neutral height when in tank measuring so that emergency water shutoff doesnt get default 0 and shut off the program at the start
Serial.println(distancemm);
// tho thats one way to get the program to not start until i actually want it to start sooooo; and i know exactly the problem
// SET LASTWATERDISTREADING HERE WITH A PROPER DEFAULT VALUE OR LEAVE AT 0 INITIALLY IF I WANT THE PROGRAM TO BEGIN PAUSED [tho its better i just set programRunning to false/paused then]
waterSonarDelay.start(WATERSONARDELAYTIME);
// need a calibration period to determine the min and max height measures
// also i think its +/- 5mm error margin??? or smth - see docs
// while(button not pressed){don't pass} --> button pressed do read for indicated level (lowest), do twice, go w higher reading; repeat while then until measured all major heights to know (manual)
/*
// record min and max somehow? or just test enough in the final project to know what to set min and max to
*/
// PIR and sonar setup
pinMode(PIRPIN, INPUT);
pirSonarDelay.start(PIRSONARDELAYTIME);
pinMode(PPLSONARPIN, INPUT);
/*
// calibrate the max and min distance; 6 will always be min bc of restraint
but also register the true max range to find the middle? i feel my own measurements is fine tho
*/
// pirDelay.start(PIRDELAYTIME); // starts the delay, tech i want it to start after PIR is read once for the first time? [**maybe i run the whole sensor reading once in setup?]
// Serial.println("1 minute initialization");
bufferedOut.connect(Serial);
// make delay 60000 (1min) for final code
// may need to increase delay init to 1.5min or smth bc it seems like it doesnt read the initial times
delay(5000); // initialize pir sensor: can change to a one-shot timer to not do a PIR reading/not leave set-up/start loop until the PIR has initialized so everything else can still set-up
// capsense setup
// capSenseDelay.start(CAPSENSEDELAYTIME);
magentaIncDelay.start(INCDELAY);
cyanIncDelay.start(INCDELAY);
yellowIncDelay.start(INCDELAY);
waterIncDelay.start(INCDELAY);
printOutTimer.start(PRINTOUTTIME);
// start with a switchSystemState() function until button is pressed so that i can hold everything in place to calibrate anything?
// programRunning = false;
switchSystemState();
// Serial.println("Press button to start pumps.");
}
void loop() {
// maybe init speed vars here instead of global bc they arent changes anywhere else rly that cant just be changed in the loop? unless it matters to extreme cases
// DEBUGGING/SHUTOFF AIDS
bufferedOut.nextByteOut(); // call at least once per loop to release chars
// loopTimer.check(bufferedOut); // send loop timer output to the bufferedOut
manualSystemSwitch(); // see if manually pausing the program with button / turning back on (pauses sensor reads which snowballs in slowing rest of program)
waterLevelShutOff(); // checks for water level too high when program is running
// BLOCKING DELAY CHECKS (if not run already in functions)
// socialDrainBlockDelay.justFinished(); // must run this each loop even if delay not set yet
// lonelyBlockDelay.justFinished();
extremeBlockDelay.justFinished();
if(!extremeBlockDelay.isRunning() && (creMaxActive || creMinActive)){
// extreme block delay not running and a hydration extreme case is true (then will reset and this will always be lie !false and false)
setNormalState(); // for yellow creative period only
bufferedOut.println("Finished extreme case.");
}
// fill in all blocking delay checks on extreme cases
// SENSOR READINGS
// when programRunning==false; the sensor delays are stopped so these give their default/non-effect values
// pirSonarInfo = readPIRSonar();
readPIRSonar(); // updates pirSonarInfo to be the right values
// capSenseVal = readCapSense();
waterSonarDistancemm = readWaterSonar();
floatDiff = readFloat(); // for now, temp
// here is where it matters if programRunning is true/false directly to control speed
// to keep the global vars at their last state, have to force speeds to 0 instead of functions
if(programRunning){
if(!extremeCaseActive){ // more frequently the case, normal system state (when extremeCaseActive == false)
// UPDATE VARIABLE BEING STATES
// when programRunning==false, sensor delays r on defaults so vars SHOULD NOT be updated (make sure to code this in)
// socialize += 100; // testing
updateSocialize(floatDiff, waterSonarDistancemm);
updateHydrate(waterSonarDistancemm);
updateCreate(floatDiff, waterSonarDistancemm);
// UPDATE PUMP SPEEDS
magentaSpeed = setMagentaPumpSpeed(); // no delays in these funcs so fine in if-else
cyanSpeed = setCyanPumpSpeed();
yellowSpeed = setYellowPumpSpeed();
waterSpeed = MINPUMPSPEED; // empirical decision of what the basic removal of water speed should be
removeWater = true;
// bufferedOut.print("cyanSpeed ");
// bufferedOut.println(cyanSpeed);
}
else{ // extreme system state; extremeCaseActive (true)
// extreme case is active - only one case can be true at any given time
// organize extreme cases by importance --> water level must trigger first if set at the same time as another case and complete itself (other sensors will trigger again if still valid)
if(hydLowActive){ // case for LOW water level
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = false;
// checkExtremeCaseWaterDist(midWaterDistance);
if(lastWaterDistReading <= midWaterDistance){ // checking for water rising, so it needs to meet at or above it (since water lvl starts already farther dist)
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(hydHighActive){ // case for HIGH water level
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
// checkExtremeCaseWaterDist(midWaterDistance);
if(lastWaterDistReading >= midWaterDistance){ // checking for water lowering, so it needs to meet at or below it (since water lvl starts already shorter dist)
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(socMaxActive){
// set socialize at max behaviors
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
// checkExtremeCaseWaterDist(waterDistToReach);
if(lastWaterDistReading >= waterDistToReach){ // checking for water to reach down to so at or below it
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(socMinActive){
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 255;
removeWater = true;
// checkExtremeCaseWaterDist(waterDistToReach);
if(lastWaterDistReading >= waterDistToReach){ // checking for water to reach down to so at or below it
setNormalState(); // reset extreme active cases and sensor timers
bufferedOut.println("Finished extreme case.");
}
}
else if(creMaxActive){ // yellow runs alone at max
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 255;
waterSpeed = 0;
removeWater = true;
}
else if(creMinActive){
magentaSpeed = 255;
cyanSpeed = 255;
yellowSpeed = 0;
waterSpeed = 0;
removeWater = true;
}
else{
// if none of the extremes were active, smth is just off with the program calculations here
// should prob turn on an LED or smth to signal that theres a missing Active bool turned to true when extremeBlockDelay was started
magentaSpeed = 0;
cyanSpeed = 0;
yellowSpeed = 0;
waterSpeed = 0;
removeWater = true;
}
}
// if(extremeActive){
// if socializeMaxRemoveDelay.isRunning{waterSpeed = 255; removeWater = true;} // if justFinished(), then start Max add delay?, note the reversal time to change polarity has to be accounted for
// else if socializeMaxAddDelay.isRunning{waterSpeed = 255; removeWater = false;}
// if socializeMinRemoveDelay.isRunning{waterSpeed = 255; removeWater = true;}
// else if socializeMinAddDelay.isRunning{waterSpeed = 255; removeWater = false;}
// if hydrateMaxRemoveDelay.isRunning{waterSpeed = 255; removeWater = true}
// if hydrateMinAddDelay.isRunning{waterSpeed = 255; removeWater = false;}
// yellow min/max settings only affect M/C pumps to bring them to max or 0 briefly while yellow is on or off appropriately, no affect on removing or adding water
// } // can extremeActive change at all when others are triggered? can it go false when the extreme case block delays are done? like if any are true justFinished() then extremeActive = false?
}
else{
magentaSpeed = 0; // pull down speed when program is paused/not running (programRunning==false)
cyanSpeed = 0;
yellowSpeed = 0;
// also slow down water removal/add if it was running
waterSpeed = 0;
removeWater = true;
}
// RUN PUMPS
runMagentaPump(magentaSpeed);
runCyanPump(cyanSpeed);
runYellowPump(yellowSpeed);
waterChange(waterSpeed, removeWater); // remove water constantly at a small amt; removeWater changes depending on min/max extremes but is normally true (for regular draining)
// timered serial prints (can i do it thru bufferedOut?) that send data to raspberry pi thru serial ports
// Serial.print("Socialize,");
// Serial.print(socialize);
// Serial.println(",");
// repeat for each var [note the time prints take in the loop..., have function and delay print outs only every few seconds to rpi to capture a sample]
// SERIAL PRINT DATA
printData(); // i think i would have the data stop when the system is in an extreme case
}
// --------SERIAL PRINT DATA--------
void printData(){
if(printOutTimer.justFinished()){ // i only need to write out the data to a file if i need to transmit it to the cluster each time; otherwise if i can have rpi immediately read it into the program then i dont need to remember old data?
printOutTimer.repeat();
bufferedOut.print(socialize);
bufferedOut.print(",");
bufferedOut.print(hydrate);
bufferedOut.print(",");
bufferedOut.print(create);
bufferedOut.print(",");
bufferedOut.println(); // also want to add info about removal to act in place of T/grey?
}
}
// --------SYSTEM PAUSE--------
// handling pauses of the program and potential resets of prior states (maybe i need to write out to a file the last system state)
// blocking delay on all functions - still need to make sure justFinished always runs each loop? --> stops all the other delays so their test if states dont pass
void manualSystemSwitch(){
// use a button w pull up resistor to read a pin repeatedly to see if its been pressed and program need to be brought to 0 slow down and set block delay
// adapted code from arduino button example and elegoo manual
int buttonState = digitalRead(PAUSEBUTTON); //(wired as one side to input digital, other to gnd)
// using built in input pullup resistor, opposite logical (closed when LOW/0)
if(!buttonState){ // just avoid clicking a bunch
delay(200); // debounce; blocking delay but program is changing from on/off so its fine
// bufferedOut.println("Changed");
switchSystemState();
}
}
void waterLevelShutOff(){
// detect water level -> but also stop program here so it can't detect a new water level after it has detected it once so the program cant start again without the button press
if(programRunning){ // only detect during program running, no delay because i want the readings asap on water level overflow or too high level
// readWaterSonar(); // prob an analog reading tho so threshold below and add in a recalibration in the switchSYstemState() on
if(lastWaterDistReading <= (closestDistanceToWater - 15)){ // don't accidentally turn on again if the program was off // lowest error is 12mm, so once past that for close range, its not triggering extreme case properly and needs to be stopped
switchSystemState(); // causes program to turn off so this will also stop reading and only the button detection can turn on the program again
}
}
// return;
}
void switchSystemState(){
if(programRunning){
programRunning = false; //!programRunning
// pirDelay.stop();
pirSonarDelay.stop();
// capSenseDelay.stop();
// waterSonarDelay.stop(); // always keep water sonar readings occurring bc this setting will still prevent it from turning on a pump; but it needs to continue reading to not get kicked back into pause with lastwaterreading after reaching too high lvl in checking water level function
floatDelay.stop();
printOutTimer.stop();
// keep pump delays on bc theyll need to be set down to 0
// force down values elsewhere in program
// bufferedOut.println("System paused.");
digitalWrite(REDPIN, HIGH); //white led (program STOPPED)
digitalWrite(GREENPIN, HIGH);
digitalWrite(BLUEPIN, HIGH);
}
else{
programRunning = true; // !programRunning
// pirDelay.start(PIRDELAYTIME);
pirSonarDelay.start(PIRSONARDELAYTIME);
// capSenseDelay.start(CAPSENSEDELAYTIME);
// waterSonarDelay.start(WATERSONARDELAYTIME);
floatDelay.start(FLOATDELAYTIME);
printOutTimer.start(PRINTOUTTIME);
// values will no longer be forced down in loop
/* NOTE FOR WATER LEVEL SENSOR EMERGENCY SHUT OFF
// insert calibration code of the water detector used (if its a switch then theres no need, but if its resistance based water level then calibrate)
*/
// bufferedOut.println("System reactivated.");
digitalWrite(REDPIN, LOW); //OFF led (program running normally)
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, LOW);
}
}
// --------SENSORS--------
void readPIRSonar(){
// bufferedOut.println(socialize);
// read PIR and capsense at the same time
if(pirSonarDelay.justFinished()){
pirSonarDelay.repeat();
int pirState = digitalRead(PIRPIN);
// distance accord to https://maxbotix.com/blogs/blog/arduino-guide
int distancein = analogRead(PPLSONARPIN) / 2; // inches, distance
// 5V yields ~9.8mV/in, (Vcc/512) per inch
// so max analog 1024 is 2in; mult 2??? - have to test output
// bufferedOut.println(pirState);
pirSonarInfo[0] = pirState; // 0/1
pirSonarInfo[1] = distancein; // inches
// int readings[2] = {pirState, distance};
bufferedOut.print("PIR: ");
bufferedOut.println(pirSonarInfo[0]);
bufferedOut.print("Distance inches: ");
bufferedOut.println(pirSonarInfo[1]);
// return readings;
// bufferedOut.println(socialize);
}
else{
// int readings[2] = {-1,-1};
// return readings;
pirSonarInfo[0] = -1;
pirSonarInfo[1] = -1;
}
// return;
}
/*
int readPIR(){ // focus end wk6
// 1) Detect motion (hi or lo?)
// 2) Count consecutives of hi/lo
// 3) return consecutive # and type
// NOTE: need to distinguish old and new readings if updateSocialize keeps reading an old reading? (or just let it process that for the particular time)
if(pirDelay.justFinished()){
pirDelay.repeat();
// code from https://mechatronicslearning.com/how-to-use-pir-sensor-with-arduino-beginners-guide/
int pirState = digitalRead(PIRPIN); // maybe the ver w capacitance as threshold i want to do repeat mode (refreshes time delay and nonreading delay each time a motion is detected anew)
// tho repeat means high can be repeat detected relatively quickly but lows won't be detected til after the timedelay+nonreaddelay (~6-8s)
// reading pir state w single trigger would mean new pir detection only every 6-8s (how do i incorporate into the program updating variables?)
// bufferedOut.println(pirState);
return pirState; // 0 is false/low, 1 is high/true
// read the PIR sensor consecutives
// NOTE: pir sensor needs an initialization period (~1min)
// NOTE: pir sensor has a stay-high period (min ~3-5sec depend on setting) AND a non-reading time (~3sec)
// account for this in a time delay so the pir isn't attempted to read again when no change or reading could occur
}
else{
return -1; // need to signal no new reading, may remove if i use in conjunction with capacitive touch sensor (so one interaction could improve or get worse if the distance of the motion that was originally detected is changing)
}
}
*/
int readWaterSonar(){ // going to be more intricate in calculating so. yeah
/*
1) calculate previous net water level change from base level [decide which is more relevant to use, prob base thinking of it is a neutral/balanced state]
2) return net water level change from base/neutral level [discount removal due to periodic ridding? or shift to have removal only due to excess water addition?]
*/
// how to read this; simplest way is directly on a sensor but water sensors r tricky...
// hrlv shortrange mb1644
if(waterSonarDelay.justFinished()){ // mb1644
waterSonarDelay.repeat();
int distancemm = (analogRead(WATERSONARPIN) * 6) - 300; // directly from doc; mm reading
lastWaterDistReading = distancemm; // always record last reading in global var
// bufferedOut.print("water distance: ");
// bufferedOut.print(distancemm);
// bufferedOut.print(" mm");
// bufferedOut.print(" | hydrate: ");
// bufferedOut.println(hydrate);
return distancemm;
}
else{
return -1; // limit of mb1644 supposedly should give a min read of 2cm, so 0 isn't possible in theory unless smth weird happens; negative def not possible
}
}
int readFloat(){
/*
1) Read floating analog pin
2) randomly choose threshold in float analog range
3) measure float value difference from threshold (+/0 is counted above threshold, - is counted below)
4) return the difference
*/
if(floatDelay.justFinished()){
floatDelay.repeat();
int floatThreshold = random(0,1024); // possible values for analog input measure ; (incl, excl); need a val 0 to 1023
int floatValue = analogRead(FLOATPIN); // current measured value for floating pin
int floatDifference = floatValue - floatThreshold; // a value -1023 to 1023 possible, 0 is neutral state but not above threshold either
// bufferedOut.print("Float Difference: ");
// bufferedOut.println(floatDifference);
return floatDifference;
}
else{
return 1024; // would need like 1024 or smth as the return if i don't want to reuse an old val tho here i think i would; use floatDiff global var if i want to reuse the last reading
}
// check the Float threshold randomization
}
// --------METAPHORICAL VARIABLES--------
/*
void checkExtremeCaseWaterDist(int waterToReach){
// readWaterSonar();
if(lastWaterDistReading >= waterToReach){ // (consider margin of error) always opt for less than more in reading levels?
setNormalState(); // reset extreme active cases and sensor timers
// will lead to exiting the extreme case loop if state
bufferedOut.println("Finished extreme case.");
}
}
*/
void setNormalState(){
socMaxActive = false; // once just finished, set these all back to false so they can be set true again later and not mess w active block delay options
socMinActive = false;
hydHighActive = false;
hydLowActive = false;
creMaxActive = false;
creMinActive = false;
extremeCaseActive = false;
// restart all sensor delays that were turned off during extreme state
// pirDelay.start(PIRDELAYTIME);
pirSonarDelay.start(PIRSONARDELAYTIME);
// capSenseDelay.start(CAPSENSEDELAYTIME);
// waterSonarDelay.start(WATERSONARDELAYTIME); // keep on always
floatDelay.start(FLOATDELAYTIME);
printOutTimer.start(PRINTOUTTIME); // restarts after a pause bc communication is "cut off" in an extreme case
// bufferedOut.println("Extreme case finished.");
digitalWrite(REDPIN, LOW); //OFF led (no extreme case)
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, LOW);
}
void setExtremeState(int delayTime){
extremeCaseActive = true;
// pirDelay.stop();
pirSonarDelay.stop();
// capSenseDelay.stop();
// waterSonarDelay.stop(); // dont use, never stop sonar bc itll be used to determine length of extreme state
floatDelay.stop();
printOutTimer.stop(); // stopped in an extreme case to reflect the cut off of communication in an overwhelmed or underwhelmed system
// 0 for all cases except hydration cases which are 5000 (5seconds) approx, or adjust
extremeBlockDelay.start(delayTime);
}
void updateSocialize(int floatValue, int sonarDistance){
/*
1) collect various sensor info to interpret into the variables
2) range social as 0 to 255 or base speed (for pump pwm) to max 255
3) basic behavior: hi turns on the pump, lo turns off the pump so maybe just create value range and then map later to 0 to 255?
*/
// if(socialDrainBlockDelay.isRunning()){ // additional conditions: && drainFinished (&& any other things that have to run before socialize is updated again r finished too)
// return; // don't update socialize, leave it at its last value which was set as slightly below base before
// }
// if(lonelyBlockDelay.isRunning()){ // additional conditions: && drainFinished ^^
// return; // don't update socialize, leave it as its last value which can go up to maybe 10% of abse
// }
// if (extremeBlockDelay.isRunning()){
// return;
// }
// max increment
int maxChange = 100; // avoid floats bc mpa() uses integer math
// PIR state 75% change or 3/4
// closePplDistance, midPplDistance
/*
HI
close = ++
far = --
LO
close = -
far = +
*/
if (pirSonarInfo[0] > 0) {
// true, non-zero, high
socialize += (maxChange * 3) / 4; // FOR TESTING, REMOVE ONCE SONAR IS INCLUDED
/*//ADD BACK WITH SONAR
if(pirSonarInfo[1] > midPplDistance){ // ignored
socialize -= (maxChange * 3) / 4;
}
else{ // interacting w friends
//closer than mid distance
socialize += (maxChange * 3) / 4;
}
*/
}
else if (pirSonarInfo[0] == 0){ // low
// socialize -= (maxChange * 3) / 8; // FOR TESTING, REMOVE ONCE SONAR INCLUDED
//ADD BACK WITH SONAR
if(pirSonarInfo[1] > midPplDistance){ // just passing strangers
socialize += (maxChange * 3) / 8; // half the effect of a motion interaction
}
else{ // a little awkward/crowded
//closer than mid distance
socialize -= (maxChange * 3) / 8;
}
}
else{
return; // no changes should occur to socialize if no social info is taken even if other vars are taken
// checked by the pir state
}
// else{ // negative val (not high or low reading), and any other strange things
// // no new reading, no change from PIR to the socialize
// }
// modify socialize based on water level calc (or sensor?)
// 15% change --> 3/20
if(sonarDistance < midWaterDistance && sonarDistance > closestDistanceToWater){ // exclude xtreme cases; higher water level
socialize -= (maxChange * 3) / 20; // needs a bathroom break
}
else if(sonarDistance > midWaterDistance && sonarDistance < farthestDistanceToWater){ // exclude xtreme cases; lower water level
socialize += (maxChange * 3) / 20; // need a drinky (w friends why not)
}
// else{
// // below min accepted or above max accepted, or middle water range neutral; or non-reading; no effect
// }
// modify socialize based on the floating input state
// 10% change --> random chance increase or decrease if float is above threshold (if not over threshold, no effect)
if (floatValue > 0 && floatValue < 1024){ //pos value that isn't over range possible
// floatValue - floatThreshold = floatDiff, if + means thats floatVal > floatThresh [excluding 0 as a neutral special interpret ig]
if(random(0,2)){ // (incl, excl)
// 0 or 1 will be read true or false
// 1 is true
socialize += (maxChange / 10); // pos effect on socialize decided; presume creativity has made connections or smth, or spontaneous activity
}
else{
// 0, false
socialize -= (maxChange / 10); // neg effect on socialize; presume creativity keeping you cooped up working
}
} // else floatDiff has no effect on socialize neutral or otherwise; maybe neutral will have a smaller pos/neg effect chance like needing to socialize to find inspo; otherwise stagnate
// constrain the socialize value within a desired range --> note extremes if hitting the bounds in order to reset!!!****** NOTE
// need to work out these bounds better bc itll take awhile for the program to get up to doing anything, maybe a smaller range? like max 300 for now
// socialize -= 200; // testing
if (socialize > SOCIALIZERANGE) { // maxChange 100 --> 30 times of max 100 increments to get to extreme case -- a total range of 3000 [may make more sense to start at 1000 or less and have 0 be min]
// upper bound
// sociallyDrained = true; // global, needs to be known by other functions too
//***CHANGES BACK TO FALSE AFTER BLOCKING DELAY IN MAGENTA PUMP FUNCTION? --> or block delay here rather than if-else state w bools? magenta pump will just stay at 0 w this socialize val
// does it make more sense to block this function here from updating socialize?
// bufferedOut.println("Socialize max extreme set");
socialize = (BASESOCIALIZE * 9) / 10; // reduce to slightly below base 90%; -> a boolean should indicate that its entering an extreme state and allow for block delay to start (also quickly returns this func w top if state)
// const int SOCMAXDELAYTIME = (INCDELAY*255*2) + 5000;
socMaxActive = true;
// extremeBlockDelay.start(SOCMAXDELAYTIME);
// // stop all sensors so they dont affect the variables by chance and run faster
// pirDelay.stop();
// // capSenseDelay.stop();
// // waterSonarDelay.stop();
// floatDelay.stop();
setExtremeState(0);
// water is going to be removed
if(lastWaterDistReading >= (farthestDistanceToWater - 6)){ // 6mm error; bc water is to be removed, have to check if the water is too low or not
setNormalState(); // water is too low to remove any further, skip extreme case (should trigger water case instead)
}
else{
waterDistToReach = (lastWaterDistReading * 3) / 2;
if(waterDistToReach >= farthestDistanceToWater){
waterDistToReach = farthestDistanceToWater;
}
bufferedOut.println("Max Socialize Set");
digitalWrite(REDPIN, HIGH); //red led
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, LOW);
}
/* TESTING
bufferedOut.print("water dist to reach (mm): ");
bufferedOut.print(waterDistToReach);
bufferedOut.print(" | water level read (mm): ");
bufferedOut.println(lastWaterDistReading);
*/
// waterDistToReach = lastWaterDistReading * 3 / 2; // the water level that the specified case should go to; 0 if (lose 1/2) [or reads as a 1/2 increase in distance]
// socialDrainBlockDelay.start(SOCIALDRAINBLOCKTIME);
// when hitting the max, see it as drained social battery - pump actions as follows for this state
// magenta pump stops/slows to 0 speed for a certain length of time [create blocking delay timer]
// reset socialize back to base level (or a little less than base level to show its back from an abnormal state)
// other pumps can continue to run, it may also contribute to a slightly higher value on drinking more for instance?
// removes water to visually show significant drain (this will cause the water level sensor to indicate need for more cyan/hydrate naturally while magenta is blocked^^)
// add some water back to make sure its somewhat at average level but still below
}
else if (socialize < 0) { // SOCIALIZERANGE - SOCIALIZERANGE = 0
// hit the lower bound
socialize = BASESOCIALIZE / 10; // it learned some self love or smth
// extremeBlockDelay.start(SOCMINDELAYTIME);
// const int SOCMINDELAYTIME = (INCDELAY*255*2) + 5000;
socMinActive = true;
setExtremeState(0);
// water to be removed
if(lastWaterDistReading >= (farthestDistanceToWater - 6)){ // 6mm error; bc water is to be removed, have to check if the water is too low or not
setNormalState(); // water is too low to remove any further, skip extreme case (should trigger water case instead)
}
else{
waterDistToReach = (lastWaterDistReading * 5) / 4;
if(waterDistToReach >= farthestDistanceToWater){
waterDistToReach = farthestDistanceToWater;
}
bufferedOut.println("Min Socialize Set");
digitalWrite(REDPIN, HIGH); //magenta led
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, HIGH);
}
// waterDistToReach = lastWaterDistReading * 5 / 4; (lose 1/4) [basically reads as a 1/4 increase in distance]
// lonelyBlockDelay.start(LONELYBLOCKTIME);
// min (loneliness) state - pump actions as follows
// magenta pump already stopped/not doing anything if its nearing here
// stagnate?, increase cyan pump? maybe trigger lowering the yellow creat threshold (get thru struggle w creating/VENTING)**
// i can only think of draining again but maybe make it more significant drainage compared to draining social battery?
// add back some water but make sure water level is Below state?
}
// bufferedOut.print("Socialize: ");
// bufferedOut.print(socialize);
// bufferedOut.print(" | ");
// return socialize;
// based on the sensors, update socialization variable (ultimately magenta pump, but multiple sensors can affect it)
}
void updateHydrate(int sonarDistance){
// take direct measure similar to float; calculate a net change
// distanceMin and distanceMax are the extremes to measure distance TO the water top (not actual water level itself)
// water level as the base level is unaffected by any other behavior... maybe
if(sonarDistance < 0){
// non-reading (no new water level), negative measuring; since 0 can be possible
return; // no new value to hydrate, just keep last value
}
hydrate = sonarDistance; // will map based on min/max in setSpeed; mm
//extremes, not yet
if(sonarDistance >= farthestDistanceToWater){ // low water level
hydrate = farthestDistanceToWater; // constrain for the sake of pump speed setting
// add in +/- error?
bufferedOut.println("low water level");
bufferedOut.println(lastWaterDistReading);
hydLowActive = true;
setExtremeState(0); // **NOTE: change to reading just sonar sensor to get water down
// waterDistToReach = midWaterDistance; // up to mid water level
digitalWrite(REDPIN, LOW); //cyan led
digitalWrite(GREENPIN, HIGH);
digitalWrite(BLUEPIN, HIGH);
}
else if(sonarDistance <= closestDistanceToWater){ // high water level
hydrate = closestDistanceToWater; // constrain for the sake of pump speed setting
bufferedOut.println("high water level");
bufferedOut.println(lastWaterDistReading);
hydHighActive = true;
setExtremeState(0); // reset in the following line to forcibly change the var --> or just have it go to the middle calculation like 50% of the current level add or remove
// waterDistToReach = midWaterDistance; // down to midwater level [must be after setExtremeState to ensure waterdist is set to mid]
digitalWrite(REDPIN, LOW); //blue led
digitalWrite(GREENPIN, LOW);
digitalWrite(BLUEPIN, HIGH);
}
// return;
// based on sensors, update hydration var (cyan)
}
void updateCreate(int floatValue, int sonarDistance){
// int maxChange = 100;
if(floatValue <= ANALOGMAX){
create = floatValue; // set create to the new float difference read
}
// else floatVal is 1024, a nonpossible difference value (out of range), don't change anything abt create value, but do allow it to be changed by other sensors still if they have new vals
// create stays the same as it was before
else{
return; // no updates to create when the float value hasnt actually been given
}
// PIR 10% influence (with sonar)
// if(pirSonarInfo[0] > 0){
// create -= floatValue / 10; // 10% decrement effect b/c busy [changes based on capsense when i get there]
// }
// else if(pirSonarInfo[0] == 0){
// create += floatValue / 10; // 10% increase effect b/c not busy [changes based on capsense]
// }
// else{-1, no effect on vars}
if (pirSonarInfo[0] > 0) {
// true, non-zero, high
if(pirSonarInfo[1] > midPplDistance){ // ignored
create += floatValue / 10; // time to create, vent art increase?
}
else{ // interacting w friends
//closer than mid distance
create -= floatValue / 20; // busy, tho lesser bc motivated partially by friends
}
}
else if (pirSonarInfo[0] == 0){ // low
if(pirSonarInfo[1] > midPplDistance){ // just passing strangers
create += floatValue / 10; // time, maybe a little curiosity
}
else{ // a little awkward/crowded
//closer than mid distance
create -= floatValue / 10; // not comfortable here
}
}
// WATER LVL 10% influence
if((sonarDistance < (midWaterDistance+10)) || (sonarDistance > (midWaterDistance-10))){ // be in (error-considered) range of neutral level
create += floatValue / 10; // sufficient hydration and not needing to pee, time and energy to art
}
else if(sonarDistance > closestDistanceToWater && sonarDistance < farthestDistanceToWater){ // within the general range of the non-extreme water levels otherwise
create -= floatValue / 10; // either need to drink or pee
}
// else{
// // below min accepted or above max accepted, or middle water range neutral; or nonreading, no effect
// or 0 and no new measure to update anything
// }
// FLOAT 80% influence
// the other sensors essentially indirectly reflect changing the threshold of the original floatDiff reading
// idk if ill have these be extreme cases yet, like max could be going overly creative hike and focuses on nothing else (ie: stops cyan and magenta b/c hyperfocus)
// no creativity min can reflect trying to find inspo by adding a little to the other functions?
// add in extreme cases only after everything is integrated since this has more effect across the other functions [just save xtreme after all else]
// bufferedOut.print("create: ");
// bufferedOut.println(create);
// create = -ANALOGMAX - 100; // testing
if(create >= ANALOGMAX){
create = ANALOGMAX; // max possible floatDiff value for mapping
const int CREMAXDELAYTIME = (INCDELAY*255*2) + 5000;
creMaxActive = true;
setExtremeState(CREMAXDELAYTIME);
bufferedOut.println("max create threshold difference");
digitalWrite(REDPIN, LOW); //green led
digitalWrite(GREENPIN, HIGH);
digitalWrite(BLUEPIN, LOW);
// will cause other pumps to stop running bc of hyperfocus
}
else if(create <= -ANALOGMAX){
create = 0; // min possible floatDiff value is -1023; TEMP: to 0 just to have it not run, but this is a specific extremity case
// will cause other pumps to get a slight boost in value in search of inspo
const int CREMINDELAYTIME = (INCDELAY*255*2) + 5000;
creMinActive = true;
setExtremeState(CREMINDELAYTIME);
bufferedOut.println("min create threshold difference");
digitalWrite(REDPIN, HIGH); //yellow led
digitalWrite(GREENPIN, HIGH);
digitalWrite(BLUEPIN, LOW);
}
// else if(create <= 0){
// create = 0; // neutral or non-overthreshold state does not run the pump; non-extreme min
// // no special effect, just smth to help define mappings of speed later
// }
}
// --------PUMPS--------
// ---SPEED---
int setMagentaPumpSpeed(){
/*
1) interpret socialize var --> map to working speed
2) set pump to run w progressive increase alongside rest of pumps w incremental increase?
*/
int speed = 0; // off, 85 is minimum for on
speed = map(socialize, 0, SOCIALIZERANGE, 0, 255); // map the values into accepted ranges for affecting the pump running
if(speed < MINPUMPSPEED){ // minimum pump speed to run
// 1/3 of max pump speed, also minimum speed to see any water flowing
speed = 0; // will pull the pump to 0 regardless if it goes below here because its useless energy wasted on putting it below that and seeing nothing but maybe getting noise
}
// bufferedOut.print("Speed: ");
// bufferedOut.print(speed);
// bufferedOut.print(" | ");
return speed;
}
int setCyanPumpSpeed(){
int speed = 0;
if(hydrate<=0){
// for whatever reason
return speed; // 0
}
if(hydrate < midWaterDistance){
// closer water distance means higher level
return speed; // 0, no adding cyan when not thirsty (enough water)
}
else{ // btwn mid water level (neutral) and below the mid level (farther from the sensor)
speed = map(hydrate, midWaterDistance, farthestDistanceToWater, MINPUMPSPEED, 255);
// should be larger water dist for more speed
return speed;
}
}
int setYellowPumpSpeed(){
int speed = 0; // off, 85 is minimum for on
if(create <= 0){
return speed; // 0
}
else{
speed = map(create, 1, ANALOGMAX, MINPUMPSPEED, 255); // map the values into accepted ranges for affecting the pump running
// increasing min pump speed just bc the yellow rate seems not to be as significant for 85 compared to how magenta pump runs
/*if(speed < MINPUMPSPEED){ // minimum pump speed to run ; shouldnt happen w mapping
// 1/3 of max pump speed, also minimum speed to see any water flowing
speed = 0; // will pull the pump to 0 regardless if it goes below here because its useless energy wasted on putting it below that and seeing nothing but maybe getting noise
}*/
// bufferedOut.print("Speed: ");
// bufferedOut.print(speed);
// bufferedOut.print(" | ");
return speed;
}
}
// ---RUNNING---
// to turn into a function w parameters per pump, i can do pointer parameters int &engageVal [change that variable directly] - my calls just have to be precise
// void runPump(int speed, int &pumpPin, int &engageVal, millisDelay &incDelay){} // my ish is the object... crossing libraries is my doom, pointer to obejct bc don't wanna make a copy, NEED to use it as is
void runMagentaPump(int speed){
// allow the pump to constantly run and adapt its speed increase/decrease based on the speed input it gets (so it changes toward a certain scope regardless of what is was trying to get to before)
// constrain speed
if(speed > 255){
speed = 255; // pump pwm cant be more than 255
}
else if (speed < 0){
speed = 0; // pump pwm cant be less than 0 [basically an unsigned byte]
}
// will the pump be constrained to 255 and 0 this way tho? speed has to be constrained then
// constraining speed, this if state should be able to constrain engageVal to 0 and 255 as well
int increment;
if(magentaEnVal < speed){
// if the current state of the pump speed is less than the speed it is given to reach, keep incrementing
increment = 1;
}
else if(magentaEnVal > speed){
// if current state of pump speed is greater than speed intended, start decrementing
increment = -1;
}
else{
// engageVal is same as intended speed, means the program shouldnt increment anymore, but itll also stop the delay later so this can be set 0
increment = 0;
}
if(magentaIncDelay.justFinished()){
magentaIncDelay.repeat();
magentaEnVal += increment;
// bufferedOut.print("Magenta Engage Val: ");
// bufferedOut.println(magentaEngageVal);
analogWrite(MAGENTAPIN, magentaEnVal); //**should i adjust to have 0 increment not calculate or keep the delay working to keep a somewhat consistent pump rate
// i can adjust the delay here to change how fast i want the pump responding to its sensory-variables
// bufferedOut.print("Engage Val: ");
// bufferedOut.println(magentaEnVal);
}
// else{
// bufferedOut.println();
// }
}
void runCyanPump(int speed){
// allow the pump to constantly run and adapt its speed increase/decrease based on the speed input it gets (so it changes toward a certain scope regardless of what is was trying to get to before)
// constrain speed
if(speed > 255){
speed = 255; // pump pwm cant be more than 255
}
else if (speed < 0){
speed = 0; // pump pwm cant be less than 0 [basically an unsigned byte]
}
// will the pump be constrained to 255 and 0 this way tho? speed has to be constrained then
// constraining speed, this if state should be able to constrain engageVal to 0 and 255 as well
int increment;
if(cyanEnVal < speed){
// if the current state of the pump speed is less than the speed it is given to reach, keep incrementing
increment = 1;
}
else if(cyanEnVal > speed){
// if current state of pump speed is greater than speed intended, start decrementing
increment = -1;
}
else{
// engageVal is same as intended speed, means the program shouldnt increment anymore, but itll also stop the delay later so this can be set 0
increment = 0;
}
if(cyanIncDelay.justFinished()){
cyanIncDelay.repeat();
cyanEnVal += increment;
// bufferedOut.print("Magenta Engage Val: ");
// bufferedOut.println(magentaEngageVal);
analogWrite(CYANPIN, cyanEnVal); //**should i adjust to have 0 increment not calculate or keep the delay working to keep a somewhat consistent pump rate
// i can adjust the delay here to change how fast i want the pump responding to its sensory-variables
// bufferedOut.print("Engage Val: ");
// bufferedOut.println(cyanEnVal);
}
// else{
// bufferedOut.println();
// }
}
void runYellowPump(int speed){
// allow the pump to constantly run and adapt its speed increase/decrease based on the speed input it gets (so it changes toward a certain scope regardless of what is was trying to get to before)
// constrain speed
if(speed > 255){
speed = 255; // pump pwm cant be more than 255
}
else if (speed < 0){
speed = 0; // pump pwm cant be less than 0 [basically an unsigned byte]
}
// will the pump be constrained to 255 and 0 this way tho? speed has to be constrained then
// constraining speed, this if state should be able to constrain engageVal to 0 and 255 as well
int increment;
if(yellowEnVal < speed){
// if the current state of the pump speed is less than the speed it is given to reach, keep incrementing
increment = 1;
}
else if(yellowEnVal > speed){
// if current state of pump speed is greater than speed intended, start decrementing
increment = -1;
}
else{
// engageVal is same as intended speed, means the program shouldnt increment anymore, but itll also stop the delay later so this can be set 0
increment = 0;
}
if(yellowIncDelay.justFinished()){
yellowIncDelay.repeat();
yellowEnVal += increment;
// bufferedOut.print("Magenta Engage Val: ");
// bufferedOut.println(magentaEngageVal);
analogWrite(YELLOWPIN, yellowEnVal); //**should i adjust to have 0 increment not calculate or keep the delay working to keep a somewhat consistent pump rate
// i can adjust the delay here to change how fast i want the pump responding to its sensory-variables
// bufferedOut.print("Engage Val: ");
// bufferedOut.println(yellowEnVal);
}
// else{
// bufferedOut.println();
// }
}
// --------WATER HANDLING--------
// NOTE: need to regularly REMOVE water from the program each loop to avoid overflow (only blocked when any of the min/max functions besides create happens)
void waterChange(int speed, bool reversePolarity){
// constrain speed
if(speed > 255){
speed = 255; // pump pwm cant be more than 255
}
else if (speed < 0){
speed = 0; // pump pwm cant be less than 0 [basically an unsigned byte]
}
// set speed to the appropriate wire based on polarity setting
int addInSpeed;
int rmvInSpeed;
if(reversePolarity){
if(waterAddInVal > 0){ // if the opposite input is not 0 yet, don't allow current flows
addInSpeed = 0; // input 1 needs to be 0 b4 reversing polarity to inc input 2
rmvInSpeed = 0; // no speed change until input 1 is 0
}
else{
addInSpeed = 0;
rmvInSpeed = speed;
}
}
else{
if(waterRmvInVal > 0){
addInSpeed = 0; // no speed change until input 2 is 0
rmvInSpeed = 0; // input 2 needs to be 0 b4 polarity to reg to inc input 1
}
else{
addInSpeed = speed;
rmvInSpeed = 0;
}
}
// set the increment for changing input val
int addIncrement;
int rmvIncrement;
// INPUT 2
if(waterAddInVal < addInSpeed){
// if the current state of the pump speed is less than the speed it is given to reach, keep incrementing
addIncrement = 1;
}
else if(waterAddInVal > addInSpeed){
// if current state of pump speed is greater than speed intended, start decrementing
addIncrement = -1;
}
else{
// engageVal is same as intended speed, means the program shouldnt increment anymore, but itll also stop the delay later so this can be set 0
addIncrement = 0;
}
// INPUT 2
if(waterRmvInVal < rmvInSpeed){
// if the current state of the pump speed is less than the speed it is given to reach, keep incrementing
rmvIncrement = 1;
}
else if(waterRmvInVal > rmvInSpeed){
// if current state of pump speed is greater than speed intended, start decrementing
rmvIncrement = -1;
}
else{
// engageVal is same as intended speed, means the program shouldnt increment anymore, but itll also stop the delay later so this can be set 0
rmvIncrement = 0;
}
if(waterRmvInVal > 0 && waterAddInVal > 0){ // shouldnt happen but just in case [both inputs should NOT be going on at the same time]
// addInSpeed = 0;
// rmvInSpeed = 0;
addIncrement = -1;
rmvIncrement = -1;
// switchSystemState(); // something wrong w system if both are on, but switchSystemState should happen only when both can be at 0
}
if(waterIncDelay.justFinished()){
waterIncDelay.repeat();
waterAddInVal += addIncrement;
waterRmvInVal += rmvIncrement;
// bufferedOut.print("Magenta Engage Val: ");
// bufferedOut.println(magentaEngageVal);
analogWrite(WATERADDIN, waterAddInVal);
analogWrite(WATERRMVIN, waterRmvInVal); //**should i adjust to have 0 increment not calculate or keep the delay working to keep a somewhat consistent pump rate
// i can adjust the delay here to change how fast i want the pump responding to its sensory-variables
// bufferedOut.print("Engage Val: ");
// bufferedOut.println(yellowEnVal);
}
}