I built a small robotic car with an ultrasonic sensor on it. (I followed this tutorial : http://educ8s.tv/arduino-robot-easy-diy-project/ ) and the full source code is underneath it (you will have to download)
I modified the code as I want the robot to stop when there is a object placed in front of it, but if the object quickly moves away, for the robot to keep on going forward.
Here is my attempt inside of the void loop :
void loop() {
int distanceR = 0;
int distanceL = 0;
delay(40);
distance = readPing();
if (distance >= 15){
while(distance>= 15){
moveForward();
distance = readPing();
}
}
if(distance<=15)
{
moveStop();
delay(100);
moveBackward();
delay(300);
moveStop();
delay(200);
distance = readPing();
distanceR = lookRight();
delay(200);
distanceL = lookLeft();
delay(200);
distance = readPing();
if (distance >= 15){
while(distance >= 15){
moveForward();
distance = readPing();
}
}
if(distanceR>=distanceL)
{
turnRight();
}else
{
turnLeft();
}
}else
{
moveForward();
}
distance = readPing();``
}
This code works initially to stop the robot and then it keeps going, but the second time you put your hand in front of it and keeping it there, it turns but then suddenly stops. (I am trying to test that the first time an object quickly moves away and the second time it stays there.)
To me it seems that the code stops looping after I have the robot stop for the first time and runs the rest of the void loop but then stops because in the beginning I have the robot test the distance of any objects in front of it but it still doesn't move.
Any help will be appreciated.
You have some dead code and several redundancies. Here is what it looks like when that is eliminated:
void loop() {
int distance;
int distanceR = 0;
int distanceL = 0;
delay(40);
distance = readPing();
while(distance>= 15){
moveForward();
distance = readPing();
}
moveStop();
delay(100);
moveBackward();
delay(300);
moveStop();
delay(200);
distanceR = lookRight();
delay(200);
distanceL = lookLeft();
delay(200);
if(distanceR>=distanceL)
{
turnRight();
}else
{
turnLeft();
}
}
This should help you see your logic more clearly.
Related
I'm doing a project on Arduino that involves traffic lights.
If the crossing button is pressed within a 7 second interval, after waitng for 3 seconds(delay3000), I will call a function. If it's not pressed, the loop will resume as normal.
I have tried with a for loop but can't seem to get around it. Help?
This is the base code that I have. How could I use a millis() fucntion in this problem? Or are there any possible solutions to this problem?
//Street1-Estado Inicial
void loop() {
digitalWrite(str1_verd,HIGH);
digitalWrite(str1_ama,LOW);
digitalWrite(str1_verm,LOW);
digitalWrite(str2_verd,LOW);
digitalWrite(str2_ama,LOW);
digitalWrite(str2_verm,HIGH);
digitalWrite(ped1_verd,LOW);
digitalWrite(ped1_verm,HIGH);
digitalWrite(ped2_verd,HIGH);
digitalWrite(ped2_verm,LOW);
//Verifica se o botao foi pressionado dps de 3s -------ISSUE
delay(3000);
int stateButton1=digitalRead(button_street1);
for (int t=7;t>=1;t--){
if(stateButton1 == false){
B_change_1();
}}
delay(1000);
digitalWrite(str1_verd,LOW);
digitalWrite(str2_ama,HIGH);
digitalWrite(str1_ama,HIGH);
delay(5000);
digitalWrite(str1_ama,LOW);
digitalWrite(str2_ama,LOW);
digitalWrite(str2_verm,LOW);
digitalWrite(str1_verm,HIGH);
digitalWrite(ped2_verd,LOW);
digitalWrite(str2_verd,HIGH);
digitalWrite(ped2_verm,HIGH);
digitalWrite(ped1_verm,LOW);
digitalWrite(ped1_verd,HIGH);
//Verifica se o botao foi pressionado dps de 3s --------ISSUE
delay(3000);
for (int t=7;t>=1;t--){
if(button_street2 == true){
B_change_2();
}}
delay(1000);
digitalWrite(str2_verd,LOW);
digitalWrite(str1_ama,HIGH);
digitalWrite(str2_ama,HIGH);
delay(5000);
loop();
}
//Funcao b_change1
void B_change_1(){
digitalWrite(str1_verd,LOW);
digitalWrite(str2_ama,HIGH);
digitalWrite(str1_ama,HIGH);
delay(5000);
digitalWrite(str1_ama,LOW);
digitalWrite(str2_ama,LOW);
digitalWrite(str2_verm,LOW);
digitalWrite(str1_verm,HIGH);
digitalWrite(str2_verd,HIGH);
digitalWrite(ped2_verm,HIGH);
digitalWrite(ped1_verm,LOW);
digitalWrite(ped1_verd,HIGH);
buzzer_alert();
digitalWrite(ped2_verd,LOW);
}
//Funcao bchange2
void B_change_2(){
digitalWrite(str2_verd,LOW);
digitalWrite(str1_ama,HIGH);
digitalWrite(str2_ama,HIGH);
delay(5000);
digitalWrite(str2_ama,LOW);
digitalWrite(str1_ama,LOW);
digitalWrite(str1_verm,LOW);
digitalWrite(str2_verm,HIGH);
digitalWrite(str1_verd,HIGH);
digitalWrite(ped1_verm,HIGH);
digitalWrite(ped2_verm,LOW);
digitalWrite(ped2_verd,HIGH);
}}}
First of all, you are repeatedly checking button press variables that can't change (though this may be intentional?) :
int stateButton1=digitalRead(button_street1);
for (int t=7; t>=1; t--) {
if(stateButton1 == false) { <---- stateButton1 will never change
B_change_1();
}
}
and
delay(3000);
for (int t=7;t>=1;t--){
if(button_street2 == true) { <---- this isn't set, and won't change
B_change_2();
}
}
You need to update stateButton1 by reading from digitalRead in the loop, or at least every time you test it.
To test if a certain amount of time has passed, you could do something similar to
long button_wait_timeout = 7000; // Maximum time to wait for button press
long button_wait_allowed = 3000; // If pressed within three seconds do action
long starttime = millis();
while (digitalRead(button_street1) == LOW && ((millis() - starttime) < button_wait_timeout)) {
delay(10); // how man millilseconds before trying the button again
}
if ((millis() - starttime) < button_wait_allowed) {
do_action_1();
}
You can remove the timeout bits if you want to wait indefinitely.
I only started programming a few days ago and ran into a few problems.
I'm trying to make a servo turn 180 degrees when I type 1 and 180 degrees the other way when I type 0, I'm using an HC-05 Bluetooth module connected to my phone, so I tried to "merge" the servo sweep code from Arduino IDE library and another code that turns a light on by Bluetooth (which works), so I've been trying to fix this without any results.
Here's what I've done so far:
#include <Servo.h>
Servo myservo;
int pos = 0;
char data = 0;
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
myservo.attach(13);
}
void loop()
{
if (Serial.available() > 0)
{
data = Serial.read();
Serial.print(data);
Serial.print("\n");
if (data == '1') for (pos = 0; pos <= 180; pos += 1)
else if (Serial.available() > 1)
digitalWrite(13, myservo(pos = 180; pos >= 0; pos -= 1));
}
}
Arduino create keeps telling me I'm missing a primary expression before else.
You've added the start of a for loop, but not told the compiler what operations to repeat.
When you're beginning, it's useful to add braces whenever you use a control statement (if, while, for, do, switch, case) irrespective of whether you have to, and indent consistently, then you can see where things should go and where the body of the control statement starts and ends.
void loop()
{
if (Serial.available() > 0)
{
data = Serial.read();
Serial.print(data);
Serial.print("\n");
if (data == '1')
{
// execute the code from the 'sweep' example if the user sends '1'
for (pos = 0; pos <= 180; pos += 1)
{
// goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos);
delay(15);
}
}
else if (Serial.available() > 1)
{
// removed as code here made no real sense
}
}
}
I am trying to control a small servo motor with an Arduino and I am running into a problem where the Servo continuously runs even when I want it to stop. I have pasted a picture of my code below. The for loops should make the Servo stop when it rotates 180 degrees, but it just keeps spinning.
I am trying to control the direction of the servos using the Serial monitor as input.
#include <Servo.h>
Servo myservo;
int i = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
myservo.attach(9);
}
void loop() {
// put your main code here, to run repeatedly:
keyboardControl();
}
void keyboardControl() {
if (Serial.available() > 0) {
int data = Serial.read();
switch (data) {
case '1' :
for (i = 0; i <= 180; i += 1) {
myservo.write(i);
delay(15);
if (i = 180) {
break;
}
case '2':
for (i = 180; i >= 0; i -= 1) {
myservo.write(i);
delay(15);
break;
}
}
}
}
}
I would give this code a try:
void stop()
{
while(1 = 180);
}
I have a rotary encoder and a DC gear motor connected to my Arduino UNO. I would like to rotate the DC motor at a certain angle. As I right now, I have written a code that reads the position of my encoder as I rotate it and prints out the position and the angle. I have also written code that runs the dc motor at fixed amount of time.
I would like to rotate the dc motor at a certain angle. For example, if I input 90 degrees my motor should rotate 90 degrees and stop.
I'm using pin 2 and pin 3 for my channel A and B (ENCODER)
I'm using pin 9 to control my dc motor.
I have no clue how to approach this... any thoughts?
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int lcd_case = 0;
volatile int timeToRun = 0;
int motorPin = 6;
#define BTN_RIGHT 0
#define BTN_LEFT 1
#define BTN_UP 2
#define BTN_DOWN 3
#define BTN_SELECT 4
#define BTN_NONE 5
#define SELECT 6
#define RESET 7
#define PIN
#define encoderPinA 2
#define encoderPinB 3
#define CPR 256
volatile int counter =0;
volatile boolean flag;
volatile int var_degrees =0;
void setup() {
pinMode(3, OUTPUT);
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
Serial.begin (9600);
attachInterrupt(digitalPinToInterrupt(encoderPinA), isr_2, RISING);
lcd.clear();
}
void loop() {
if(flag == true){
var_degrees = ((360/256.0)*counter);
Serial.println(var_degrees);
//lcd.setCursor(0, 1);
//lcd.print("Degrees: ");
//lcd.setCursor(9, 1);
//lcd.print(var_degrees);
flag = false;
}
lcd_case = readButtons();
int read_button = analogRead (0);
//Depending on which button we pressed, we performan action
switch (lcd_case) {
case BTN_RIGHT:
{
break;
}
case BTN_LEFT:
{
break;
}
case BTN_UP:
{
timeToRun = timeToRun +1;
lcd.setCursor(0, 1);
lcd.print("Degrees: ");
lcd.setCursor(9, 1);
lcd.print(timeToRun);
delay(500);
break;
}
case BTN_DOWN:
{
if (timeToRun > 0) {
timeToRun = timeToRun - 1;
lcd.setCursor(0, 1);
lcd.print("Degrees: ");
lcd.setCursor(9, 1);
lcd.print(timeToRun);
delay(500);
break;
}
}
case BTN_SELECT:
{
analogWrite(motorPin, 255);
// I NEED TO ROTATE MOTOR BASED ON ANGLE IN ENCODER
delay(timeToRun * 100); //ONLY ROTATES DC MOTOR IN SECONDS
break;
}
case RESET:
{
break;
}
}
}
//Interrupts
void isr_2(){
flag = true;
if(digitalRead(encoderPinA) == HIGH){
if(digitalRead(encoderPinB) == LOW){
counter = counter -1; //COUNTER CLOCK WISE
}
else{
counter = counter +1; //CLOCK WISE
}
}
else{ //IF PIN A IS LOW
if(digitalRead(encoderPinB) == LOW){
counter = counter +1; //CLOCK WISE
}
else{
counter = counter -1 ; //COUNTER CLOCK WISE
}
}
}
int readButtons() {
int read_button;
read_button = analogRead (0);
if (read_button < 50) {
return BTN_RIGHT;
}
if (read_button < 195) {
return BTN_UP;
}
if (read_button < 400) {
return BTN_DOWN;
}
if (read_button < 600) {
return BTN_LEFT;
}
if (read_button < 800) {
return BTN_SELECT;
}
else
return BTN_NONE;
}
It's good that you are correctly reading the position of the armature of your motor. Now is the time to use PID and closed loop! Tuned PID is a controller that helps your motor to go to the desired position at the best possible time with the lowest possible overshoot(error) It takes a control course to learn all of this. You will basically need a feedback loop that takes the "desired angle", give it to the controller which moves the motor. Then you get the current position of the motor, which will be fed back to the origin of the system. Your "desired angle" minus "current angle" will be how much your motor should move each time the micro controller go over the loop.
Here is how the feedback loop looks like:
And here is link to learn control. Good luck!
Control Tutorials
Edit 2: I should probably give you an intro on what PID is as well. PID controller is made of three different components:
Proportional
Integral
Derivative
Each time you get your "Desired Angle" - "Actual Angle" or "e" as shown in diagram, you will times it by Kp. Find its derivative with respect to previous e and times it by Kd, and find the integral of the errors and times it by Ki. You can start by ignoring Ki and integral, and add it if it was needed later. After you got Kpe+Kdd(e)/dt, this values is the percentage of power you will output to your motor. Kp and Kd and Ki is where the real engineering comes into play. You should find them using the transfer function of your system and fine-tune them in MatLab or a similar software. These values are usually low (less than 1). It really depends on your system. For my motor, they were Kp=0.001 and Kd=0.02
currently am working on project to open a door with access code using arduino UNO and a servo motor. Normal operation requires entering access code using keypad which is working fine. Another option requires pressing a button that causes an interrupt to rotate the servo motor. My problem is my interrupt only works once and never works again. Plus how do i put the for-loop to rotate the servo motor inside the interrupt function with a delay. I know that is not possible but am calling another function that has the delayMicroseconds but all this is not working. Below is my implementation please help
#include <Keypad.h>
#include <LiquidCrystal.h>
#include <Servo.h>
Servo servo;
const int openButtonPin = 2;
void setup() {
// put your setup code here, to run once:
servo.attach(5);
pinMode(openButtonPin, INPUT); //Pin 2 is input
attachInterrupt(0, enforceOpenAccess, HIGH); // PIN 2
}
void(* resetFunc)(void) = 0;
void loop()
{
//My other keypad implementations go here
}
void myDelay(int x) // function to cause delay in the interrupt
{
for(int i = 0; i<x; i++)
{
delayMicroseconds(1000);
}
}
void enforceOpenAccess() // ISR
{
for(int k =0; k<=180; k+=2)
{
servo.write(k); //rotate the servo
myDelay(30); //delay the rotation of the servo
}
}
The code above is run on arduino UNO being simulated in proteus and the interrupt button is a push button. Please if there is other ways of implementing that but with the same behaviour as I have described above help out. Thanks a lot
There are a couple of problems in the slice of code you posted. Just for completeness, you should post the loop function, since we can't guess what you wrote inside.
Just one comment: did you put a pullup? Otherwise use INPUT_PULLUP instead of INPUT for the button pinmode.
The main one is that you attached the interrupt for the HIGH mode, which will trigger the interrupt any time the pin is up, not on the rising edge. And please use the macro digitalPinToInterrupt to map to the correct pin:
attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
Then.. Let's improve the code. You really should use the interrupts only when strictly necessary when you have to respond IMMEDIATELY (= less than a couple of milliseconds) to an input. Here you don't have to, so it's MUCH better to check for the button in the loop (more on turning the motor following)
uint8_t lastState;
void setup()
{
...
lastState = LOW;
}
void loop()
{
uint8_t currentState = digitalRead(openButtonPin);
if ((currentState != lastState) && (currentState == HIGH))
{
// Start turning the motor
}
lastState = currentState;
...
}
This will enable you to properly debounce the button too:
#include <Bounce2.h>
Bounce debouncer = Bounce();
void setup()
{
...
pinMode(openButtonPin, INPUT); //Pin 2 is input
debouncer.attach(openButtonPin);
debouncer.interval(5); // interval in ms
}
void loop()
{
debouncer.update();
if (debouncer.rose())
{
// Start turning the motor
}
...
}
If, on the other way, you REALLY want to use the interrupts (because waiting for a couple of milliseconds is too much for you), you should do something like this:
#include <Bounce2.h>
Bounce debouncer = Bounce();
void setup()
{
...
pinMode(openButtonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
}
void loop()
{
...
}
void enforceOpenAccess() // ISR
{
// Start turning the motor
}
It looks like your code? No, because now we'll speak about turning the motor
You should NOT use delays to make steps, because otherwise you will wait for 30ms * 180 steps = 5.4s before being able to do anything else.
You can, however, make a sort of reduced state machine. You want your servo to move from 0 to 180 in steps of 1. So let's code the "don't move" state with any value greater than 180, and consequently we can do something like this in the loop:
unsigned long lastServoTime;
uint8_t servoPosition = 255;
const int timeBetweenSteps_in_ms = 30;
void loop()
{
...
if (servoPosition <= 180)
{ // servo should move
if ((millis() - lastServoTime) >= timeBetweenSteps_in_ms)
{
lastServoTime += timeBetweenSteps_in_ms;
servoPosition++;
if (servoPosition <= 180)
servo.write(servoPosition);
}
}
}
Then, using any of the previous examples, instead of // Start turning the motor write
lastServoTime = millis();
servoPosition = 0;
servo.write(servoPosition);
This way you won't block the main loop even when the button is pressed
This is what is in my loop()
char key = keypad.getKey();
if(key)
{
if(j < 10)
{
studentNumber[j] = key;
//holdMaskedNumber[j] = '*';
lcd.setCursor(0,2);
lcd.print(String(studentNumber));
if(j == 9)
{
studentNumber[9] = '\0';
//holdMaskedNumber[9] = 0;
lcd.clear();
//String number = String(studentNumber);
//lcd.print(number);
//delay(1000);
//lcd.clear();
lcd.print("Access Code");
}
j++;
}
else
{
if(i < 5)
{
accessCode[i] = key;
holdMaskedCode[i] = '*';
lcd.setCursor(1,2);
lcd.print(String(holdMaskedCode));
if(i == 4)
{
holdMaskedCode[5] = '\0';
accessCode[5] = '\0';
//lcd.clear();
//lcd.setCursor(0,0);
//accessCodeString = String(accessCode);
//lcd.print(accessCodeString);
//delay(1000);
lcd.clear();
for(int i =0; i<6; i++)
{
lcd.print("Please wait.");
delay(500);
lcd.clear();
lcd.print("Please wait..");
delay(500);
lcd.clear();
lcd.print("Please wait...");
delay(500);
lcd.clear();
}
digitalWrite(4, HIGH);
lcd.print("Access Granted");
for(int k =0; k<=180; k+=2)
{
servo.write(k);
delay(30);
}
resetFunc();
}
i++;
}
}
}