what to do with unstable ultrasonic sensor values - arduino

building a poop box for my cat with automatic door.
im using an HC-SR04 ultrasonic sensor with Arduino mega.
i have a sensor inside of an enclosed box(to sense if my cat is stuck inside, or stay open while cat is inside)
the inside sensor will fluctuate 67-68cm most of the time, however randomly it will throw in a value significantly less like 50cm, which in my program is designed to open up because it passed a threashold for 'nothing to be inside' and because of this my door keeps opening. how do i get around this.
my only solutions in my head is:
adding approx 5-10 sets of value in an array and take the average(since its scanning fast enough)
any other solutions? thanks :)

These random values could be nothing but noise as your receiver may be sensing other source of ultra sound.
Here is an example, where I take multiple readings (poop_measurements measurements) and then take the average over it:
long getDuration() {
digitalWrite(TRIGGER, LOW);
delayMicroseconds(10);
digitalWrite(TRIGGER, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER, LOW);
return pulseIn(ECHO, HIGH);
}
void loop() {
float duration = 0, distance = 0;
int poop_measurements = 10;
for (int i = 0; i < poop_measurements; i++) {
duration += getDuration();
}
duration = duration/poop_measurements;
distance = (duration / 2) / 29.1;
if (distance < 30 ){
digitalWrite(RELAY, HIGH);
} else{
digitalWrite(RELAY, LOW);
}
Serial.print("CM: ");
Serial.println(distance);
}

Related

Pulsein() function blocks other tasks from running silmultaneously

