Line follower robot using atmega8 - avr

I Am new to AVR programming. I am trying to build a Line follower robot using atmega8 which can park itself when both the infrared sensors detect black . my sensors are connected to the PORTD2 and PORTD3, and my Motors are connected to PORTB0 and PORTB4 . I planned on running and then delaying the motor for 3 second and the switching them off but the robot has started to work haphazardly. Please help me find out what is wrong with my code.
#include<avr/io.h>
#include<util/delay.h>
int main()
{
DDRD=0b00000000;
DDRB=0b11111111;
uint8_t sensor;
uint8_t A= 0b00000000;
while(1)
{
A=0b00000000;
sensor = PIND;
A= sensor|0b11110011;
switch(A)
{
case 0b11110011:
PORTB=0b00010001;
_delay_ms(3000);
PORTB=0b00000000;
break;
case 0b11111011:
PORTB=0b00000001;
break;
case 0b11110111:
PORTB=0b00010000;
break;
case 0b11111111:
PORTB=0b00010001;
break;
}
}
return 0;
}

You can try declaring sensor as volatile:
volatile uint8_t sensor;

If you are compiling with any optimization, the delay functions don't work properly.
Otherwise, it looks straightforward, depending on the details of the sensors and motors. What is erratic about the behaviour?

Related

if statement in while loop arduino

code dose not perfect work
int pushButton = 2;
int gearstatus = 0 ;
int buttonState;
void setup() {
Serial.begin(9600);
pinMode(pushButton, INPUT);
}
void gearfunction(){
buttonState = digitalRead(pushButton);
while(gearstatus <= 5){
Serial.println( gearstatus);
if(buttonState == HIGH){
gearstatus++;}
}
}
void loop() {
gearfunction();
}
in this code i am trying to if statement in while loop,
but code doesn't work . can some one give me how to did this ? i want to increase gearstatus up to 5 but value not increase .
It doesn't work because marking pushButton as INPUT wont make it equal to HIGH
You need to put inside setup function after the input instruction:
digitalWrite(pushButton,HIGH)
A Button-Pin has to be initialized on Setup, like in the preceding answer or with:
pinMode(2, INPUT_PULLUP); //Pin-D2. This command activates it's internal
//resistor, so the resulting signal is clear HIGH and not floating like a duck...
Hint: on StartUp all pins of a uC are floating-inputs, so if pulled-UP
they may be grounded with a button or anything else like a sensor, NTC-Resistor, etc.), resulting in a clear "1" or "0" - or a defined Analog-Signal, which later may be scanned like:
boolean buttonState = digitalRead(2); //Pin D2
//or
int value = analogRead(A0); //Pin A0
Can you please explain a little what you are trying to do, It would be better if you attach a small image of the circuit. I can suggest you the code and answer using circuits.io if you give the required info.

Arduino/MPU6050/AdafruitMotorShieldV2: script hangs/freezes when turn on motors

