Robotic arm homing - arduino

I'm making a humanoid robotic arm and so far i've designed the shoulder. for rotation I've been using a high torque dc motor with an encoder that has a hall sensor and uses 17 pulses for one complete rotation along with a gear box that has a gear ratio of 1:625 making total pulses to (625x17). Now the robotic arm shoulder should only moves around 90 degrees making the pulses (625x17x0.25 = 6256.25). I'm controlling this dc motor with an Arduino and an L298 H-bridge module for controlling the motor. I've written a code using the Arduino IDE and I am still a beginner at this.
The main premise here is to do the homing of the shoulder. Basically when the robot turns on first it moves in the counter clockwise direction looking for the limit switch and then from their start counting the pulses to reach 90 degrees (6256.25 pulses) clock wise.
The main problem here is that after pressing the limit switch the motor starts to rotate in the clockwise direction after hitting the limit switch but it does not stop after reaching 90 degrees.
Any help is highly appreciated. Im new to coding as well as stack overflow.
#define Encoder_output_A 2
#define Encoder_output_B 3
int y;
int pos = 0;
int motorpin1=5;
int motorpin2=4;
float Count_pulses = 0;
float Count_rounds = 0;
int Limswitch = 7;
void setup() {
Serial.begin(9600); // activates the serial communication
pinMode(Encoder_output_A,INPUT); // sets the Encoder_output_A pin as the input
pinMode(Encoder_output_B,INPUT); // sets the Encoder_output_B pin as the input
attachInterrupt(digitalPinToInterrupt(Encoder_output_A),DC_Motor_Encoder,RISING);
pinMode(motorpin1,OUTPUT);
pinMode(motorpin2,OUTPUT);
pinMode(Limswitch,INPUT);
homing();
}
void loop() {
Serial.print("Result: ");
Serial.println(Count_pulses);
Serial.println(Count_rounds);
delay(100);
y=digitalRead(Limswitch);
if(y==LOW ||Count_pulses>=2656.25)// 17 x 625 x 0.25 = 2656.25
{digitalWrite(motorpin1,LOW);
digitalWrite(motorpin2,LOW);
} else{
digitalWrite(motorpin1,HIGH);
digitalWrite(motorpin2,LOW);
}
}
//The purpose of this code is to count the ouput pulses or the encoder outputs as you rotate the Motor shaft.
void DC_Motor_Encoder(){
int b = digitalRead(Encoder_output_B);
if(b > 0){
Count_pulses++;
Count_rounds = Count_pulses/17;
}
else{
Count_pulses--;
}
}
void homing() {
y=digitalRead(Limswitch);
if(y==HIGH && Count_pulses==0)
{while(y==HIGH){digitalWrite(motorpin1,HIGH);
digitalWrite(motorpin2,LOW);
y=digitalRead(Limswitch);
}
}
else if(y==LOW){
while(Count_pulses < 2657){
digitalWrite(motorpin1,LOW);
digitalWrite(motorpin2,HIGH);
}
}
if(Count_pulses>=2656.25)
digitalWrite(motorpin1,LOW);
digitalWrite(motorpin2,LOW);
}

