Stepper motor control via RC receiver - while-loop

I am new to Arduino programming and have spent a couple days getting this far, but cannot seem to figure out why this code is not working.
I am trying to control a stepper motor using a hobby grade remote control RX/TX.
I have an RC receiver sending an analog value from 1000 to 2000 to my Arduino. If that signal is 1000, I would like to make 1000 = -360 degrees on the stepper and 2000 = +360 degrees on the stepper.
I am receiving the correct signals from the receiver and printing them to the serial monitor, but I cant seem to control the stepper motor with this value yet. This motor simply gets stuck in the first while loop and continues to spin in 1 direction.
int ch1 = 0; // RC Reciever Channel Value
int ch1previous = 0; // RC Receiver Channel Previous Value
int PUL=7; //define Pulse pin of stepper driver
int DIR=6; //define Direction pin of stepper driver
int ENA=5; //define Enable Pin of stepper driver
void setup() {
pinMode (PUL, OUTPUT); // Stepper Driver Pulse Pin
pinMode (DIR, OUTPUT); // Stepper Driver Direction Pin
pinMode (ENA, OUTPUT); // Stepper Driver Enable Pin
pinMode(3, INPUT); // RC Reciever Pin Input
Serial.begin(9600);
}
void loop() {
ch1 = pulseIn(3, HIGH, 50000); // Read RC Reciever Channel Value
while ( ch1 > ch1previous) { // If CH1 is greater than CH1Previous run the differance
for ( int i = ch1; i < ch1previous; i++);{ // in steps to maintain the setpoint value in forwared position
digitalWrite(DIR,HIGH);
digitalWrite(ENA,HIGH); // pulsing stepper motor in forward motion
digitalWrite(PUL,HIGH);
delayMicroseconds(50);
digitalWrite(PUL,LOW);
delayMicroseconds(50);
}
}
while ( ch1 < ch1previous) { // if CH1 is less than CH1Previous run the differance
for ( int i = ch1; i<ch1previous; i--);{ // in steps to maintain the setpoint value in reverse motion
digitalWrite(DIR,LOW);
digitalWrite(ENA,HIGH); // pulsing stepper motor in reverse motion
digitalWrite(PUL,HIGH);
delayMicroseconds(50);
digitalWrite(PUL,LOW);
delayMicroseconds(50);
}
}
Serial.print ("Channel 1: "); // print text to the serial monitor
Serial.println(ch1); // print ch1 value to the serial monitor and end line
Serial.print("CH1 Previous: "); // print text to the serial monitor
Serial.println(ch1previous); // print ch1previous value to the serial monitor and end line
ch1previous = ch1; // remember the previous value from ch1
delay(500); // just to clean up the serial monitor
}