I am using a zumo bot with a reflectance sensor used to follow a black line. I want to use an arduino to make the zumo bot stop once it gets a certain distance from an obstacle.
I have an ultrasonic sensor (HC-SR04) which ive connected to the bot.
Both of these tasks work independently but once i merge the code together(so it follows the line aswell as stoping when it detects an object using the ultrasonic sensor), it doesn't work properly.. (the zumo bot no longer follows the line)
I THINK it is to do with the pulsein() function blocking any other tasks but not sure.
My code is below. Can anyone help please?
#include <ZumoShield.h>
ZumoBuzzer buzzer;
ZumoReflectanceSensorArray reflectanceSensors;
ZumoMotors motors;
Pushbutton button(ZUMO_BUTTON);
int lastError = 0;
// This is the maximum speed the motors will be allowed to turn.
// (400 lets the motors go at top speed; decrease to impose a speed limit)
const int MAX_SPEED = 400;
#define echoPin A4
#define trigPin A5
// defines variables
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
void setup()
{
reflectanceSensors.init();
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
// Initialize the reflectance sensors module
// Wait for the user button to be pressed and released
button.waitForButton();
// Turn on LED to indicate we are in calibration mode
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
// Wait 1 second and then begin automatic sensor calibration
// by rotating in place to sweep the sensors over the line
delay(1000);
int i;
for(i = 0; i < 80; i++)
{
if ((i > 10 && i <= 30) || (i > 50 && i <= 70))
motors.setSpeeds(-200, 200);
else
motors.setSpeeds(200, -200);
reflectanceSensors.calibrate();
// Since our counter runs to 80, the total delay will be
// 80*20 = 1600 ms.
delay(20);
}
motors.setSpeeds(0,0);
// Turn off LED to indicate we are through with calibration
digitalWrite(13, LOW);
// Wait for the user button to be pressed and released
button.waitForButton();
Serial.begin(9600); // // Serial Communication is starting with 9600 of baudrate speed
Serial.println("Ultrasonic Sensor HC-SR04 Test"); // print some text in Serial Monitor
Serial.println("with Arduino UNO R3");
}
void loop()
{
unsigned int sensors[6];
// Get the position of the line. Note that we *must* provide the "sensors"
// argument to readLine() here, even though we are not interested in the
// individual sensor readings
int position = reflectanceSensors.readLine(sensors);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Our "error" is how far we are away from the center of the line, which
// corresponds to position 2500.
int error = position - 2500;
// Get motor speed difference using proportional and derivative PID terms
// (the integral term is generally not very useful for line following).
// Here we are using a proportional constant of 1/4 and a derivative
// constant of 6, which should work decently for many Zumo motor choices.
int speedDifference = error / 4 + 6 * (error - lastError);
lastError = error;
// Get individual motor speeds. The sign of speedDifference
// determines if the robot turns left or right.
int m1Speed = MAX_SPEED + speedDifference;
int m2Speed = MAX_SPEED - speedDifference;
if (m1Speed < 0)
m1Speed = 0;
if (m2Speed < 0)
m2Speed = 0;
if (m1Speed > MAX_SPEED)
m1Speed = MAX_SPEED;
if (m2Speed > MAX_SPEED)
m2Speed = MAX_SPEED;
motors.setSpeeds(m1Speed, m2Speed);
//if (distance <20){
// motors.setSpeeds(0,0);
// }
////////////////////////////////////////////
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
// Displays the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
} ```
Of course pulseIn is blocking function. Arduino project is open source, you can easily check source code
Here is C equivalent countPulseASM function which does measurement.
unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops)
{
unsigned long width = 0;
// wait for any previous pulse to end
while ((*port & bit) == stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to start
while ((*port & bit) != stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to stop
while ((*port & bit) == stateMask) {
if (++width == maxloops)
return 0;
}
return width;
}
If you need measure pulse length in non blocking way, use hw counters.

Stop getting values from arduino after some time

I have a strange problem, I have Arduino UNO/MEGA and I need to get Gyro sensors's data and I want to see the data in the serial monitor. Seems like a simple task, I wrote a simple C program which collects data from Arduino through serial monitor I can see the data. Everything is working for few minutes and after that, it stops.
This code is supposed to calculate a distance travelled in a line using encoder (PID algorithm implemented using Gyroscope data for straight motion) after reaching desired position, machine takes a U-Turn.
It stop for a second after taking the U-Turn and then starts straight motion again. The problem I'm facing is that the gyroscope readings stop randomly while machine taking the turn. Due to this, the machine keeps rotating about that point without stopping.
#include <Wire.h>
#include <MPU6050.h>
MPU6050 mpu;
float timeStep = 0.01, yaw=0;
const int motor11=6;//LEFT MOTOR FW
const int motor12=7;//LEFT MOTOR BK
const int motor1pwm=3;
const int motor21=8;//RIGHT MOTOR FW
const int motor22=9;//RIGHT MOTOR BK
const int motor2pwm=5;
int flag1 = 0;
int thres1=120;//PWM Values
int thres2=120;
void setup()
{
Serial.begin(115200);
// Initialize MPU6050
while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
{
Serial.println("Could not find a valid MPU6050 sensor, check wiring!");
delay(500);
}
mpu.calibrateGyro();
mpu.setThreshold(1);
pinMode(motor11, OUTPUT);
pinMode(motor12, OUTPUT);
pinMode(motor1pwm, OUTPUT);
pinMode(motor21, OUTPUT);
pinMode(motor22, OUTPUT);
pinMode(motor2pwm, OUTPUT);
}
void loop()
{
Vector norm=mpu.readNormalizeGyro();
yaw=yaw+norm.ZAxis*timeStep;
if(flag1 == 0){
straight();
}
if(flag1 == 2){
taketurn();
}
}
void straight()
{
digitalWrite(motor11, HIGH);
digitalWrite(motor12, LOW);
analogWrite(motor1pwm, thres1);
digitalWrite(motor21, HIGH);
digitalWrite(motor22, LOW);
analogWrite(motor2pwm, thres2);
delay(8000);
flag1 = 2;
}
void taketurn()
{
float setPoint = yaw - 500;
digitalWrite(motor11, HIGH);
digitalWrite(motor12, LOW);
analogWrite(motor1pwm, 120);
digitalWrite(motor21, LOW);
digitalWrite(motor22, LOW);
analogWrite(motor2pwm, 120);
while(true)
{
Vector norm = mpu.readNormalizeGyro();
yaw = yaw + norm.ZAxis * timeStep;
Serial.print("Turning Yaw= ");
Serial.println(yaw);
if(setPoint >= yaw) {
digitalWrite(motor11, LOW);
digitalWrite(motor12, LOW);
analogWrite(motor1pwm, thres2);
digitalWrite(motor21, LOW);
digitalWrite(motor22, LOW);
analogWrite(motor2pwm, thres1);
delay(2000);
break;
}
}
flag1 = 0;
}
The serial monitor just stops displaying the reading. This does not happen every time, and it is very random. I want to get proper and continuous data. Is it a logical problem or a board problem?
Normally a random crash would indicate possibly unhandled interrupts or memory overwrite, but looking at your code and it being an Arduino program, it's unlikely to be either. I don't see any divide ops either, so you are not dividing by zero. The two possible things I see is that a) you have a "while (true)" without exit, so surely that could get you into trouble, and b) perhaps your delay functions are called with a very large value unexpectedly, and the MCU is actually just delaying a long time.

IR sensor with Arduino for restaurant parking

I have problem in the code logic, I did not find any solution.
My doubt is I'm using two IR sensor interface with Arduino, so when car is passing 1st sensor and 2nd sensor then I'm sending the data that car is passed. That is fine but whenever car1 is passing 1st sensor and another car, say car2 is in 2nd sensor, then also flag is becoming 1, that is true but I don't want that.
How to code this so that car should pass two sensors? If car 1 is in sensor 1 and car 2 is in sensor 2 than flag should not be 1.
Please find the code below:
#include<avr/wdt.h>
#define DISTANCE 100
const int trigPin1 = 7;
const int echoPin1 = 6;
const int trigPin2 = 5;
const int echoPin2 = 4;
int MOVE_FLAG = 0;
void setup() {
// initialize serial communication:
Serial.begin(9600);
MOVE_FLAG = 0;
wdt_enable(WDTO_8S);
}
void loop()
{
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration1, duration2, inches1, inches2, cm1, cm2;
// The sensor is triggered by a HIGH pulse of 10 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(trigPin1, OUTPUT);
digitalWrite(trigPin1, LOW);
delayMicroseconds(2);
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);
// Read the signal from the sensor: a HIGH pulse whose
// duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(echoPin1, INPUT);
duration1 = pulseIn(echoPin1, HIGH);
inches1 = microsecondsToInches(duration1);
cm1 = microsecondsToCentimeters(duration1);
delay(10);
pinMode(trigPin2, OUTPUT);
digitalWrite(trigPin2, LOW);
delayMicroseconds(2);
digitalWrite(trigPin2, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin2, LOW);
pinMode(echoPin2, INPUT);
duration2 = pulseIn(echoPin2, HIGH);
// convert the time into a distance
inches2 = microsecondsToInches(duration2);
cm2 = microsecondsToCentimeters(duration2);
if(cm1 <= DISTANCE && cm2 <= DISTANCE && MOVE_FLAG == 0)
{
Serial.println("3");
MOVE_FLAG = 1;
}
if (cm1 > DISTANCE && cm2 > DISTANCE && MOVE_FLAG == 1)
{
MOVE_FLAG = 0;
delay(500);
}
delay(50);
wdt_reset();
}
long microsecondsToInches(long microseconds)
{
return microseconds / 74 / 2;
}
long microsecondsToCentimeters(long microseconds)
{
return microseconds / 29 / 2;
}
Two motion sensors are inadequate to accomplish what you described. Without video or something similar, there's no way for you to know whether Car 1 triggered the sensor or Car 2 triggered the sensor.
I suggest you re-think your approach to solving the problem. You might want to look at other parking lot projects people have created and posted on the Internet. Do a Google search for "Arduino Parking Lot" or something similar.

Beginner Arduino loop function and variable

This is the revised code, the initial value is reading ridiculously high without the conversion!! How do I get the conversion to apply to the initialTemp as well temperatureC?
The code you have helped with as far as I can tell is exactly what I was trying to achieve, but obviously.
Thanks again!!
int pin_tempRead = 0; // temperature sensor pin
int coolLED = 2; // cooling LED digital pin
int heatLED = 3; // heating LED digital pin
float initialTemp;
float cutOffTemp = 30; //cut off temperature = 30°C
void setup()
{
Serial.begin(9600); //Start the serial connection with the computer
pinMode(heatLED, OUTPUT); //initialise as OUTPUT
pinMode(coolLED, OUTPUT); //initialise as OUTPUT
initialTemp = analogRead(pin_tempRead); // read the initial temp
Serial.print("Initial temperature: "); Serial.print(initialTemp); Serial.println("C"); //prints out starting temperature
}
void loop() // run over and over again
{
//getting the voltage reading from the temperature sensor
float current_temp = analogRead(pin_tempRead);
// converting that reading to voltage
float voltage = current_temp * 5.0; voltage /= 1024.0;
float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree with 500 mV offset
//to degrees ((voltage - 500mV) times 100)
if(temperatureC > cutOffTemp) {
// temp too high -> turn on the cooling system
digitalWrite(heatLED, LOW);
digitalWrite(coolLED, HIGH);
}else if (temperatureC < initialTemp) {
// temp too low -> turn on the heating system
digitalWrite(heatLED, HIGH);
digitalWrite(coolLED, LOW);
}
Serial.print("Current pump temperature: ");
Serial.print(temperatureC); Serial.println("C");
delay(1000);
}
the loop() function executes over and over, so it's not a good place to store initial values.
What you need to do is define a global variable, initialize it inside the setup() function and then you can read it in the loop() function
Minimalist example:
int pin_tempRead = 0; // temperature sensor pin
float initial_temp; // define a global variable
void setup() {
initial_temp = analogRead(pin_tempRead); // read the initial temp
}
void loop() {
float current_temp = analogRead(pin_tempRead);
// get the temperature difference respect to the initial one
float difference = initial_temp - current_temp;
delay(1000);
}
PD: Also is a good practice to distinguish the variables defining a hardware connection (pins) from the software ones. I usually append pin_ to the variables that define connections. Otherwise is not clear if tempRead is the value of the temperature or the pin where the sensor is attached.
Also, for the turning on and off of the heater/cooling system: You are already in a loop (the loop() function is a loop) so you don't need a while loop.
And you have some problem with our logic.
As I understood, you want to heat until the higher threshold (cutOff) is reached, then cool down until the lower threshold is reached (initialTemperature).
This is called Hysteresis, but your logic was wrong, here's the corrected one:
Just do:
void loop() {
if(temperatureC > cutOffTemp) {
// temp too high -> turn on the cooling system
digitalWrite(heatLED, LOW);
digitalWrite(coolLED, HIGH);
}else if (temperatureC < initialTemp) {
// temp too low -> turn on the heating system
digitalWrite(heatLED, HIGH);
digitalWrite(coolLED, LOW);
}
Serial.print("Current pump temperature: ");
Serial.print(temperatureC); Serial.println("C");
delay(1000);
}
By the way, you are using the initialTemperature as the low threshold for turning on the heating.
Is that what you really want?
What if the initial temperature is higher that the cutOffTemp? You will have problems in that case since the lower threshold is higher than the higher threshold.

Arduino Uno Avoidance Robot: One of two motors not working

I'm trying to code an Arduino avoidance robot as a learning project. When I run the following code only one motor (the left one) works. If I comment out the if statement that uses the checkDistance() function and just loop the forward() function both motors work fine. I'm using an Adafruit Motorshield v1.2, and I believe this is the motor: Link. I've tried powering directly through USB, and also through external power supply (4 x AAs), and have the same issue. Any pointers would be appreciated. Thank you!
#include <AFMotor.h>
#define trigPin 3
#define echoPin 2
AF_DCMotor left_motor(2, MOTOR12_64KHZ); // create motor #1, 64KHz pwm
AF_DCMotor right_motor(1, MOTOR12_64KHZ); // motor #2\
int maxDistance = 30;
//int minDistance = 0;
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
left_motor.setSpeed(255);
right_motor.setSpeed(255);
}
void forward(int delayTime) {
left_motor.run(FORWARD);
right_motor.run(FORWARD);
delay(delayTime);
}
void backward(int delayTime) {
left_motor.run(BACKWARD);
right_motor.run(BACKWARD);
delay(delayTime);
}
void stop(int delayTime) {
left_motor.run(RELEASE);
right_motor.run(RELEASE);
delay(delayTime);
}
void right(int delayTime) {
left_motor.run(FORWARD);
right_motor.run(BACKWARD);
delay(delayTime);
}
void left(int delayTime) {
left_motor.run(BACKWARD);
right_motor.run(FORWARD);
delay(delayTime);
}
int checkDistance(){
long duration, distance;
/* The following trigPin/echoPin cycle is used to determine the
distance of the nearest object by bouncing soundwaves off of it. */
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
//Calculate the distance (in cm) based on the speed of sound.
distance = duration/59.1;
return distance;
}
void loop() {
int currentDistance = checkDistance();
Serial.print(currentDistance);
if (currentDistance >= maxDistance){
Serial.println(" cm. No immediate obstacles detected. Moving forward.");
forward(2000);
stop(1000);
}
else {
Serial.println(" cm. Obstacle detected. Changing direction.");
right(1500);
stop(1000);
}
}
If I were trying to debug this, I would first test each of the motor functions without any logic check from the sensor. (e.g. do both wheels turn and in the correct direction when left, right, backward, etc are called just from loop()). That will give confidence that it is not a wiring or other hardware problem. If they don't work then sorting that out give you a place to start.
If they do work, then it must be the values with the sensor, right? How did you determine the maxDistancevalue? If it is too high then this line:
if (currentDistance >= maxDistance){
may never evaluate to true. You have some log statements in there so you have some sense of the value of currentDistance. Does it seem to be reflecting accurate values when you place objects at varying distances from the sensor?
Anyway... some thoughts.

Resources