I am trying to get a continuous (180 to 0 and back 0 to 180) movement from a servo when I press a button in remote and ONLY stop when I press the other button. So far, I have gotten it to move continuously, but then it doesn't stop when I press the 'stop' button. I know it is because of the while loop. However, I have tried switch-case, if statement, nothing has worked so far.
Please help, any advice for it make it work is appreciated.
#include <Servo.h>
#define code1 2534850111 //decimal value of button 1
#define code3 16724175 //decimal value of button 1
#define code 4294967295 //random value
#define code2 16738455 //decimal value of button 0
#define code4 3238126971 //decimal value of button 0
Servo myservo; // servo object
int RECV_PIN = 11; //receiveing pin IR remote
int pos = 0;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); //start the receiver
myservo.attach(9); //servo connect to pin 9
pinMode(2, OUTPUT); //LED connect to pin 2
}
void loop() {
if(irrecv.decode(&results)){
// if(results.value == code1 || results.value == code3){
while(results.value == code1 || results.value == code3){
digitalWrite(2,HIGH); //turn the led on
for(pos = 0; pos <= 180; pos += 1){ //servo goes form 0 to 180 degrees in steps of 1 degree
myservo.write(pos);
delay(7);
}
for(pos = 180; pos >= 0; pos -= 1){ //servo goes back from 180 to 0 degrees with 1 degree step
myservo.write(pos);
delay(7);
}
}
while(results.value == code2 || results.value == code4){
digitalWrite(2, LOW); // turn the led off
myservo.write(pos);
delay(15);
break;
}
Serial.println(results.value, DEC); //show the decimal value of the pressed button
irrecv.resume(); //receive the next value
}
}
One way to solve your problem would be to check for the presence of a "button push" deeper inside loop(). Put your checks for the button presses inside your movement for loop to catch the changes right away. Looks like you might have two startcodes (?) so you might have to alter the if statements below, but hopefully I demonstrate how to check the condition to "keep going" in the code sample below.
void loop()
{
if(irrecv.decode(&results))
{
// turn one way
for(pos = 0; pos <= 180; pos += 1)
{
// only continue if the start code(s) still active
if(results.value == STARTCODE || results.value == OTHERSTARTCODE)
{
myservo.write(pos);
delay(7);
irrecv.resume(); //receive the next value
}
}
// turn the other way
for(pos = 180; pos >= 0; pos -= 1)
{
// only continue if the start code(s) still active
if(results.value == STARTCODE || results.value == OTHERSTARTCODE)
{
myservo.write(pos);
delay(7);
irrecv.resume(); //receive the next value
}
}
}
}
Related
I am very new to Arduino. I want to make a simple setup, in which, pressing a button on a remote will make the servo rotate 90 degree and come back to 0.
Here is my code:
#include <Servo.h>
#include <IRremote.h>
int receiver = 13;
IRrecv irrecv(receiver);
decode_results results;
Servo myServo;
int pos = 0;
void setup() {
// put your setup code here, to run once:
myServo.attach(9);
Serial.begin(9600);
irrecv.enableIRIn();
myServo.write(0);
delay(200);
}
void loop() {
// put your main code here, to run repeatedly:
if (irrecv.decode(&results)){
if (results.value== 0xC0000C){
for (pos = 0; pos <= 90; pos += 1) {
// in steps of 1 degree
myServo.write(pos);
delay(15);
}
for (pos = 90; pos >= 0; pos -= 1) {
myServo.write(pos);
delay(15);
}
}
}
delay(100);
}
However, when I press the button assigned, the servo keeps swinging from 0 to 90 degree and back infinitely, but I only want it to do so once, each time the button is pressed. How do I do that?
You need to add the line
irrecv.resume();
to the end if loop just before that final delay in order to clear out the results and start looking for a new signal.
void loop() {
// put your main code here, to run repeatedly:
if (irrecv.decode(&results)){
if (results.value== 0xC0000C){
for (pos = 0; pos <= 90; pos += 1) {
// in steps of 1 degree
myServo.write(pos);
delay(15);
}
for (pos = 90; pos >= 0; pos -= 1) {
myServo.write(pos);
delay(15);
}
}
}
irrecv.resume();
delay(100);
}
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 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
So far I have wrote code so that if 1 then enter pressed or send clicked, and then 1 again and enter pressed or send clicked causes LED one to turn on, if ‘1’ ‘0’ is entered in a similar way then LED 1 turns off, and so on for LEDs two and three, ie: ‘2’ ‘1’ turns on LED 2, ‘3’ ’0’ turns off LED 3.
int incomingVal;
int ledPin = 16;
int ledPin2 = 15;
int ledPin3 = 14;
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
Serial.println("starting");
pinMode(ledPin,OUTPUT);
pinMode(ledPin2,OUTPUT);
pinMode(ledPin3,OUTPUT);
}
void loop()
{
if (Serial.available() > 0 ) //then chars are in the serial buffer
{
incomingVal = Serial.parseInt();
Serial.print("You entered: ");
Serial.println(incomingVal);
if (incomingVal == 10)//turns off led 1
{
digitalWrite(ledPin, LOW);
}
if (incomingVal == 11)//turns on led 1
{
digitalWrite(ledPin, HIGH);
}
if (incomingVal == 20)//turns off led 2
{
digitalWrite(ledPin2, LOW);
}
if (incomingVal == 21)//turns on led 2
{
digitalWrite(ledPin2, HIGH);
}
if (incomingVal == 30)//turns off led 3
{
digitalWrite(ledPin3, LOW);
}
if (incomingVal == 31)//turns on led 3
{
digitalWrite(ledPin3, HIGH);
}
}
}
How could i change the code so i can enter a third value to change the brightness from 0 to 250? For example, typing “2,1,125” would make LED 2 to light up at 50% brightness.
To make the LED light up at half brightness you need to use pulse width modulation. Make sure that the pins you are using have ~ next to them (pins 3, 5, 6, 9, 10, 11 on the Uno).
I would change your input method slightly, because 0 brightness is essentially the same as turning the LED off, you should only need 2 numbers. The first number corresponds to the LED, the second number corresponds to the brightness.
int led_pins[3] = {9,10,11};
int incomingVal;
int brightness;
int parsed_value;
int x = 0;
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
Serial.println("starting");
pinMode(led_pins[0],OUTPUT); // You could also use a loop here
pinMode(led_pins[1],OUTPUT);
pinMode(led_pins[2],OUTPUT);
}
void loop()
{
if (Serial.available() > 0 ) //then chars are in the serial buffer
{
incomingVal = Serial.parseInt();
Serial.print("You entered: ");
Serial.println(incomingVal);
//figure out which LED we selected
parsed_value = incomingVal;
while (parsed_value > 9){
/*
because of integer division, this line will remove the last
number from the integer. ie 11 / 10 = 1 (the result is rounded down)
The loop will continue until only 1 digit remains
*/
x++;
parsed_value = parsed_value / 10;
}
// x represents the number of times parsed_value was divided by 10
// this line removes the first digit of the incoming value, leaving
// the brightness
brightness = incomingVal - pow(10,x)*parsed_value;
/*parsed_value will be 1 greater than the array key value because
the array is 0 based.*/
//set the LED to the right brightness
analogWrite(led_pins[parsed_value-1],brightness);
}
}
i want to make an IR sensor door with DFRobot IRsensor (switch) and Servo. the problem is in the if statement because the digitalread is always changing when there's nothing in front of the IR sensor which is the way it suppouse to be... so it rapidly closing and opening. but i want the door to be open when there's something in front of the sensor and then some delay, then its gonna close if there's something (new) in front of the door.
mycode:
#include <Servo.h>
Servo myservo;// create servo object to control a servo
// a maximum of eight servo objects can be created
int IRsensor =8;
int pos = 180; // variable to store the servo position
int d;
boolean kondisi;
void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
pinMode (IRsensor,INPUT);
Serial.begin (9600);
}
void loop()
{
d = digitalRead (IRsensor);
bukatutup (d);
delay (15);
}
void bukatutup(int IR)
{
Serial.println (IR);
if (IR == 0 and (kondisi == false))
{
pos = 0;
Serial.println ("terbuka");
myservo.write (pos);
kondisi == true;
delay(1000);
}
else if ( IR == 0 and (kondisi == true))
{
pos = 180;
Serial.println ("tertutup");
kondisi == false;
myservo.write (pos);
delay (1000);
}
}
Thx,