I have an arduino uno with wifi shield and I want it to be able to go to source of signal.
The rssi that I get is usually -80 dBm above -40 dBm I assume the robot has found the source.
So the robot goes straight and checks every 2 seconds the rssi if the new signal is worse than it was before it turns 90 degrees right and goes straight and keeps doing that until it finds the source.
Void loop() is the logic of the robot.
int angle = 90;
char ssid[]="AndroidAP";
bool sourceFound = false;
long rssi = -100;
long prevRssi = 0;
void setup() {
Serial.begin(9600);
updateRSSI();
servoLeft.attach(8);
servoRight.attach(9);
goStraight();
}
void loop() {
if(!sourceFound){
updateRSSI();
if(prevRssi>rssi){
turnRight();
goStraight();
delay(2500);
}
if(rssi>-41){
stayStill();
detachServos();
sourceFound = true;
Serial.print("Source found.");
Serial.println();
}
}
}
/*MOVEMENT CONTROLS*/
void turnLeft(){
servoLeft.writeMicroseconds(1300);
servoRight.writeMicroseconds(1300);
delay(angle*10.6);
}
void turnRight(){
servoLeft.writeMicroseconds(1700);
servoRight.writeMicroseconds(1700);
delay(angle*10.6);
}
void turnAround(){
if((double)rand() / (double)RAND_MAX==0){
turnLeft();
turnLeft();
}else{
turnRight();
turnRight();
}
}
void stayStill(){
servoLeft.writeMicroseconds(1500);
servoRight.writeMicroseconds(1500);
}
void goStraight(){
servoLeft.writeMicroseconds(1600);
servoRight.writeMicroseconds(1444 );
}
void detachServos(){
servoLeft.detach();
servoRight.detach();
}
/*MOVEMENT CONTROLS*/
/*WIFI SHIELD CONTROLS*/
void updateRSSI(){
prevRssi = rssi;
uint8_t available_networks = WiFi.scanNetworks();
for (uint8_t net = 0; net < available_networks; ++net)
{
if (strcmp(WiFi.SSID(net), ssid) == 0)
{
// ssidFound = true;
rssi = WiFi.RSSI(net);
if(rssi-prevRssi<-10){ //disregard the measurement and try again
rssi = prevRssi;
updateRSSI();
}
Serial.print("Old: ");
Serial.print(prevRssi);
Serial.print(" dBm ");
Serial.print("New: ");
Serial.print(rssi);
Serial.print(" dBm");
Serial.println();
break;
}
}
}
The problem is that the signal varies a lot which will cause robot sometimes to turn right even when it's pretty close to the source and always going right is not the most effective way of getting to router it is quite random. Is there an easier way or more efficient way to find and get to the source?
Basically your robot is doing the localization part of a common task called "wardriving" (sounds illegal but it's not). I was recently doing some research in pretty much exactly what you were doing although some papers found that essentially the signal strength of WiFi stations is to weak and inconsistent for use.
Dartmouth study (Page 14) This study found that using typical war driving methods they were only able to detect between 40 and 60 % of all WiFi nodes and on average was around 30-40m of error from the actual transmitter.
Another study (Page 4) Here you have a plot of 3 base stations being sampled for signal strength at a constant distance away. You will notice a bell curve which looks to have a standard deviation of at least 5 (sadly no table for the data). However that does pretty clearly show how noisy of a signal you should expect.
I'm not saying that your goal is impossible I am saying however you will need to do a lot of filtering and move very slowly (something my project could not do). Contrary to instincts WiFi signal strength is incredibly noisy making accurate wardriving difficult without an extremely large data set. Hope having these papers at least helps curve your expectations.
Related
I am working on a school project for which I rotate a servo after a cable disconnects and a specific delay is over. This is my current code. We are using an Arduino Uno powered from the USB port
#include <Servo.h>
int reader=4;
int servo1Pin=8;
Servo servo1;
int value;
int pos=10;
int wacht=5000;
void setup() {
pinMode(reader, INPUT);
servo1.attach(servo1Pin);
}
void loop() {
value = digitalRead(reader);
servo1.write(pos);
if (value == LOW) {
delay(wacht);
pos=180;
}
else {
pos=10;
}
}
wacht is the specific delay. When we disconnected pin 4 to break that circuit we don't have a consistent time between the interruption of the power flow and the opening of the servo. It seems to vary from anywhere between 5 to 40 seconds of delay after triggering. Does anyone have any ideas to solve this issue?
try change
pinMode(reader, INPUT);
to
pinMode(reader, INPUT_PULLUP);
And for clarification delay don't use timer.
The order of your instructions seem strange. the usual order is:
Read
Decide
Act
Also, you may want to avoid sending useless instructions to the servo. For example, when you know the servo is already in the correct position. You should not rely on eternal code to do the right thing. In other terms, you have no idea how long servo1.write() takes to execute.
Which would give for your loop()
void loop()
{
if (digitalRead(reader) == LOW)
{
if (pos != 180)
{
delay(wacht); // delay() is only called once, when circuit breaks.
// this guarantees immediate response when circuit
∕/ closes again.
pos = 180;
servo1.write(pos);
}
}
else if (pos != 10)
{
pos = 10;
servo1.write(pos);
}
}
Also, have a look and implement Peter Plesník's answer. This will probably solve some of your problems. You input will definitely still have a random lag of up to 5 seconds when closing the circuit, though.
i am trying to make a stopwatch and counter project for arduino. Code aside, is this wired correctly?
The top button is to start the stopwatch, second is the button to start the counter (every press increases by one), and the bottom button should be to reset any of them. the green light is to show the stopwatch is selected and blue is to show the counter is selected. the lcd is to display everything obviusly. Also, what is the best way to learn to code this and how long would it take? Thanks.
This is the code as per your requirement. I have defined pins as per above connections. counter mode has minutes and seconds and it does not contain milliseconds as I am encountering problem to implement it. You can suggest me if you have got any way. Counter mode selection button is the same button which is going to be used to increment the counter.
#include <LiquidCrystal.h>
LiquidCrystal mylcd(7,6,5,4,3,2);
int counter_sel=12,stopwatch_sel=11,reset1=10,stopwatch_led=9,counter_led=8;
void setup()
{
mylcd.begin(16,2);
mylcd.setCursor(0,0);
mylcd.print("Counter and ");
mylcd.print("Stopwatch");
delay(1000);
pinMode(counter_sel,INPUT);
pinMode(stopwatch_sel, INPUT);
pinMode(reset1, INPUT);
pinMode(counter_led,OUTPUT);
pinMode(stopwatch_led, OUTPUT);
}
void loop()
{ int state1=digitalRead(counter_sel);
int state2=digitalRead(stopwatch_sel);
if (state1==0) {delay(300); counter(); } // call counter function
else if (state2==0) {delay(300); stopwatch(); } // call stopwatch function
}
void counter()
{ mylcd.clear();
digitalWrite(counter_led,1);
mylcd.setCursor(0,0);
mylcd.print("Counter Mode :");
short int i=0;
while(1)
{
int rst=digitalRead(reset1);
if (rst==0) { delay(300); break;}
int state1=digitalRead(counter_sel);
if (state1==0) { i++; delay(200);}
mylcd.setCursor(0,1);
mylcd.print(i);
}
digitalWrite(counter_led,0);
}
void stopwatch()
{
mylcd.clear();
digitalWrite(stopwatch_led,1);
long int ms=millis();
byte sec=0, mins=0;
mylcd.setCursor(0,0);
mylcd.print("Stopwatch Mode : ");
while(1)
{
mylcd.setCursor(0,1);
int state1=digitalRead(reset1);
if (state1==0){delay(300); break; }
if (sec==59) {mins++; sec=0;}
if ((millis()-ms)>1000) {sec++; ms=millis(); }
mylcd.print(mins);
mylcd.setCursor(3,1);
mylcd.print(":");
mylcd.setCursor(5,1);
mylcd.print(sec);
mylcd.print(":");
//mylcd.print(millis()-ms);
}
digitalWrite(stopwatch_led,0);
}
As much as I can see, and considering what you explained above, the connections are correct. But the thing is you need to make it clear as much as you can, because due to intersecting point in LCD connection, it would be very much harder to debug and resolve the connection problem, for that you must make it neat. To learn to code this stuff there is no rocket science, just use your wisdom, and start reading books, blogs, articles on arduino ide(which is too simple too use), c programming and microcontrollers , and youtube videos are the great source to learn to code, you should have handful experience of c programming, that's all.
I am using a Remote Control from FlySky. For my robotics project, I want to read PWM from the receiver on an Arduino. I came across 2 options:
pulseIn() arduino function
ISR(PCINTx_vect) (interrupt)
I cant use the first option of pulseIn() because I want my robot to continue with the operation if receiver signal are not coming (Tx not available etc.) So I used ISR.
Most reliable source : Mr. Brookings channel on YouTube.
Here is what I did (Only the required part for 1 axis):
// [R] where R is defined as 0 => [R] == [0]
volatile long CH[4]; //4 pwms to read so array of 4
float IN[3]={0,0,0}; // throttle is directly written
unsigned long timer[4],curr_time;
byte last[4];
void setup(){
PCICR |= (1 << PCIE0);
PCMSK0 |= (1 << PCINT0);
PCMSK0 |= (1 << PCINT1);
PCMSK0 |= (1 << PCINT2);
PCMSK0 |= (1 << PCINT3);
/* There is some more code here */
Serial.begin(115200);
}
void loop(){
/* There is some more code here */
IN[R] = ((CH[ROLL] - (1500 + R_TRIM))/11.0); // eg.: (1200 - (1500 + 8))/11.0 = -28 (interpreted as setpoint of -28° by the robot)
Serial.println(IN[R]);
}
ISR(PCINT0_vect){
curr_time = micros();
//channel 1 roll
if(PINB & B00000001){
if(last[ROLL] == 0){
last[ROLL] = 1;
timer[ROLL] = curr_time;
}
}
else if(last[ROLL] == 1){
last[ROLL] = 0;
CH[ROLL] = ((curr_time - timer[ROLL]));
}
}
I can read the PWM actually, but the robot keeps showing random twitches in its control at a given set point. I managed to trace the reason and found out that the PWM is insanely ridden by noise. Its not stable like it should be - steady. I have a MATLAB plot I used for analysis:
Signal (IN[R]):
Close up (when Tx stick was in the middle w/o movement) :
There are such spikes coming which is adding up to the control signal eventually making my robot to twitch. I tried some filtering techniques like 'moving average' and '1st and 2nd order exponential filters'. Also checked if it was due to power supplied to it - tried putting a capacitor or an iron core to the power lines but in vain. I can figure out how to remove them as their some constrains :
platform is Arduino Uno (slower in heavy computation)
Control loop shall not go below 100Hz (Currently its at 108Hz exponential filters on 4 axes took it to
~85Hz)
I would appreciate some guidance!
There's no way of telling from this if the input is noisy, or if your code is reading the PWM wrong, of if something else is going on, like external noise on the line, the Arduino's clock jitter, or other interrupts taking time. Also note that micros() on an Arduino Uno only has a resolution of 4µs, not 1µs.
You should check the input for jitter and noise, and try fast code that isn't influenced by other interrupts.
A fairly simple and fast way of getting the PWM pulse width is something like this, preferably without using anything else that uses interrupts:
volatile int pwmPulseWidth = 0;
volatile unsigned long int previousTime = 0;
void setup() {
attachInterrupt(0, rising, RISING);
}
void loop() {
// pwmPulseWidth is available here.
}
void rising() {
attachInterrupt(0, falling, FALLING);
previousTime = micros();
}
void falling() {
attachInterrupt(0, rising, RISING);
pwmPulseWidth = micros() - previousTime;
}
Untested, but it should give you an idea. This will return the width of the PWM pulse.
There are other ways of doing this, of course, like using a timer in capture mode.
Knowing the PWM frequency and the width of the PWM pulse is enough to reconstruct the PWM signal, should you want to.
I am trying to build an automatic plant watering system using ATmega16.The logic is, the sensor will give an analog input at PA0 which will be compared with a preset value to turn on/off water pump.
The following is the code fragment we used:
#include<avr/io.h>
int adc(void);
void pump(void);
int adc_value;
int main(void)
{
DDRC=0x01; //Defining PC0 as output
ADCSRA=0x87; //Setting the mode of operation
ADMUX=0x00; //Selection of channel and bit alignment
while(1)
{
adc_value=adc(); //reading moisture level
pump(); //Pump activator routine
}
return 0;
}
int adc(void)
{
int lower_bits,higher_bits,result;
ADCSRA |= (1 << ADSC)|(1 << ADIF); //Turn on conversion and clear flag
while(ADCSRA & (1 << ADIF) == 0); //wait for flag
lower_bits=ADCL;
higher_bits=ADCH;
result=lower_bits|(higher_bits<<8); //Accessing converted value by shifting
return result;
}
void pump(void)
{
if(adc_value>=700) //Pump ON trigger point
{
PORTC|=(1<<0);
}
else if(adc_value<=600) //Pump Off trigger point
{
PORTC&=~(1<<0);
}
}
Is there anything wrong in the code? Because after burning it, i am getting low voltage**(0.15**) for wet soil and high voltage(4.84) for dry soil from the analog sensor input which is ok … but the problem is, I am always getting voltage like 0.7 (and sometimes like 0.15) at PC0 in both cases(I am using multimeter for measuring this). There in no change in the values for dry and wet soil at PC0.. in such case where is the actual problem? Is there anything wrong in the circuit design or in the code?
Have you connected AREF to 5V? The wiring schematic from your other similar post doesn't show it.
As a side note, you might consider using ADLAR, aligning left. Then you only have to look at one byte, since you don't seem to concerned about 10 bits of precision anyway.
I'm trying to read data from a photocell resistor and my Arduino Diecimila and then graph it in real-time with Processing.
It should be painfully simple; but it’s growing into a little bit of a nightmare for me.
The code I'm running on my Arduino:
int photoPin;
void setup(){
photoPin = 0;
Serial.begin(9600);
}
void loop(){
int val = int(map(analogRead(photoPin), 0, 1023, 0, 254));
Serial.println(val); // Sending data over Serial
}
The code I'm running in Processing:
import processing.serial.*;
Serial photocell;
int[] yvals;
void setup(){
size(300, 150);
photocell = new Serial(this, Serial.list()[0], 9600);
photocell.bufferUntil(10);
yvals = new int[width];
}
void draw(){
background(0);
for( int i = 1; i < width; i++ ){
yvals[i - 1] = yvals[i];
}
if(photocell.available() > 0){
yvals[width - 1] = photocell.read();
}
for(int i = 1; i < width; i++){
stroke(#ff0000);
line(i, yvals[i], i, height);
}
println(photocell.read()); // For debugging
}
I've tested both bits of code separately, and I know that they work. It's only when I try to have the input from the Arduino going to Processing that the problems start.
When I view the data in Arduino's "Serial Monitor", I get a nice constant flow of data that seems to look valid.
But when I read that same data through Processing, I get a repeating pattern of random values.
After a closer look at the resources at hand, I realized that the problem had already been solved for me by the folks over at http://arduino.cc
http://arduino.cc/en/Tutorial/Graph
Oh how much time I could have saved if I had seen that earlier.
You could transmit that data with the Plotly Arduino API, which along with the documentation and setup is available here. Basic idea: you can continuously stream data from your Arduino, or transmit a single chunk.
Then, if you want to embed it into a site, you'll want to grab the URL and use this snippet:
<iframe id="igraph"
src="https://plot.ly/~abhishek.mitra.963/1/400/250/"
width="400"
height="250"
seamless="seamless"
scrolling="no"></iframe>
You can change the width/height dimensions in that snippet. Note: you need to swap in your own URL there to get it stream through.
Here's an example of how it looks to stream Arduino data
Full disclosure: I work for Plotly.