Hi, I'm trying to figure out how to make this project function the way I want.
I have a motion-activated temperature-controlled fan on wheels. When the PIR is activated I want the wheels to move forward for about 6-12 inches or 3-4 seconds. After the wheels stop, I want to run the fan if the temperature is above a certain level and the fan to stay in place. If the PIR does not see any motion for 30-45 seconds I want the fan to turn off and roll back to the original position.
At the moment I have my code and the wheels constantly roll back a forth.
Code is a little jumbled because multiple people working on it
Thank you
#define IN1 7 //K1、K2 Wheels
#define IN2 8 //K1、K2 Wheels
#define MotorA 9 //K3、K4 Fan
#define MotorB 10 //K3、K4 Fan
#define ENA 5 // Needs to be a PWM pin to be able to control motor speed ENA
#define ENB 6 // Needs to be a PWM pin to be able to control motor speed ENA
int Pir = 1; //pin for PIR sensor.
int Activate = 0; //Variable to state if PIR is triggered or not.
float Tempsens = A2; //Pin for temperature sensor
float Temperature = 0; //Dummy variable will be set to temperature
float TempVolt = 0; //Dummy variable
float TempRead = 0; //Dummy variable
float CtoF = 0; //Dummy variable to facilitate convertion from C to F
//Pin setup and variables for Pontentiometer
//This nob will determing the temperature at which fan will activate
int Nob = A0; //Pin for potentiometer
int TempSet = 0; //Dummy variable for triggering temperature
int Speed = 255;
/*motor control*/
void go_ahead() //motor rotate clockwise -->robot go ahead
{
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
}
void go_back() //motor rotate counterclockwise -->robot go back
{
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
}
void go_stop() //motor brake -->robot stop
{
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
}
/*set motor speed */
void set_motorspeed(int lspeed, int rspeed) //change motor speed
{
analogWrite(ENA, lspeed); //lspeed:0-255
analogWrite(ENB, rspeed); //rspeed:0-255
}
void setup() {
/******L298N******/
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(MotorA, OUTPUT);
pinMode(MotorB, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(Pir, INPUT);
pinMode(Tempsens, INPUT);
pinMode(Nob, INPUT);
}
void loop() {
// put your main code here, to run repeatedly:
//Get ambient temperature
TempRead = analogRead(Tempsens); //This Variable gets the direct reading from sensor
TempVolt = TempRead * 5 / 1025;
CtoF = ((TempVolt - .5) * 100); // Temperature in Celcius
Temperature = (1.8 * CtoF) + 32 ; // Temperature in Farenheit
Serial.println(Temperature);
//Get the triggering temperature from the nob
//The temperature range will be from 50 Degrees to 102
TempSet = 50 + (analogRead(Nob) * .1023) / 2;
Serial.println(TempSet);
//Check if motion sensor is being triggered.
//Check if motor should be on based on ambient temperature and triggering temperature
//Start motor at Default Speed
Activate = digitalRead(Pir);
Serial.println(Activate);
if ((Activate == 1) && (Temperature >= TempSet))
{
set_motorspeed(127, 127);
//go ahead 5s
go_ahead();
delay(1000);
go_stop();
delay(1000);
analogWrite(ENB, Speed);
digitalWrite(MotorA, HIGH);
digitalWrite(MotorB, LOW);
delay(20);
}
else
{
analogWrite(ENB, 0);
delay(2000);
set_motorspeed(127, 127);
//go back 5s
go_back();
delay(1000);
go_stop();
delay(1000);
}
}
I am really bored so might do this coding just for S&Gs.
Clarity required though. Does this ...
After the wheels stop, I want to run the fan if the temperature is above a certain level and the fan to stay in place. If the PIR does not see any motion for 30-45 seconds I want the fan to turn off and roll back to the original position.
... mean that if there's no movement for 30-45 seconds after reaching the destination and the temp is still over, the fan must still go off and the car returns?
I think that you will need a state change detection for the pir sensor.
You want to react when the sensor becomes active, not when it is active.
This adafruit tut explains how to get a pir to tell you there is "new" movement.
Based on what you've said above, this problem is very similar to the one I was having a few days ago, and its a state change problem as mentioned in replies #1 and #2. Please see my topic PIR which describes how to resolve the issue.
I would code that as a state machine as shown below, probably using a switch..case with a variable called say currentState. So for example in the first state (= case in the switch..case) where it starts, only monitor the motion pin, and if there's movement (edit) switch to the next case and run the motor/s forward for 3-4 seconds.*
I managed to find my pir sensor in the clutter and may have a go at coding this today (0530 Monday here, coffee underway....)
that's not a reliable way of positioning the machine. Say the wheels slipped a little on the way out, but didn't slip on the way back it would over-shoot its home. But that might be another discussion.
Have a look at the code below, which follows my state diagram from earlier.
Run it with the serial monitor open- there are debug prints to let you know what state it’s in.
Important notes
I just used a pot as a mimic for the temperature, and just check if it’s under or over 500
I didn’t do your motor stuff with speed and enable pins; I just tested with 2 leds, one forward one backward
I used pin 13’s led as a sort of proof-of-life pulse so you can check nothing’s blocked. Also handy for counting the seconds while the motor runs or waiting for the 35s timeout
I used an led on pin 7 to always show what the pir output is.
Also, my pir sensor has no adjustment pots at all. Its output is high with motion, and it goes low about 12-13s after motion stops. So to get your 35 seconds of no motion, I wait 22 to make up the difference.
// https://forum.arduino.cc/index.php?topic=678583
// see state diagram in post #5 there
// 20 apr 2020
/*
I [jcwahl86] have a motion-activated temperature-controlled fan on wheels.
When the PIR is activated I want the wheels to move forward for
about 6-12 inches or 3-4 seconds. After the wheels stop, I want to run
the fan if the temperature is above a certain level and the fan to
stay in place. If the PIR does not see any motion for 30-45 seconds
I want the fan to turn off and roll back to the original position.
*/
// my pir goes high on movement, goes low about 13s after movement stops
const byte pirPin = 3;
const byte movementLed = 7;
bool pirVal;
unsigned long lastTimeThereWasMovement;
//*** NOTE: my pir output goes low after about 13s of no motion
// so we need to see if it's been low for about 22 to make 35 total
long noMovementTimeout = 22000;
//motors and fans
const byte motorForward = 8;
const byte motorBackward = 9;
unsigned long startedMotorAt;
int runMotorFor = 4000; //but this is a very unreliable way of positioning the trolley
const byte fan = 10;
const byte tempSensor = A0;
const byte fanThreshold = 500; // I don't have an actual sensor, just using a pot over/under
//states
enum {ST_home, ST_moving_out, ST_out, ST_fan_on, ST_moving_back} currentState = ST_home;
// ala https://www.gammon.com.au/statemachine
//pulse, to prove there's no blocking
unsigned long previousPulse;
bool pulseState;
int pulseInterval = 500;
void setup()
{
// initialize serial communication:
Serial.begin(9600);
Serial.println("setup() ... ");
Serial.println("*** 678583 ***");
Serial.print("Compiler: ");
Serial.print(__VERSION__);
Serial.print(", Arduino IDE: ");
Serial.println(ARDUINO);
Serial.print("Created: ");
Serial.print(__TIME__);
Serial.print(", ");
Serial.println(__DATE__);
Serial.println(__FILE__);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, pulseState);
pinMode(motorForward, OUTPUT);
pinMode(motorBackward, OUTPUT);
pinMode(fan, OUTPUT);
pinMode(movementLed, OUTPUT);
Serial.println("setup() done");
Serial.println(" ");
Serial.println("State: home");
}
void loop()
{
pirVal = digitalRead(pirPin);
digitalWrite(movementLed, pirVal); //always show what the pir's thinking...
//Serial.println(pirVal);
manageStates();
doPulse();
} //loop
void manageStates()
{
switch (currentState) //ST_home, ST_moving_out, ST_out, ST_fan_on, ST_moving_back
{
case ST_home:
if (pirVal) //if there's movement, run the trolley out
{
Serial.println("State: moving out");
currentState = ST_moving_out;
digitalWrite(motorForward, HIGH);
startedMotorAt = millis();
}
break;
case ST_moving_out:
if (millis() - startedMotorAt >= (unsigned long) runMotorFor) //if run long enough, stop
{
Serial.println("State: out");
currentState = ST_out;
digitalWrite(motorForward, LOW);
}
break;
case ST_out:
if (analogRead(tempSensor) >= fanThreshold) //if over temp, run fan
{
Serial.println("State: fan on");
currentState = ST_fan_on;
digitalWrite(fan, HIGH);
}
checkNoMotion(); //and run back if none
break;
case ST_fan_on:
if (analogRead(tempSensor) < fanThreshold) //if under temp, turn fan off
{
Serial.println("State: out");
currentState = ST_out;
digitalWrite(fan, LOW);
}
checkNoMotion(); //and run back if none (even if the fan is on....)
break;
case ST_moving_back:
if (millis() - startedMotorAt >= (unsigned long) runMotorFor) //if run long enough, stop
{
Serial.println("State: home");
currentState = ST_home;
digitalWrite(motorBackward, LOW);
}
break;
}//switch
}//manageStates
void checkNoMotion()
{
if (pirVal == HIGH)// we want to time the low
{
lastTimeThereWasMovement = millis(); //so continually reset clock if high
}
if (millis() - lastTimeThereWasMovement >= noMovementTimeout)
{
Serial.println("State: moving back");
currentState = ST_moving_back;
digitalWrite(motorBackward, HIGH);
digitalWrite(fan, LOW); //might be going direct from ST_fan_on
startedMotorAt = millis();
}
}//check no motion
void doPulse()
{
if (millis() - previousPulse >= (unsigned long) pulseInterval)
{
previousPulse = millis();
pulseState = !pulseState;
digitalWrite(LED_BUILTIN, pulseState);
}
}//do pulse
Could probably ditch the fan on state by the way, and just turn the fan on and off inside the out state. I just put it in for completeness, in case other stuff needs to happen that is not known (to me) yet.
The code below dispenses with that extra state.
// https://forum.arduino.cc/index.php?topic=678583
// see state diagram in post #5 there
// 20 apr 2020
// ********* V2 does away with the separate "fan" state
/*
I [jcwahl86] have a motion-activated temperature-controlled fan on wheels.
When the PIR is activated I want the wheels to move forward for
about 6-12 inches or 3-4 seconds. After the wheels stop, I want to run
the fan if the temperature is above a certain level and the fan to
stay in place. If the PIR does not see any motion for 30-45 seconds
I want the fan to turn off and roll back to the original position.
*/
// my pir goes high on movement, goes low about 13s after movement stops
const byte pirPin = 3;
const byte movementLed = 7;
bool pirVal;
unsigned long lastTimeThereWasMovement;
//*** NOTE: my pir output goes low after about 13s of no motion
// so we need to see if it's been low for about 22 to make 35 total
long noMovementTimeout = 22000;
//motors and fans
const byte motorForward = 8;
const byte motorBackward = 9;
unsigned long startedMotorAt;
int runMotorFor = 4000; //but this is a very unreliable way of positioning the trolley
const byte fan = 10;
const byte tempSensor = A0;
const byte fanThreshold = 500; // I don't have an actual sensor, just using a pot over/under
//states
enum {ST_home, ST_moving_out, ST_out, ST_moving_back} currentState = ST_home;
// ala https://www.gammon.com.au/statemachine
//pulse, to prove there's no blocking
unsigned long previousPulse;
bool pulseState;
int pulseInterval = 500;
void setup()
{
// initialize serial communication:
Serial.begin(9600);
Serial.println("setup() ... ");
Serial.println("*** 678583 ***");
Serial.print("Compiler: ");
Serial.print(__VERSION__);
Serial.print(", Arduino IDE: ");
Serial.println(ARDUINO);
Serial.print("Created: ");
Serial.print(__TIME__);
Serial.print(", ");
Serial.println(__DATE__);
Serial.println(__FILE__);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, pulseState);
pinMode(motorForward, OUTPUT);
pinMode(motorBackward, OUTPUT);
pinMode(fan, OUTPUT);
pinMode(movementLed, OUTPUT);
Serial.println("setup() done");
Serial.println(" ");
Serial.println("State: home");
}
void loop()
{
pirVal = digitalRead(pirPin);
digitalWrite(movementLed, pirVal); //always show what the pir's thinking...
//Serial.println(pirVal);
manageStates();
doPulse();
} //loop
void manageStates()
{
switch (currentState) //ST_home, ST_moving_out, ST_out, ST_fan_on, ST_moving_back
{
case ST_home:
if (pirVal) //if there's movement, run the trolley out
{
Serial.println("State: moving out");
currentState = ST_moving_out;
digitalWrite(motorForward, HIGH);
startedMotorAt = millis();
}
break;
case ST_moving_out:
if (millis() - startedMotorAt >= (unsigned long) runMotorFor) //if run long enough, stop
{
Serial.println("State: out");
currentState = ST_out;
digitalWrite(motorForward, LOW);
}
break;
case ST_out:
if (analogRead(tempSensor) >= fanThreshold) //if over temp, run fan
{
digitalWrite(fan, HIGH);
}
else
{
digitalWrite(fan, LOW);
}
checkNoMotion(); //and run back if none
break;
case ST_moving_back:
if (millis() - startedMotorAt >= (unsigned long) runMotorFor) //if run long enough, stop
{
Serial.println("State: home");
currentState = ST_home;
digitalWrite(motorBackward, LOW);
}
break;
}//switch
}//manageStates
void checkNoMotion()
{
if (pirVal == HIGH)// we want to time the low
{
lastTimeThereWasMovement = millis(); //so continually reset clock if high
}
if (millis() - lastTimeThereWasMovement >= (unsigned long) noMovementTimeout)
{
Serial.println("State: moving back");
currentState = ST_moving_back;
digitalWrite(motorBackward, HIGH);
digitalWrite(fan, LOW); //might be on
startedMotorAt = millis();
}
}//check no motion
void doPulse()
{
if (millis() - previousPulse >= (unsigned long) pulseInterval)
{
previousPulse = millis();
pulseState = !pulseState;
digitalWrite(LED_BUILTIN, pulseState);
}
}//do pulse