I'm a newby to robotics and electronics in general, so please don't assume I tried anything you might think is obvious.
I'm trying to create a cart which will basically run around by itself (simple AI routines to avoid obstacles, go from pt. A to pt. B around corners, follow lines, etc.). I'm putting together an Adafruit Arduino Uno R3 with the Adafruit Motor Shield v2 and an MPU-6050. I'm using the "breadboard" on the Motor Shield for the circuitry, soldering everything there.
I can get all the pieces working independently with their own scripts: the Motor Shield drives the 4 motors as expected using the Adafruit library; I'm using the "JRowberg" library for the MPU-6050, and started with the example MPU6050_DMP6.ino, which works fine as long as the cart motors are turned off. My only changes in the example script below are motor startup and some simple motor commands.
As long as I leave the switch which powers the motors off, everything seems fine: it outputs to the Serial window continuously with Euler data which, I assume, is correct. However, a few seconds after I turn on the power to the motors (and the wheels start turning), it just hangs/freezes: the output to the Serial window stops (sometimes in mid-line), and the wheels keep turning at the speed of their last change. Sometimes I see "FIFO overflow" errors, but not always. Sometimes I see "nan" for some of the floating point values before it hangs, but not always.
Some things I've tried, all of which changed noting:
* I've swapped out the MPU-6050 board for another from the same manufacturer.
* I've tried moving the MPU-6050 away from the motors using a ribbon cable.
* I've changed the I2C clock using JRowber's advice (a change in a .h file and changing the value of the TWBR variable), but I don't think I've tried all possible values.
* I've changed the speed of the MotorShield in the AFMS.begin() command, although, again, there are probably other values I haven't tried, and I'm not sure how in-sync this and the TWBR value need to be.
And some other things, all to no avail.
Below is an example script which fails for me:
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
#include "Adafruit_MotorShield.h"
#include "utility/Adafruit_PWMServoDriver.h"
#define DEBUG 1
MPU6050 mpu;
#define OUTPUT_READABLE_EULER
#define LED_PIN 13
bool blinkState = false;
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
#define NUM_MOTORS 4
#define MOTOR_FL 0
#define MOTOR_FR 1
#define MOTOR_RR 2
#define MOTOR_RL 3
Adafruit_DCMotor *myMotors[NUM_MOTORS] = {
AFMS.getMotor(1),
AFMS.getMotor(2),
AFMS.getMotor(3),
AFMS.getMotor(4),
};
#define CHANGE_SPEED_TIME 500
long changeSpeedMillis = 0;
int curSpeed = 30;
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
void setup() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// start the motor shield.
AFMS.begin(); // create with the default frequency 1.6KHz
// AFMS.begin(4000); // OR with a different frequency, say 4KHz
// kill all the motors.
myMotors[MOTOR_FL]->run(BRAKE);
myMotors[MOTOR_FL]->setSpeed(0);
myMotors[MOTOR_FR]->run(BRAKE);
myMotors[MOTOR_FR]->setSpeed(0);
myMotors[MOTOR_RR]->run(BRAKE);
myMotors[MOTOR_RR]->setSpeed(0);
myMotors[MOTOR_RL]->run(BRAKE);
myMotors[MOTOR_RL]->setSpeed(0);
Serial.println("Motor Shield ready!");
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
while (Serial.available() && Serial.read()); // empty buffer
while (!Serial.available()); // wait for data
while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize) {
// as per Vulpo's post.
delay(10);
if (millis() > changeSpeedMillis) {
curSpeed += 20;
if (curSpeed > 256) {
curSpeed = 30;
}
Serial.print("changing speed to: ");
Serial.println(curSpeed);
myMotors[MOTOR_FL]->run(FORWARD);
myMotors[MOTOR_FL]->setSpeed(curSpeed);
myMotors[MOTOR_FR]->run(FORWARD);
myMotors[MOTOR_FR]->setSpeed(curSpeed);
myMotors[MOTOR_RR]->run(FORWARD);
myMotors[MOTOR_RR]->setSpeed(curSpeed);
myMotors[MOTOR_RL]->run(FORWARD);
myMotors[MOTOR_RL]->setSpeed(curSpeed);
changeSpeedMillis = millis() + CHANGE_SPEED_TIME;
}
}
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & 0x02) {
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180/M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180/M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180/M_PI);
#endif
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}
}
Have you considered that your troubles are caused by interference from the currents flowing into your motors?
If your motors are DC brush, then more interference may be radiated from the brushes back into your various wires.
As a first step, perhaps let only one motor work and see if hangups diminish in frequency (although, to be sure, you need a 'scope onto a few wires carrying logic signals.

Arduinos IDE Serial Monitor works while XCode popen() does not.

I am trying to communicate with my Arduino through popen() function. I wrote a simple Mac App in XCode:
- (IBAction)ButtonPressed:(id)sender {
popen("echo hello world > /dev/tty.usbmodem1411", "r");
}
And here is the Arduino Code:
int redPin = 8;
int greenPin = 9;
int bluePin = 10;
int inByte = 0; // for incoming serial data
void setup()
{
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
Serial.begin(8000);
}
void loop()
{
if (Serial.available() > 0) {
// get incoming byte:
inByte = Serial.read();
Serial.print(inByte);
setColor(inByte,inByte,inByte);
delay(1000);
setColor(0,0,0);
}
}
void setColor(int red, int green, int blue)
{
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
}
Now, when I try to use Arduino Serial Monitor and write some gibberish there my LED's light up fine and I see that it is working. When I run my XCode program, press the button, nothing happens. I did set break points and I did check that the line of code gets executed. I double checked the serial port, it is all fine, but no luck. It still does not work.
Basically I solved the problem by using IOKit/ioctl. I am still not sure why popen() did not work, might be because Arduino IDE was using the port and thus it was not available, however IOKit works like a charm. Plus it allows more control and flexibility, you can actually search for ports before you start and see if they are available. If anyone runs in to the same problem check http://playground.arduino.cc/Interfacing/Cocoa#IOKit. Thanks for all help.

Controlling Arduino-connected servos with the WiFly shield via an ad-hoc connection

I'm trying to control some servos connected to an Arduino (breadboarded) over an ad-hoc connection. I've set up the network, can telnet into the WiFly, and can even do some simple controls (for example, turning an LED on and off). However, when I try to start and stop a servo based on a character typed into the telnet session, the servo will run for half a second, then stop - after which the WiFly stops responding completely. My code for the LED works:
void loop(){
delay(100);
index = 0;
while(serialWiFly.available() > 0){
if(index < 100){
inputIn = serialWiFly.read();
input[index] = inputIn;
index++;
input[index] = '\0';
}
if(inputIn == 'a')
digitalWrite(13, HIGH);
if(inputIn == 'z')
digitalWrite(13, LOW);
} //end while
serialWiFly.flush();
delay(10);
} //end loop
This lets me turn the LED on by pressing 'a', and off by pressing 'z'. Cool. But when I add a moveForward() function:
void moveForward(){
myservo.write(124);
}
And call it from my loop:
if(inputIn == 'a') moveForward();
The servo will spin and then stop, as I've described. I'm at a loss here - how can I fix this problem?
If anyone stumbles across this, I still don't know what caused it, but I fixed it by using an Arduino MiniPro instead of my standalone breadboarded unit. I believe it might have something to do with pulling the 'reset' pin HIGH or LOW (which I neglected to do in my breadboarded version.)

do_gettimeofday() in Beaglebone giving wrong time

I am trying to measure the time period of a square wave on a Beaglebone running Angstrom OS. I have written a kernel driver to register an ISR in which I'm timing the pulses. Everything is working fine, but the time interval being measured is completely wrong. I'm using do_gettimeofday() function to measure the time. When I do the same in userspace program using poll() function, I'm able to achieve correct values (it shows around 1007 us for a 1000us wave), but when I use the driver to measure the pulse, I get the interval as 1923us. I have no idea why the time interval in the kernel is higher than that in user space. I have attached my code below.
I would be grateful if someone can find the mistake in my program.
kernel ISR:
static irqreturn_t ISR ( int irq, void *dev_id)
{
prev = c;
do_gettimeofday(&c);
printk(KERN_ALERT "%ld", (c.tv_usec - prev.tv_usec));
return IRQ_HANDLED;
}
userspace prog:
while(1){
prev = start;
gettimeofday(&start, NULL);
rc = poll(&fdset, 1, 20000);
if(rc < 0){
printf("Error in rc\n");
return -1;
}
if(rc == 0){
printf("Timed out\n");
return -1;
}
if (fdset.revents & POLLPRI) {
len = read(fdset.fd, buf, 2);
printf("%ld\n", (start.tv_usec - prev.tv_usec));
}
}
For profiling interrupt latency, I find it quite useful to be lazy and to set a GPIO pin then measure the time with an oscilloscope. Probably not the answer you want, but it might help you over a hurdle quickly.

Resources