I have a flex sensor connected with an arduino lily pad and an 47k ohms resistor.
My problem is that I am unable to get the consistent values from flex sensors: sometimes, i get very strange readings, even though the flex sensor is not in bending state.
I tried to change the values of straight_resistance and bend_resistance, but it doesn't seem to fix the issue.
Here is my code, looking forward for help.
const int FLEX_PIN = A0; // Pin connected to voltage divider output
// Measure the voltage at 5V and the actual resistance of your
// 47k resistor, and enter them below:
const float VCC = 4.98; // Measured voltage of Ardunio 5V line (r1/r1+r2)5
const float R_DIV = 47500.0; // Measured resistance of 3.3k resistor
// Upload the code, then try to adjust these values to more
// accurately calculate bend degree.
const float STRAIGHT_RESISTANCE = 24248750.00; // resistance when straight
const float BEND_RESISTANCE = 48544996.00; // resistance at 90 deg
void setup()
{
Serial.begin(9600);
pinMode(FLEX_PIN, INPUT);
}
void loop()
{
// Read the ADC, and calculate voltage and resistance from it
int flexADC = analogRead(FLEX_PIN);
float flexV = flexADC * VCC / 1023.0;
float flexR = R_DIV * (VCC / flexV - 1.0);
Serial.println("Resistance: " + String(flexR) + " ohms");
// Use the calculated resistance to estimate the sensor's
// bend angle:
float angle = map(flexR, STRAIGHT_RESISTANCE, BEND_RESISTANCE,
0, 90.0);
Serial.println("Bend: " + String(angle) + " degrees");
Serial.println();
delay(750);
}
The following values from your code don't seem right. These are values in the MOhms, not kOhms.
const float STRAIGHT_RESISTANCE = 24248750.00; // resistance when straight
const float BEND_RESISTANCE = 48544996.00; // resistance at 90 deg
Another problem is the map() function only works with integers! The floating point values you are passing in are converted to integers before the map() function uses them.
Related
i'm doing wireless sensor node using (esp32, DHT11, soil moisture and nrf24l01) and i want to add an battery to supply those sensors, also need to measure battery voltage.
For the battery, voltage always change to cant use as a Vcc reference, so i find there is an internal reference voltage.
Could anyone done with this give me some instruction.
Thank you
i'm gonna use LIFEPO4 3.3v normaly (3.6v at max) or 18650 3.7v/4.2v max
According to docs:
The default ADC full-scale voltage is 1.1V. To read higher voltages
(up to the pin maximum voltage, usually 3.3V) requires setting >0dB
signal attenuation for that ADC channel.
So set it to zero for 1.1v; next, you can read the voltage (in a loop for better accuracy) and then convert it to a valid voltage and find the percentage of battery level.
In the below example, the function would return the percentage of battery level. Remember to edit battery_max and battery_min based on your battery voltage levels. I assumed that you connect the battery to ADC1 channel 0 (GPIO 36).
Also, I recommend you create a resistor divider circuit to reduce the voltage level. If your input power supply drops down, the Arduino will feed directly from Analog input, which is undesirable. Remember that your voltage level should not exceed above 3.9v.
#include <driver/adc.h>
float battery_read()
{
//read battery voltage per %
long sum = 0; // sum of samples taken
float voltage = 0.0; // calculated voltage
float output = 0.0; //output value
const float battery_max = 3.6; //maximum voltage of battery
const float battery_min = 3.3; //minimum voltage of battery before shutdown
float R1 = 100000.0; // resistance of R1 (100K)
float R2 = 10000.0; // resistance of R2 (10K)
for (int i = 0; i < 500; i++)
{
sum += adc1_get_voltage(ADC1_CHANNEL_0);
delayMicroseconds(1000);
}
// calculate the voltage
voltage = sum / (float)500;
voltage = (voltage * 1.1) / 4096.0; //for internal 1.1v reference
// use if added divider circuit
// voltage = voltage / (R2/(R1+R2));
//round value by two precision
voltage = roundf(voltage * 100) / 100;
Serial.print("voltage: ");
Serial.println(voltage, 2);
output = ((voltage - battery_min) / (battery_max - battery_min)) * 100;
if (output < 100)
return output;
else
return 100.0f;
}
void setup()
{
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db); //set reference voltage to internal
Serial.begin(9600);
}
void loop()
{
Serial.print("Battery Level: ");
Serial.println(battery_read(), 2);
delay(1000);
}
If you add a divider circuit, you need to change battery_min and battery_max according to the new output of the divider circuit.
I'm using Arduino Micro to read from 5 flex sensors and display the corresponding angles to the Serial monitor. I am currently having quite some problems with the oscillating values I am getting from the analogRead(). It doesn't seem to matter whether the pin is connected to a flex sensor or just grounded - the output is oscillating a lot.
Originally everything was being read and outputted just fine but I wanted to have an exact 100Hz sampling frequency and tried to play a bit with Timer Interrupts. And that's when this oscillating behaviour started. I reversed to my original code, which just uses some delay(), and simplified to only read from two pins, but cannot seem to shake off the oscillations.
I think I may have messed up something about ADC when trying to implement Interrupts, but I don't know how to check it or fix it. Please, help me figure out how to fix this!
This is the raw output of analogRead. The drop in values occurs when I bend the flex sensor
And this is the resulting calculated angle. Also oscillating.
Here is my code minimal working example:
int fin;
const int input[5] = {A0,A1,A2,A3,A4}; // the analog pins
int flex[5]; // analog signal read
float flexV;
float flexR[5]; // resistance on the 47k resistor
int angle[5]; // joint angles
const float VCC = 4.98; // Measured voltage of Arduino 5V line
// Measured resistance of the 47k resistors R1-R5
const float R[5] = {45900.0,45900.0,45900.0,45900.0,45900.0};
// Calibration values of resistance measured during straight phase and 90 deg bend phase
const float R_STRAIGHT[5] = {37651.0,37651.0,37651.0,37651.0,37651.0};
const float R_BEND[5] = {71783.0,71783.0,71783.0,71783.0,71783.0};
void setup() {
}
void loop() {
for(fin = 0; fin <= 4; fin++) {
flex[fin] = analogRead(input[fin]);
flexV = flex[fin]*VCC/1023.0;
flexR[fin] = R[fin] * (VCC/flexV - 1.0);
angle[fin] = map(flexR[fin],R_STRAIGHT[fin],R_BEND[fin],0,90.0);
delay(1);
}
Serial.print(angle[0]);
Serial.print(" ");
Serial.print(angle[1]);
Serial.print(" ");
Serial.print(angle[2]);
Serial.print(" ");
Serial.print(angle[3]);
Serial.print(" ");
Serial.print(angle[4]);
Serial.print(" ");
Serial.println(millis());
delay(6);
}
ok, analogReads normally do have a little oscillation, its normal! they are measuring voltage values and depending on the sensor you are using they will oscillate, same idea of measuring voltage using a multi meter. if you want to learn a bit more about this, ADC's conversor is a good way to start.
What you need to do in order to prevent those oscillations is to develop a filter. this could be done on hardware or software. Obviously the software is the easiest way to go.
My tip for you would be to a average filter! it's a simple concept, you will get X readings at the same time of that sensors (values would go up and down on variation) and you would get the avarage value out of it.
Here is a simple example using your code:
int fin;
const int input[5] = {A0,A1,A2,A3,A4}; // the analog pins
int flex[5]; // analog signal read
float flexV;
float flexR[5]; // resistance on the 47k resistor
float average; //Variable to store the sum of measurements
int nSamples = 4; //Number of reading you are going to use
int angle[5]; // joint angles
const float VCC = 4.98; // Measured voltage of Arduino 5V line
// Measured resistance of the 47k resistors R1-R5
const float R[5] = {45900.0,45900.0,45900.0,45900.0,45900.0};
// Calibration values of resistance measured during straight phase and 90 deg bend phase
const float R_STRAIGHT[5] = {37651.0,37651.0,37651.0,37651.0,37651.0};
const float R_BEND[5] = {71783.0,71783.0,71783.0,71783.0,71783.0};
void setup() {
}
void loop() {
for(fin = 0; fin <= 4; fin++) {
/* A new for here to make readings and store them on the average variable */
for(int x = 0; x <= nSamples; x++){
flex[fin] = analogRead(input[fin]);
average = average + flex[fin];
}
/*Do de avarage and clear the value on this variable*/
flex[fin] = average/nSamples;
avarage = 0;
flexV = flex[fin]*VCC/1023.0;
flexR[fin] = R[fin] * (VCC/flexV - 1.0);
angle[fin] = map(flexR[fin],R_STRAIGHT[fin],R_BEND[fin],0,90.0);
delay(1);
}
Serial.print(angle[0]);
Serial.print(" ");
Serial.print(angle[1]);
Serial.print(" ");
Serial.print(angle[2]);
Serial.print(" ");
Serial.print(angle[3]);
Serial.print(" ");
Serial.print(angle[4]);
Serial.print(" ");
Serial.println(millis());
delay(6);
}
The idea here is simple, to smooth the values by doing this average, leading to more consistent values. Obviously, Higher number of samples improve the results.
It's simple math, if you are getting 4 values like: 45, 50, 55, 50, your average would be 50 (45+50+55+50 = 200/nSamples = 50)
So i'm making a "turret" type thing using two servo motors, controlled by a joystick. The code i'm running works, however it's very jerky and doesn't move that well, especially in diagonal lines. My code is as follows:
#include <Servo.h>
#define LASER 11
int x = 0;
Servo servo_1; // create servo object to control a servo
Servo servo_2;
// Arduino pin numbers
const int SW_pin = 2; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
int butt;
int joy_val;
void setup() {
pinMode(SW_pin, INPUT);
digitalWrite(SW_pin, HIGH);
servo_1.attach(9);// attaches the servo on pin 9 to the servo object
servo_2.attach(10);
pinMode(LASER, OUTPUT);
digitalWrite(LASER, HIGH);
Serial.begin(9600);
}
void loop() {
joy_val = analogRead(X_pin); // reads the value of joystick (between 0-1023)
joy_val = map(joy_val, 0, 1023, 0, 180); // servo value between 0-180
servo_1.write(joy_val); // sets the servo position according to the joystick value
delay(150);
joy_val = analogRead(Y_pin); // reads the value of joystick (between 0-1023)
joy_val = map(joy_val, 0, 1023, 0, 180); // servo value between 0-180
servo_2.write(joy_val); // sets the servo position according to the joystick
value
delay(150);
delay(15);
butt = digitalRead(SW_pin);
if (butt == LOW){
x = true;
}
if (x == true){
digitalWrite(LASER, LOW);
Serial.print(x);
}
}
I would really appreciate any advice or help, I'm fairly new to arduino :)
Servos are small and light and attempt to move to the position you tell them as quickly as they can. Joysticks can also change values very quickly, and they can also be glitchy. As a result, your servos are constantly making lots of small, quick movements, which can make the turret seem jerky.
I can think of two options, and you might want to do both:
Smooth out the joystick inputs with some low-pass filtering. This generally just means using a weighted average of the current and previous values. The idea is to eliminate a bad reading or two that might happen because of dirty contacts in the potentiometer.
Smooth out the motion. Instead of instantly trying to move the servos directly to the joysticks' current positions, move them toward the target position. On each iteration of the loop, they'll get closer to the target position instead of trying to jump there almost instantaneously.
For #2, there are a couple approaches I like to use.
One is to simply use a weighted average of the servo's current position and the target position. If you move the joystick a fair distance, the turret will swivel quickly but slow down as it approaches the target position.
The other is to use a physical model. Imagine creating a force vector that points from the servos' current position to the joysticks' target position and is proportional to the distance between them. Apply that force to the current point. Also apply a "friction" force that resists the current point's velocity. Numerically integrate the velocity and the position in the loop. If you move the joystick suddenly to a new position, then the turret will accelerate toward it and then slow down as it approaches it. Adjusting the constants used to compute the forces will let you control how "heavy" the mechanism appears to be.
I put a delay proportional to the speed of the servo. Try this (taken from my tutorial: Arduino Servo Motor Basics and Control):
#include <Servo.h>
#include <math.h>
Servo servo_1; // servo controller (multiple can exist)
int servo_pin = 3; // PWM pin for servo control
int joy_pin_x = A0; // pin for x-dir joystick
int joy_pin_y = A1; // pin for y-dir joystick
int offset_x = 0; // subtracting the initial joystick x-location
int offset_y = 0; // subtracting the initial joystick y-location
int pos = 90; // servo starting position aligned with joystick
int prev_deg = 0; // bound for reducing jitter
int x_prev = 0; // bound for reducing jitter
int y_prev = 0; // reducing jitter
void setup() {
servo_1.attach(servo_pin); // start servo control
Serial.begin(9600);
servo_1.write(pos); // move to center (joystick neutral)
Serial.println("Positioned at 90 Degrees");
offset_x = analogRead(joy_pin_x); // initial joystick x-val
offset_y = analogRead(joy_pin_y); // initial joystick y-val
}
void loop() {
int x_val = analogRead(joy_pin_x)-offset_x; // relative joystick x
int y_val = analogRead(joy_pin_y)-offset_y; // relative joystick y
if (abs(x_prev-x_val)<10 and abs(y_prev-y_val)<10){
// reduce jitter
} else {
x_prev = x_val;
y_prev = y_val;
float deg = 180-(int(atan2(x_val,y_val)*(180.0/PI))+90); // angle calc
if (abs(deg-prev_deg)>2 and deg>0 and deg<180){
servo_1.write(deg); // move servo to joystick location
delay(abs(deg-prev_deg)*(10.0/6.0));
prev_deg = deg;
Serial.println(deg); // print out degree
}
}
}
Notice the delay that is functionally dependent on the angle it's moving to - this will 'smooth' the servo and reduce jitter (though not completely remove it).
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.
I am creating my first Arduino program on the UNO r3. I have played with the Arduino Uno before just with petty example programs, etc. I am using two analog inputs to sense distance using 2 laser sensors with 0-5vdc scaling. These two inputs are 0-5vdc and I have ensured common grounding throughout. The two sensors are named left and right and are input to A0 and A1 respectively. I also have a differential POT which uses a 10K ohm POT wiper voltage as an input on A2. The theory of the program is to take the absolute value of the difference in input voltages between the left and right lasers then determine if the result is greater than or equal to the voltage on pin A2 from the POT wiper. Based on the resulting math, turn on or off a relay interposed to pin D13 via a transistor driver circuit.
The PROBLEM: I cannot achieve accurate changes in voltage on the scale (0-1023) on pins A0, A1, or A2. I have utilized the serial monitor to diagnose this problem. Not sure what the problem is, any help would be great. Also, I cannot achieve a 0 value on any of the above analog pins, even the POT wiper!!!
Here's my code:
const int lf_dist = A0; //names A0
const int rt_dist = A1; //names A1
const int differential = A2; //names A2
const int relay = 13; // select the pin for the relay coil
unsigned int left = 0; // variable to store the value coming from the left sensor
unsigned int right = 0; // variable to store the value coming from the right sensor
unsigned int diff = 0; // variable to store the value coming from the differential POT for maximum distance differential
unsigned int offset = 0; // variable that stores the value between the two laser sensors
void setup() {
Serial.begin(9600);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(relay, OUTPUT); // declare the relay pin as an OUTPUT:
analogReference(DEFAULT);
}
void loop()
{
unsigned int left = 0; // variable to store the value coming from the left sensor
unsigned int right = 0; // variable to store the value coming from the right sensor
unsigned int diff = 0; // variable to store the value coming from the differential POT for maximum distance differential
unsigned int offset = 0; // variable that stores the value between the two laser sensors
left = analogRead(A0); // read the value from the left laser
delay(5);
right = analogRead(A1); // read the value from the right sensor
delay(5);
diff = analogRead(A2); // read the value from the differential POT
delay(5);
offset = abs(left - right);
if(offset >= diff) // does math to check if left and right distances are greater than the value clocked in by the differential POT
{
digitalWrite(relay, LOW); // turns off the relay, opens the stop circuit, and turns on the yellow light
}
else
{
digitalWrite(relay, HIGH); // turns on the relay if all is good, and that keeps the machine running
}
Serial.print("\n left = " );
Serial.print(left);
Serial.print("\n right = " );
Serial.print(right);
Serial.print("\n differential = " );
Serial.print(diff);
delay(1000);
}
afaict, this should really be due to the floating pins surrounding the measuring pins, having erratic values, hence perturbating your measures. You should look at your values using arduinoscope, which will show you the interfering effects of the other floating pins on your measuring pins.
The easy workaround for this is to ground all analogical input pins you're not using, and put as much space as you can between both your inputs, so they don't interfere with each other.
I realize this thread is somewhat old not, but perhaps this will help someone. If you power the Arduino with only 5V, as you say you did with a regulator, you will get very erratic behavior, particularly from the analog pins. This is because you will start to brown out the internal voltage regulators that provide the AREF, 3.3, and 5.0 outputs. I've tested this for a robotics project I'm working on, and right around 6.5 volts, everything begins to go wrong. I suppose if you always provided 5.0 input voltage you could compensate for this effect, but in my case I used a LiPo battery that could range from 8.4 volts down to 6.0 volts, and everything goes crazy at 6.5 volts.
The minimum current that arduino sinks in during the sampling from potentiometer should not disturb the actual open input volts at the wiper.
Initialize the pins in pull up mode to avoid garbage values or 'floating' pins or use your own pull down/up resistors at the pins :)