Can
ch1 = pulseIn(3, HIGH, 50000)
ever be a negative value? if not, then that could explain this behavior, when you consider this statement:
while ( ch1 > ch1previous) {
and ch1previous is initialized to zero.

Both the while conditions will go on infinitely if they are started even once. As you have put in comments If CH1 is greater than CH1Previous run the difference, these while conditions have to be replaced by if statements. That is, make them as if(ch1 > ch1previous) and else if(ch1 < ch1previous). And for loops' conditions should also be reversed, as per the if condition bounding them.
After these changes, your code will become something like this
void loop() {
ch1 = pulseIn(3, HIGH, 50000);
if ( ch1 > ch1previous) {
for ( int i = ch1; i > ch1previous; i--){
//code
}
}
else if ( ch1 < ch1previous) {
for ( int i = ch1; i<ch1previous; i++){
//code
}
}
...
}

Related

Distance measurement using Ultrasonic and ATMEGA32

I'm working on a Distance measurement program using an AVR microcontroller. I use a 16x2 LCD and an ultrasonic sensor along with ATMEGA32A. I wrote a code to display the distance from the Ultrasonic HC-SR04 on the LCD screen, but it gives me false readings, it increases the distance when the object is very near and vice versa. I just want an accurate reading.
Ultrasonic datasheet
ATMEGA32A Datasheet
#include <avr/io.h>
#include <avr/interrupt.h>
#include <MrLcd/MrLCDmega32.h>
#define F_CPU 1000000
#include <util/delay.h>
#include <stdlib.h>
#define Trigger_pin PD0 /* Trigger pin */
static volatile int pulse = 0;
static volatile int i = 0;
int main(void)
{
Initialise();
DDRD = 0b11111011;
_delay_ms(50);
GICR |= 1<<INT0;
MCUCR |= 1<<ISC00;
int16_t count_a = 0;
char show_a[16];
sei();
while(1)
{
PORTD |= (1<<Trigger_pin);
_delay_us(10);
PORTD &= ~(1<<Trigger_pin);
count_a = pulse/58;
Send_A_String("Distance Sensor");
GoToMrLCDLocation(1,2);
Send_A_String("Distance=");
itoa(count_a,show_a,10);
Send_A_String(show_a);
Send_A_String(" ");
GoToMrLCDLocation(13,2);
Send_A_String("cm");
GoToMrLCDLocation(1,1);
}
}
ISR(INT0_vect)
{
if(i == 1)
{
TCCR1B = 0;
pulse = TCNT1;
TCNT1 = 0;
i = 0;
}
if(i==0)
{
TCCR1B |= 1<<CS10;
i = 1;
}
}
I tried to change the trigger pin definition and define it in the code itself but still no progress.
Update: I changed a bit more in the code but I'm getting hex values when the distance is more than 9, for example, 10 is being displayed as 1e.
This is for initialise function
void Initialise(void)
{
DataDir_MrLCDsControl|=1<<LightSwitch|1<<ReadWrite|1<<BipolarMood; //these information will go towards the LCD
_delay_ms(15); // Wait for the LCD to start
Send_A_Command(0x01); // to clear the screen
_delay_ms(2);
Send_A_Command(0x38); // TO tell LCD about 8 data lines
_delay_us(50);
Send_A_Command(0b00001110); //Some cursor command
_delay_us(50);
}
You are sending pulses at a very rapid rate (determined solely by the display update time), and they are asynchronous to the time/counter reset. You have no idea which pulse triggered the interrupt and it did not start at the same time as the timer.
I would suggest that you reset the counter at the start of the pulse, and capture the counter value on interrupt. When the time has exceeded the maximum range, send a new pulse:
First define some constants:
#define PULSES_PER_CMx100 (F_CPU * 100 / 68600)
#define MAX_RANGE_CM 300
#define MAX_RANGE_COUNT ((MAX_RANGE_CM * PULSES_PER_CMx100) / 100)
Then your measure/display loop might look like:
pulse = 1 ; // dummy start
GICR &= ~(1<<INT0) ; // Disable INT0
for(;;)
{
// Ready for new measurement?...
if( pulse != 0 )
{
// Send pulse and reset timer
PORTD |= (1<<Trigger_pin) ;
pulse = 0 ;
TCNT1 = 0 ;
_delay_us(10);
PORTD &= ~(1<<Trigger_pin) ;
// Wait for echo pulse interrupt...
GIFR |= 1<<INTF0; // Clear INT0 pending flag
GICR |= 1<<INT0 ; // Enable INT0
}
else // When measurement available...
{
int distance_cm = pulse * 100 / PULSES_PER_CMx100 ;
// display distance
...
}
// If out of range, timeout, send a new pulse
if( TCNT1 > MAX_RANGE_COUNT )
{
// Force a new pulse to be triggered
pulse = 1 ;
}
}
And the ISR:
ISR(INT0_vect)
{
pulse = TCNT1; // Capture time on interrupt
GICR &= ~(1<<INT0) ; // Disable further interrupts
}
Now bear in mind that that method will take measurements as fast as possible and since you are displaying them for human reading, that is rather unnecessary. You might simply put a delay in the loop - making the pulse timeout unnecessary, or better you could take the mean of multiple measurements to get a more robust measurement, or use a moving average window, with outlier rejection.

While loop before if-else statement not working?

I have a code illuminating an LED using a few different inputs. I'm not sure why but the (while) command to turn off the light when the battery is low, isn't executing. Currently it's draining below the 3v level all the way down to 1.9v. Could it be because of my code structure?
While- measures battery and shuts off when under 3v
if (rf95.available())- listens for a radio signal and switch command
if(digitalRead(SWITCH))- listens for physical switch command
else- leaves the LED on if no commands are sent
Watchdog.sleep- deep sleep command to save battery
void loop(){
Serial.begin(115200);
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
float measuredvbat = analogRead(VBATPIN);
measuredvbat *= 2; // we divided by 2, so multiply back
measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage
measuredvbat /= 1024; // convert to voltage
measuredvbat /=1.61; // fudge factor
Serial.print("VBat: " );
Serial.println(measuredvbat);
while(measuredvbat < 3.00){
analogWrite(LED,0);
Serial.print("VBat: " );
Serial.println(measuredvbat);
Serial.println("Battery Low");
int sleepMS = Watchdog.sleep(3600000);
}
if (rf95.available()){
if (rf95.recv(buf, &len)) {
if(strncmp(buf, "TurnOn", strlen(buf)) == 0){
Serial.println("Turn Up For WAT !!");
analogWrite(LED,75);
}
}
}
if(digitalRead(SWITCH)){
Serial.println("SWITCH-ON-12");
analogWrite(LED, 75);
}
else{
Serial.println("SWITCHED ON-12");
analogWrite(LED, 112);
}
}

What is the best way to detect a button push - Arduino

I have a function which is basically a Whack-A-Mole game using LEDs and Push Buttons. LED-A lights up, and the user has to push BTN-A to turn it off... and we move on to the next LED/BTN combo.
My circuitry works and i can turn each LED on/off individually and detect each button push as well. However, once in my game loop (see below), I see some odd behavior.
My code looks like this:
void gameTwo(){
Serial.println("We are in Game 2");
playGameTwo();
//lightShowTwo();
// Set game state
int gameState = 0;
// Start counter
elapsedMillis timeElapsed;
// First LED
digitalWrite(ledB, HIGH);
while(digitalRead(btnB) != HIGH){
//Serial.print("btnBstate is: ");
//Serial.println(digitalRead(btnB));
if(digitalRead(btnB) == 1){
delay(50);
digitalWrite(ledB, LOW);
Serial.print(timeElapsed);
}
}
// Second LED
digitalWrite(ledE, HIGH);
while(digitalRead(btnE) != HIGH){
//Serial.print("btnBstate is: ");
//Serial.println(digitalRead(btnE));
if(digitalRead(btnE) == 1){
delay(50);
digitalWrite(ledE, LOW);
Serial.print(timeElapsed);
}
}
// Third LED
digitalWrite(ledF, HIGH);
while(digitalRead(btnF) != HIGH){
//Serial.print("btnBstate is: ");
//Serial.println(digitalRead(btnE));
if(digitalRead(btnF) == 1){
delay(50); // these dalays DO NOT work
digitalWrite(ledF, LOW);
Serial.print(timeElapsed);
}
}
// End Game - Publish Elapsed Time
gameState = 1;
// record user's elapsed time
int userTime = timeElapsed;
Serial.print("Game Finished - Your time was: ");
Serial.print(timeElapsed);
Serial.println(" ms!");
}
The problem is that it doesn't always work. Sometimes LED-A turn off, sometimes it stays on.
As you can see, I've tried adding a small delay(50) also to no avail.
What is the best way to detect button presses in a while loop.
Bonus question: I'm hard coding the game (eg LEDA, LEDB... LEDx). There should be a better way, perhaps using an array, to push the game sequence. As I'm not a programmer, I'd appreciate some guidance or an article to read to get more educated on this. Thanks.
You can use while to loop until a button is pressed.
Using arrays will make it much easier, here I use an array for leds and a another for buttons. The numbers in arrays represents the pins. I inserted random() function that will make it more challenging. Each loop it takes a random ledPin for led[] and a corresponding btnPin for btn[].
//suppose that the button in pin 4 is for led in pin 1
//the button in pin 5 is for led in pin 2
//and the button in pin 6 is for led in pin 3
int led[] = {1, 2, 3};
int btn[] = {4, 5, 6};
int count = 3;
int ledPin = 0;
int btnPin = 0;
int previous = 0;
void setup() {
for( ledPin=0; ledPin<count; ledPin++ ){
pinMode(led[ledPin], OUTPUT);
}
}
void loop() {
ledPin = random(1, 4); //pick a random number 1-3
while( ledPin == previous ){ //if it is the same as previous, change it
ledPin = random(3); }
btnPin = ledPin + 3; //btnPin set to 4-6
digitalWrite(led[ledPin], HIGH);
while( digitalRead(btn[btnPin]) == LOW ){} //or HIGH according to pulling method
digitalWrite(led[ledPin],LOW);
previous = ledPin;
}

Faulty Arduino Logic?

I am making a simple Led program that will be turned into a library for my project. I have created four methods that will allow you to A) Setup as many Led pins as you want and make them as Outputs. B) Flash the Led lights at a customized time. C) Turn On Leds. D) Turn Off Leds. Everything is working if i just run the methods in the void loop(). For example:
Void loop(){
flashLed(pinNum, 2000);
turnOf(pinNum);
turnOn(pinNum);
}
If i run the above code it works fine, however it keeps looping as its obviously in a loop. So i decided to start the serial com by using Serial.begin(9600) in the setup(), and then testing for the serial com and used a switch case statement in order to appropriately implement these methods. What am i doing wrong here? i get no errors at all. When i type into the serial monitor nothing happens, i believe my logic is fine but that is why i am here. When anything is typed into the serial monitor, the code runs the default in the switch case statement and that is all. I have tried using while, if to no avail. Also tested the inverse of serial which would be !serial.available() Here is my code:
//Define the pin numbers
byte pinNum[] = {4, 3, 2};
void setup() {
//Setup the ledPins
ledSetup(pinNum);
Serial.begin(9600);
}
void loop() {
while(Serial.available() > 0){
//Read the incoming byte
byte ledStatus = Serial.read();
switch (ledStatus){
case 0:
turnOff(pinNum);
Serial.println("The Leds Have Been Turned Off");
break;
case 1:
turnOn(pinNum);
Serial.println("The Leds Have Been Turned On");
break;
case 2:
flashLed(pinNum, 1000); //This will make the Led blink for half a second
Serial.println("The Leds Will Begin Flashing");
break;
default:
flashLed(pinNum, 1000); //This will make the Led blink for half a second
break;
}
}
}
//Method to declare the pins as output
void ledSetup(byte ledPins[]){
for (int i = 0; i <= sizeof(ledPins); i++){
pinMode(ledPins[i], OUTPUT);
}
}
//Method to blink the Led light/lights
void flashLed(byte ledBlink[], int duration){
//Time is divided by two because it takes 2 seconds
//to run the sketch
for (int i = 0; i <= sizeof(ledBlink); i++){
digitalWrite(ledBlink[i], HIGH);
delay(duration/2);
digitalWrite(ledBlink[i], LOW);
delay(duration/2);
}
}
//Method to turn Leds off
void turnOff(byte ledOff[]){
for(int i = 0; i <= sizeof(ledOff); i++){
digitalWrite(ledOff[i], LOW);
}
}
//Method to turn Leds On
void turnOn(byte turnOn[]){
for (int i = 0; i <= sizeof(turnOn); i ++){
digitalWrite(turnOn[i], HIGH);
}
}
The serial monitor sends symbols encoded in the ASCII format.
e.g. when you enter 0, Serial.read() returns 48, which is the ASCII code for digit 0. Since the value 48 is not listed in the following cases, the default branch is taken:
case 0: ...
case 1: ...
case 2: ...
default: ...
There are many solutions to your problem.
1. change case conditions to match what you are sending:
case '0': ...
case '1': ...
case '2': ...
2. replace Serial.read() with Serial.parseInt():
int ledStatus = Serial.parseInt();
This will actually work with more general inputs, e.g. 123, but it will return 0 if there is anything different from a digit in the input buffer.
3. wrap Serial.read() within atoi():
byte ledStatus = atoi(Serial.read());
This is somewhat more limited than both of previous options, since now you can only have 10 cases in your switch.

