I have been working on this code for a while, hoping whatever I am missing is simple. Basically what I want to do is when I turn on my car, it turns on an output unless the car is moving of which it then disables the output. I pretty much got this far without much issue but now I want to add to the code and when the car is turned off, the output is enabled (High) for 20min then goes off (Low) and stays there until the car turns on again. See code below. The last part in bold I know is wrong but I can't figure out what should be here to achieve the last step. Thanks
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
int switchState = 0;
Adafruit_MPU6050 mpu;
void setup(void) {
Serial.begin(115200);
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 Found!");
// set accelerometer range to +-8G
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// set gyro range to +- 500 deg/s
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
// set filter bandwidth to 21 Hz
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
delay(100);
pinMode(13, OUTPUT);
pinMode(2, INPUT);
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
/* Print out the values */
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");
Serial.println("");
delay(500);
switchState = digitalRead(2);
if (switchState == LOW){ //Initiates program when car ignition is on
} else if(abs(a.acceleration.x) + abs(a.acceleration.y) + abs(a.acceleration.z) > 13.0){
digitalWrite(13, LOW); //If car is moving, disables Pin 13 turning off light
delay(1000);
}else{
digitalWrite(13, HIGH); //If car is not moving, enables Pin 13 turning on light
}
**if (switchState == HIGH){ //My attempt to to turn off Pin 13 once ignition is off**
}
digitalWrite(13, LOW);
}
If you're going to do something involving twenty minutes, you will need to use millis to record when you last saw that the ignition was on. Then you can check if it's more than that long ago and turn off.
How is the Arduino is powered, and how is pin 2 determining the car is on or off?
Two of your if/else blocks are empty.
This
digitalWrite(13, LOW);
is just at the bottom of loop(), where it gets executed every time loop() does. Loop.
So perhaps if you posted the best version of something that worked well, but does not yet have the additional feature you are trying to add, it would be easier to see what you need to do.
Also this
digitalWrite(13, LOW); //If car is moving, disables Pin 13 turning off
is a bit confusing. What do HIGH and LOW mean when on pin 13? I know lighting the build-in LED, but what is the interpretation?
The Adruino will be powered off of the battery, it doesn't put hardly any current so it can just stay live 24/7. Pin 2 would be connected to a source that is only live when the car is in accessory mode (turned on or running). I haven't diagramed out yet if this will be a relay or what but that is minor at this point.
If car stops moving? Light goes back on? or does it stay off once car has moved?
the light comes (or stays) on for 20 minutes after the car turns OFF.
Sry if I could glean this from rereading and reading again your description, but if you can confirm this (or fix it in the same style) it will help. Me anyways.
Updated code. Added the last line and a delay. I thought I could just add the delay here for keeping the light on for 10-20min but using delay in the code is screwing with other parts of it and hangs the code which is a problem because if the switchstate changes while this is processing the delay then it is ignored....so I may use an external delay unless I can figure out how to code for this. Thanks for everyone's help thus far.
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
int switchState = 0;
Adafruit_MPU6050 mpu;
void setup(void) {
Serial.begin(115200);
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 Found!");
// set accelerometer range to +-8G
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// set gyro range to +- 500 deg/s
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
// set filter bandwidth to 21 Hz
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
delay(100);
pinMode(13, OUTPUT);
pinMode(2, INPUT);
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
/* Print out the values */
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");
Serial.println("");
delay(500);
switchState = digitalRead(2);
if (switchState == LOW){} //Initiates program when car ignition is on
else if(abs(a.acceleration.x) + abs(a.acceleration.y) + abs(a.acceleration.z) > 13.0)
{
digitalWrite(13, LOW); //If car is moving, disables Pin 13 turning off light
delay(1000);
}
else{digitalWrite(13, HIGH); //If car is not moving, enables Pin 13 turning on light
}
if (switchState == HIGH){} //If car ignition is off
else
{
delay(100);
digitalWrite(13, LOW);
}
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
Serial.println("Print out the values removed for now");
delay(500);
switchState = digitalRead(2);
if (switchState == HIGH) //If car ignition is on
{
if (abs(a.acceleration.x) + abs(a.acceleration.y) + abs(a.acceleration.z) > 13.0)
{
digitalWrite(13, LOW); //If car is moving turn off light
delay(1000);
}
else
{
digitalWrite(13, HIGH); // If car is not moving turn on light
}
}
if (switchState == LOW) // If car ignition is off
{
delay(100);
digitalWrite(13, LOW);
}
}
I find it easier to read when you aren't including {} empty statements and therefor reverse logic. The above is identical in function to your latest code.
I assume the delay(100); in the "if ignition is off" section is where you tried a delay of 20 minutes.
Your analysis of why this won't work satisfactorily is correct.
It's too late here for me to help more right now. Soon enough ppl are going to be telling you about "state machines", also know as "finite-state machines" or FSMs.
If you want to get a head start, google those terms and poke around a bit. See if you get some inspiration. Don't be intimidated, it is hard only until it is easy. You can look at them in general, or google a bit harder and find dozens of Arduino examples.
I encourage you to stay the course with code. Adding an external delay device might be more in your comfort zone right now, but if you are planning on going any further with programming, this is an ideal and simple case to be solved with an FSM.
Part of it will be getting very specific about the way your system is to respond to all the different conditions that may obtain. Which was why I asked at least one question I could not discern from going over your prose, and why I asked you to verify my understanding of your requirements. Long english descriptions can be, or seem, ambiguous or underspecified. I did, trust me, "see above".
Maybe below pseudo code can get you on the right track
void loop()
{
// variable to remember the last time that a movement was detected
static uint32_t lastMovementTime;
// if a movement was detected
if(movementCondition == true)
{
// 'reset' the timer
lastMovementTime = millis();
}
// if no movement detected for someDuration
if(millis() - lastMovementTime > someDuration)
{
// do what needs to be done
}
}
/*
https://forum.arduino.cc/t/disable-output-at-end-of-code-using-a-timer/900440
Basically what I want to do is when I turn on my car,
it turns on an output unless the car is moving of which it then disables the output.
I want to add to the code and when the car is turned off, the output is enabled (High) for 20min then goes off (Low)
and stays there until the car turns on again.
example for a finite state machine
*/
enum class State {OFF, // car is closed for longer than n minutes
IGNITION, // ignition on
MOVING, // car moves
STOPPED // car was stopped, timer is running
} state;
int switchState = 0;
bool isCarMoving = false;
const byte outputPin = 13;
const byte ignitionPin = A0;
const byte sensorPin = A1; // others might not have a sensor
const uint32_t interval = 1 * 60 * 1000UL; // durance of the nonblocking delay - should be finally 20 * 60 * 1000UL
void setup(void) {
Serial.begin(115200);
pinMode(outputPin, OUTPUT);
pinMode(ignitionPin, INPUT); // HIGH active
pinMode(sensorPin, INPUT); // HIGH active
}
void loop() {
switchState = digitalRead(ignitionPin);
isCarMoving = digitalRead(sensorPin); // replace this with reading MPU6050
static State previousState = State::OFF;
static uint32_t previousMillis = 0;
switch (state)
{
case State::OFF :
// e.g. blink a security LED here ...
// otherwise - just do nothing
break;
case State::IGNITION :
if (isCarMoving)
{
Serial.println(F("unless the car is moving of which it then disables the output."));
digitalWrite(outputPin, LOW);
state = State::MOVING;
}
if (digitalRead(outputPin) == LOW)
{
Serial.println(F("I want to do is when I turn on my car, it turns on an output"));
digitalWrite(outputPin, HIGH);
}
break;
case State::MOVING :
if (switchState == LOW)
{
Serial.println(F("when the car is turned off, the output is enabled (High)"));
// start timer
previousMillis = millis();
digitalWrite(outputPin, HIGH);
state = State::STOPPED;
}
break;
case State::STOPPED :
if (millis() - previousMillis > interval)
{
Serial.println(F("for 20min then goes off (Low) and stays there until the car turns on again"));
digitalWrite(outputPin, LOW);
state = State::OFF;
}
break;
}
}
This should get you close... In order to speed up loop(), I also removed the delay(500) and only spit out the data every second. You can also adjust the delayTime for testing purposes, unless you like to hang around for 20 minutes
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
const int ignitionPin = 2;
const int outputPin = 13;
const float accTriggerLevel = 13.0;
const unsigned long delayTime = 1000UL * 60 * 20; // twenty minutes
unsigned long startTime;
enum { CAR_OFF, CAR_IDLE, CAR_MOVING, CAR_STOPPED, CAR_DELAY_OFF };
int state;
Adafruit_MPU6050 mpu;
void setup(void) {
Serial.begin(115200);
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 Found!");
// set accelerometer range to +-8G
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// set gyro range to +- 500 deg/s
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
// set filter bandwidth to 21 Hz
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
delay(100);
pinMode(outputPin, OUTPUT);
pinMode(ignitionPin, INPUT);
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
static unsigned long lastReportTime;
// only report every second
if ( millis() - lastReportTime >= 1000 ) {
lastReportTime = millis();
/* Print out the values */
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");
Serial.println("");
}
float totalAcc = abs(a.acceleration.x) + abs(a.acceleration.y) + abs(a.acceleration.z);
int ignitionState = digitalRead(ignitionPin);
switch ( state ) {
case CAR_OFF:
// car is off, check to see if it is on and react
digitalWrite(outputPin, LOW);
if ( ignitionState == HIGH ) {
// car is on
digitalWrite(outputPin, HIGH);
state = CAR_IDLE;
}
break;
case CAR_IDLE:
// car is ON but not moving
if (totalAcc > accTriggerLevel) {
state = CAR_MOVING;
}
if (ignitionState == LOW ) {
// car turned off
state = CAR_OFF;
}
break;
case CAR_MOVING:
digitalWrite(outputPin, LOW);
if (totalAcc <= accTriggerLevel) {
// car has stopped
state = CAR_STOPPED;
}
break;
case CAR_STOPPED:
if (totalAcc > accTriggerLevel) {
state = CAR_MOVING;
}
if (ignitionState == LOW ) {
// car turned off
state = CAR_DELAY_OFF;
startTime = millis();
digitalWrite(outputPin, HIGH);
}
break;
case CAR_DELAY_OFF:
// check timer and, if expired, we are OFF
if ( millis() - startTime >= delayTime ) {
state = CAR_OFF;
}
if (ignitionState == HIGH) {
// car turned back on so reset
state = CAR_OFF;
}
break;
}
}
okay, if you can notice that small of a blink on a corner case...
case CAR_DELAY_OFF:
// check timer and, if expired, we are OFF
if ( millis() - startTime >= delayTime ) {
state = CAR_OFF;
}
if (ignitionState == HIGH) {
// car turned back on so reset
state = CAR_IDLE;
}
break;
You can click on the accelerometer to simulate motion.
# include <Adafruit_MPU6050.h>
# include <Adafruit_Sensor.h>
# include <Wire.h>
const int ignitionPin = 2;
const int outputPin = 13;
const float accTriggerLevel = 13.0;
// const unsigned long delayTime = 1000UL * 60 * 20; // twenty minutes
const unsigned long delayTime = 1000UL * 5; // five seconds
unsigned long startTime;
enum { CAR_OFF, CAR_IDLE, CAR_MOVING, CAR_STOPPED, CAR_DELAY_OFF };
int state;
Adafruit_MPU6050 mpu;
void setup(void) {
Serial.begin(115200);
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 Found!");
// set accelerometer range to +-8G
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// set gyro range to +- 500 deg/s
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
// set filter bandwidth to 21 Hz
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
delay(100);
pinMode(outputPin, OUTPUT);
pinMode(ignitionPin, INPUT_PULLUP);
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
static unsigned long lastReportTime;
// only report every second
if ( millis() - lastReportTime >= 5000 ) {
lastReportTime = millis();
/* Print out the values
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");
Serial.println("");
*/
}
float totalAcc = abs(a.acceleration.x) + abs(a.acceleration.y) + abs(a.acceleration.z);
int ignitionState = digitalRead(ignitionPin);
switch ( state ) {
case CAR_OFF:
// car is off, check to see if it is on and react
if ( ignitionState == HIGH ) {
// car is on
digitalWrite(outputPin, HIGH);
state = CAR_IDLE;
}
else digitalWrite(outputPin, LOW);
break;
case CAR_IDLE:
// car is ON but not moving
if (totalAcc > accTriggerLevel) {
state = CAR_MOVING;
}
if (ignitionState == LOW ) {
// car turned off
state = CAR_DELAY_OFF;
startTime = millis();
}
break;
case CAR_MOVING:
digitalWrite(outputPin, LOW);
if (totalAcc <= accTriggerLevel) {
// car has stopped
state = CAR_STOPPED;
}
break;
case CAR_STOPPED:
if (totalAcc > accTriggerLevel) {
state = CAR_MOVING;
Serial.println("car moving again");
}
if (ignitionState == LOW ) {
// car turned off
state = CAR_DELAY_OFF;
startTime = millis();
digitalWrite(outputPin, HIGH);
}
else digitalWrite(outputPin, HIGH);
break;
case CAR_DELAY_OFF:
// check timer and, if expired, we are OFF
if ( millis() - startTime >= delayTime ) {
state = CAR_OFF;
}
if (ignitionState == HIGH) {
// car turned back on so reset
state = CAR_OFF;
}
break;
}
}