Your code is a bit hard to read the way you have it formatted, I suggest you follow a more typical standard. It will make pulling out issues easier. Here's how I would format your homing() function:
void homing() {
y=digitalRead(Limswitch);
if(y==HIGH && Count_pulses==0) {
while(y==HIGH) {
digitalWrite(motorpin1,HIGH);
digitalWrite(motorpin2,LOW);
y=digitalRead(Limswitch);
}
} else if(y==LOW){
while(Count_pulses < 2657) {
digitalWrite(motorpin1,LOW);
digitalWrite(motorpin2,HIGH);
}
}
if(Count_pulses>=2656.25) {
digitalWrite(motorpin1,LOW);
digitalWrite(motorpin2,LOW);
}
}
The issue may be that you are missing a curly bracket after the last if statement. I've added it above.
This: if(Count_pulses>=2656.25) {
Vice your original: if(Count_pulses>=2656.25)

Related

Arduino timer not counting accuratly

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.

Arduino Interrupt getting triggered more than once - Working with Hall Sensor for RPM

I am working with an hall sensor for counting the RPM of my wheel. I am using following sensor :
My code as follows :
int hall_pin = 3; // digital pin
float hall_threshold = 5.0;
float count = 0;
void setup() {
pinMode(hall_pin,INPUT);// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(hall_pin),hall_ISR,RISING);
}
void loop() {
count = 0.0;
float start = micros();
while(1){
if(count >= hall_threshold){
break;
}
}
float end_time = micros();
float time_passed = (end_time - start)/1000000.0; // in seconds
float rpm = (count/time_passed)*60.0;
Serial.println(rpm);
delay(10000);
}
void hall_ISR()
{
count+=1.0;
}
I am using digital pin 3 to read from sensor and count the number of times it detects magnetic field using interrupt. Since the sensor outputs 1 on detecting, I have used a RISING interrupt. Once the count is greater than 5 then the control comes out of the infinite loop and calculates the RPM. The problem is this interrupt is getting triggered multiple times. I have tried using detachInterrupt(hall_pin) but it is not working. I also tried to decrease the sensitivity of hall sensor using the trimmer provided.
I am sure the problem is not with the sensor, it is with the interrupt, I guess. Where am I going wrong?
Any help is very much appreciated!
Thank you.

Creating an oscillating tone using Arduino, ATTiny85 and a simple buzzer

First a bit of background. I am attempting to make an LED glow and a buzzer produce a tone that sweeps smoothly up and down in frequency, like an air raid siren. I am using an Arduino Uno, connected to an ATTiny85 chip operating at 8hz clock speed. An SPDN contact switch is used to provide input on 4, while 0 and 1 go out to the positive legs of the buzzer and LED respectively. Suitable resistors are being used to limit current, which is 5v from the Arduino board.
Now, my problem. I can produce a constant tone at any frequency I like. I can produce a tone that goes back and forth between two tones like a UK police siren (Dee-Daa-Dee-Daa etc) but I am unable to generate a smooth transition between two tones. The LED works as expected.
What I actually observe is a single tone that does not vary. Once or twice I've managed to produce a tone that varies, but randomly within the given range rather than smoothly.
I am not using the tone() Arduino command and would prefer not to, as it is not best suited for what I am trying to accomplish.
Here is my code:
const float pi2 = 6.28318530717;
const int buzzer = 0;
const int light = 1;
const int button = 4;
// Set up the pins as input and output
void setup() {
pinMode(buzzer, OUTPUT);
pinMode(light, OUTPUT);
pinMode(button, INPUT);
}
bool buzzerState = LOW;
float nextFlip = 0;
// Generates a sine wave for the given uptime, with a period and offset (in milliseconds).
float sineWave(float uptime, float period, float offset, float minimum, float maximum) {
float s = sin(((uptime + offset) * pi2) / period);
// Normalise the result between minimum and maximum
return (s + 1) / 2 * (maximum - minimum) + minimum;
}
// Returns the time between buzzer inversions based on a given system uptime.
float frequency(float uptime) {
return sineWave(uptime, 5000, 0, 1, 10);
}
// Main loop
void loop() {
// Check button state and turn the light on or off
bool buttonDown = digitalRead(button);
digitalWrite(light, buttonDown);
// Check to see if it's time for the next buzzer inversion
float m = micros();
if (!buttonDown || m < nextFlip) return;
// Get the inverse of the current buzzer state
if (buzzerState == HIGH) {
buzzerState = LOW;
} else {
buzzerState = HIGH;
}
// Write the new buzzer state
digitalWrite(buzzer, buzzerState);
// Decide when the next inversion will occur
nextFlip = m + frequency(m);
}
Silly mistake! I finally noticed: I'm reading micros() where I meant to read millis() - in other words, it was oscillating, just a thousand times faster than I intended it to! Multiplying all values up by a factor of 1000 in the sine wave function produced a lovely oscillation.

Following the source of WiFi signal using rssi

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.

getting wrong output in atmega16

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.

Resources