Traffic lights simulation and xbee communication

So i am having this project. The system will give priority to emergency vehicles when they get close to traffic lights and when they get close i want to change the state of the traffic lights from red to green but in correct sequence.
I have managed to pull it off but it doesnt work with a real car because the xbees (coordinator on the vehicle and end device on home-made traffic lights) take sometime to communicate which is not enough for the speed of a vehicle approaching traffic lights with lets say an average speed of 60km/h.
The system works like this. There is an arduino on the vehicle which has a GPS shield and an xbee set to COORDINATOR on it. In the program on the arduino it checks if the gps reads coordinates that are saved inside the arduino so it checks against real time coordinates and if they match, the xbee gets to send a message across to the corresponding xbees that are set as end-devices on the traffic lights which again setup is arduino + xbee.
The problem 1 is i need to make a faster connection between the xbees (COORDINATOR - END DEVICE)
Here is the arduino sketch for ARDUINO-GPS-COORDINATOR. Note: GPS Shield is from adafruit and i use their code plus some of mine.
// Test code for Adafruit GPS modules using MTK3329/MTK3339 driver
//
// This code shows how to listen to the GPS module in an interrupt
// which allows the program to have more 'freedom' - just parse
// when a new NMEA sentence is available! Then access data when
// desired.
//
// Tested and works great with the Adafruit Ultimate GPS module
// using MTK33x9 chipset
// ------> http://www.adafruit.com/products/746
// Pick one up today at the Adafruit electronics shop
// and help support open source hardware & software! -ada
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11);
SoftwareSerial xbee(13,12);
// If using hardware serial (e.g. Arduino Mega), comment out the
// above SoftwareSerial line, and enable this line instead
// (you can change the Serial number to match your wiring):
//HardwareSerial mySerial = Serial1;
Adafruit_GPS GPS(&mySerial);
// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences.
#define GPSECHO true
// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy
void setup()
{
Serial.begin(115200);
Serial.println("Adafruit GPS library basic test!");
xbee.begin(9600);
xbee.println("SoftwareSerial on coordinator working!");
GPS.begin(9600);
// uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
// uncomment this line to turn on only the "minimum recommended" data
//GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
// For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
// the parser doesn't care about other sentences at this time
// Set the update rate
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
// For the parsing code to work nicely and have time to sort thru the data, and
// print it out we don't suggest using anything higher than 1 Hz
// Request updates on antenna status, comment out to keep quiet
GPS.sendCommand(PGCMD_ANTENNA);
// the nice thing about this code is you can have a timer0 interrupt go off
// every 1 millisecond, and read data from the GPS for you. that makes the
// loop code a heck of a lot easier!
useInterrupt(true);
delay(1000);
// Ask for firmware version
mySerial.println(PMTK_Q_RELEASE);
}
// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
char c = GPS.read();
// if you want to debug, this is a good time to do it!
#ifdef UDR0
if (GPSECHO)
if (c) UDR0 = c;
// writing direct to UDR0 is much much faster than Serial.print
// but only one character can be written at a time.
#endif
}
void useInterrupt(boolean v) {
if (v) {
// Timer0 is already used for millis() - we'll just interrupt somewhere
// in the middle and call the "Compare A" function above
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
usingInterrupt = true;
} else {
// do not call the interrupt function COMPA anymore
TIMSK0 &= ~_BV(OCIE0A);
usingInterrupt = false;
}
}
// difference_ratio
float diff_ratio = 0.010;
// COORDINATES INDEX
float coord_lat = 23;
float coord_lon = 23;
uint32_t timer = millis();
void loop() // run over and over again
{
// in case you are not using the interrupt above, you'll
// need to 'hand query' the GPS, not suggested :(
if (! usingInterrupt) {
// read data from the GPS in the 'main loop'
char c = GPS.read();
// if you want to debug, this is a good time to do it!
if (GPSECHO)
if (c) Serial.print(c);
}
// if a sentence is received, we can check the checksum, parse it...
if (GPS.newNMEAreceived()) {
// a tricky thing here is if we print the NMEA sentence, or data
// we end up not listening and catching other sentences!
// so be very wary if using OUTPUT_ALLDATA and trytng to print out data
//Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
return; // we can fail to parse a sentence in which case we should just wait for another
}
// if millis() or timer wraps around, we'll just reset it
if (timer > millis()) timer = millis();
// approximately every 2 seconds or so, print out the current stats
if (millis() - timer > 2000) {
timer = millis(); // reset the timer
Serial.print("\nTime: ");
Serial.print(GPS.hour, DEC); Serial.print(':');
Serial.print(GPS.minute, DEC); Serial.print(':');
Serial.print(GPS.seconds, DEC); Serial.print('.');
Serial.println(GPS.milliseconds);
Serial.print("Date: ");
Serial.print(GPS.day, DEC); Serial.print('/');
Serial.print(GPS.month, DEC); Serial.print("/20");
Serial.println(GPS.year, DEC);
Serial.print("Fix: "); Serial.print((int)GPS.fix);
Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
if (GPS.fix) {
//Serial.print("Location: ");
//Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
//Serial.print(", ");
//Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
Serial.print("Location (in degrees, works with Google Maps): ");
Serial.print(GPS.latitudeDegrees, 4);
Serial.print(", ");
Serial.println(GPS.longitudeDegrees, 4);
//Serial.print("Speed (knots): "); Serial.println(GPS.speed);
//Serial.print("Angle: "); Serial.println(GPS.angle);
//Serial.print("Altitude: "); Serial.println(GPS.altitude);
//Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
if(GPS.latitudeDegrees + diff_ratio >= coord_lat && coord_lat >= GPS.latitudeDegrees - diff_ratio) {
if(GPS.longitudeDegrees + diff_ratio >= coord_lon && coord_lon >= GPS.longitudeDegrees - diff_ratio){
Serial.println("location OKAY");
xbee.println("K");
}
}
//if((float)GPS.latitude > (home_lat - diff_ratio) && (float)
}
}
}
The important part is where it says if(GPS.fix()) and later on.
And here is the sketch for the traffic light simulation which if it receives the message "K" it will stay to green light until it does not receive it anymore.
#include <SoftwareSerial.h>
SoftwareSerial xbee(3,2);
int greenled = 8; //Led's and pins
int yellowled = 9;
int redled = 10;
int ard_led = 13;
void setup(){
pinMode(greenled,OUTPUT);
pinMode(yellowled, OUTPUT);
pinMode(redled, OUTPUT);
pinMode(ard_led,OUTPUT);
Serial.begin(9600);
xbee.begin(9600);
}
void loop(){
delay(700);
if(xbee.available() > 0 && xbee.read() == 'K' && digitalRead(ard_led) == 0){
//Serial.println("second block");
digitalWrite(redled,HIGH);
delay(1000);
digitalWrite(yellowled, HIGH); //Yellow and red on for 2 seconds
digitalWrite(ard_led,HIGH);
}else if(xbee.available() > 0 && xbee.read() == 'K' && digitalRead(ard_led) == 1){
//Serial.println("third block");
blinking_green();
}
else if(!xbee.available() && xbee.read() != 'K' && digitalRead(greenled) == 0){
//Serial.println("first block");
digitalWrite(redled, HIGH);
delay(1000);
digitalWrite(yellowled, HIGH); //Yellow and red on for 2 seconds
delay(1000);
digitalWrite(redled, LOW); //Red and Yellow off
digitalWrite(yellowled, LOW);
digitalWrite(greenled, HIGH); //Green on for 5 seconds
delay(3000);
digitalWrite(greenled, LOW); //Green off, yellow on for 2 seconds
digitalWrite(yellowled, HIGH);
delay(1000);
digitalWrite(yellowled,LOW);
digitalWrite(redled,HIGH);
} else if(!xbee.available() && xbee.read() != 'K' && digitalRead(greenled) == 1 && digitalRead(yellowled == 0)){
//Serial.println("fourth block");
digitalWrite(greenled,LOW);
digitalWrite(yellowled, HIGH);
delay(1000);
digitalWrite(yellowled, LOW);
digitalWrite(redled,HIGH);
digitalWrite(ard_led,LOW);
}
}
void blinking_green(){
digitalWrite(redled, LOW); //Red and Yellow off
digitalWrite(yellowled, LOW);
digitalWrite(greenled,HIGH);
delay(2500);
}
Problem 2: How can i interrupt the traffic lights simulation instantly when it receives a message from a nearby arduino to change the traffic light to green BEFORE it finishes that loop? Because in a real example green and red light would say for over 20 seconds.
Question: Will a faster baud rate on the xbees achieve faster xbee communication?
thank you in advance
You need to change the loop() on your traffic light simulation. Have a variable you use to store the "state" of the light, along with a timer to keep track of when the next state change happens. This way, your loop can also check the XBee serial input every time around.
if (xbee_event_happened()) {
set_leds_off();
timer = millis();
state = STATE_FLASH_GREEN_OFF;
}
switch (state) {
case STATE_FLASH_GREEN_OFF:
if (millis() - timer > 1000) {
set_leds_green();
state = STATE_FLASH_GREEN_ON;
timer = millis();
}
break;
case STATE_FLASH_GREEN_ON:
if (millis() - timer > 1000) {
set_leds_off();
state = STATE_FLASH_GREEN_OFF;
timer = millis();
}
break;
case STATE_RED:
if (millis() - timer > 5000) {
set_leds_green();
state = STATE_GREEN;
timer = millis();
}
break;
case STATE_GREEN:
if (millis() - timer > 3000) {
set_leds_yellow();
state = STATE_YELLOW;
timer = millis();
}
break;
// etc.
}
This just covers the basics, but it shows an important aspect of loop() function design -- it should never run for more than a few milliseconds. Don't have a delay inside of your main loop, track the state of the device and then use logic to decide if the state needs to change on that pass of the loop.
Additionally, use higher baud rates when possible to avoid latency from serial transmissions, get rid of the 700ms delay in your loop, and organize your if/else structure better:
if (xbee.available() > 0) {
character = xbee.read();
if (character == 'K') {
if (digitalRead(ard_led)) {
// second block
} else {
// third block
}
} else if (character == 'X') {
// do something different? Vehicle left area?
}
}