need motors to only run once while pir is active

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 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.

There is an example of state change detection in the IDE.

How you detect that the motor has made on turn is an other question.

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.

yes, if there is no movement from 30-45 seconds I want the fan to shut off and return to position even if temp is still above the threshold.

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.*

678583 state diagram.png

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.

678583 state diagram.png

Made a slight edit to the text above for clarity, see (edit) in italics.

And I forgot to add this: switch...case

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

This is the diagram for the simpler state machine code above.

678583 state diagram_v2.png

678583 state diagram_v2.png

Thank you so much! I think this is exactly what I needed

jcwahl86:
I think this is exactly what I needed

Well there's only one way to find out :wink: and that's to test it....