Arduino - PD - Line Following - arduino

#include <QTRSensors.h>
#define NUM_SENSORS 5 //Number of sensors used
#define NUM_SAMPLES_PER_SENSOR 4 //Average 4 analog samples per sensor reading
#define EMITTER_PIN 13 //Emitter is controlled by digital pin 2
QTRSensorsAnalog qtra((unsigned char[]) {0,1,2,3,4},
NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS]; //Variable Array for sensor values
const double kp = .505; //Variable for adjusting KP Value
const double kd = 150; //Variable for adjusting KD Value
const int max_speed = 255; //Variable for the Maximum Speed of the Motors
unsigned int position = 0; //Variable for holding the calculated position
int set_point = 1500;//Variable for holding the value of the center of the line
int error = 0; //Variable for holding the error from center of line based on position
int last_error = 0; //Variable for holding the previous error
int white = 0; //Variable for reading the line over white or black
int max_difference = 80 ;
double spd_right; //Speed for the Right Motor
double spd_left; //Speed for the Left Motor
int derivative = 0; //Value for the derivative
int error_value = 0; //Value for the error_value calculated from the pd function
int key_s6 = 2;//Declaring Digital Push Button
int E1 = 5; //M1 Speed Control
int E2 = 6; //M2 Speed Control
int M1 = 4; //M1 Direction Control
int M2 = 7; //M2 Direction Control
int sensors_sum = 0;
//Setup Method that includes calibration
void setup(){
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(13, OUTPUT);
calibration();
set_Point();
}//Ends Setup
void loop (){
get_sum();
white_or_black();
pid_calc();
adjust_control();
set_motors();
}//Ends Loop*/
/*Method for calibrating set_point on individual tracks
*/
void set_Point(){
qtra.readCalibrated(sensorValues);
for (int i = 0; i <= 5; i++){
set_point = sensorValues[i] + set_point;
}//Ends For
}//Ends set_point Method
/*Method for Calibrating the sensors to the ambiance lighting and
* varying contrasts of each individual track.
*/
void calibration (){
for (int i = 0; i<250; i++){
qtra.calibrate();
delay(20);
}//Ends For
}//Ends Calibration Method
/*Method for calculating the sum of all the sensors to be used in the
* white_or_black method for determining the background color of the track
*/
void get_sum(){
qtra.readCalibrated(sensorValues);
for (int i = 0; i <= 5; i++){
sensors_sum = sensorValues[i] + sensors_sum;
}//Ends For
}//Ends get_sum Method
/*Method for determining the background color of the current portion of the
* track based off of the value returned by get_sum and adjusting a variable
* to follow a white of black line as necessary.
*/
void white_or_black(){
if (sensors_sum > 2000){
white = 1;
}//Ends If
else{
white = 0;
}//Ends Else
}//Ends white_or_black Method
/*Method for following the line based of the position, proportional,
* and derivative
*/
void pid_calc(){
position = qtra.readLine(sensorValues, QTR_EMITTERS_ON, white);
error = position - set_point;
derivative = error-last_error;
last_error = error;
error_value = int(error*kp+derivative*kd);
}//Ends pid_calc Method
void adjust_control(){
if (error_value>max_difference){
error_value = max_difference;
}//Ends If
else if(error_value < max_difference){
error_value = -max_difference;
}//Ends If
if (error_value < 0 ){
spd_right = max_speed + error_value;
spd_left = max_speed;
}//Ends If
else{
spd_right = max_speed;
spd_left = max_speed - error_value;
}//Ends Else
}//Ends adjust_control Method
void set_motors(){
analogWrite(M1, HIGH);
analogWrite(M2, HIGH);
analogWrite(E1, constrain(spd_right, 0, max_speed));
analogWrite(E2, constrain(spd_left, 0, max_speed));
}//Ends set_motors Method
void stop(){
analogWrite(E1, 0);
analogWrite(E2, 0);
}//Ends Stop Method
I'm new to the arduino language. This is my first program and I wrote it last night. It's a PD Line Following example.
I'm currently having issues with the motors adjusting. Simply put it just goes straight.
I'm using a QTR Analog Sensor Array. I might switch to digital because one of the analog inputs on the romeo board I have is not working. Does anyone one have any suggestions or improvements to my logic?

void set_Point(){
qtra.readCalibrated(sensorValues);
for (int i = 0; i < NUM_SENSORS; i++){
set_point += sensorValues[i];
}
}
A strange thing about this loop is that is set_point is not initialised (to zero) before adding, and not divided (by i==NUM_SENSORS-=5) after the summation.

Related

MPU6050 FIFO overflow and freezing problems

Im using the sensor MPU6050 to control movements of my robotic arm. The codes work fine when it is a standalone program but i keep encountering 'FIFO overflow' when the codes are complied into the main program. This is the code that i am using.
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 mpu;
RF24 radio(9, 8); // CE, CSN
const byte address[6] = "00001";
const int AccReadings = 10;
//Wrist Roll
int DataX[AccReadings];
int WRIndex = 0;
int WRtotal = 0;
int WRaverage = 0;
//Wrist Pitch
int DataY[AccReadings];
int WPIndex = 0;
int WPtotal = 0;
int WPaverage = 0;
//Shoulder Lift
int DataY2[AccReadings];
int SLIndex = 0;
int SLtotal = 0;
int SLaverage = 0;
//Elbow Lift
int ELaverage = 0;
//Arm Rotation
int ARaverage = 0;
float correct;
#define OUTPUT_READABLE_YAWPITCHROLL
#define INTERRUPT_PIN 2
bool blinkState = false;
// MPU control/status vars
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
// orientation/motion vars
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
struct Sensor_Data
{
int WristRoll;
int WristPitch;
int ShoulderLift;
int ElbowLift;
int ArmRotation;
};
Sensor_Data data;
//Interrupt Detection
volatile bool mpuInterrupt = false;
void dmpDataReady()
{
mpuInterrupt = true;
}
void setup()
{
radio.begin();
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();
//Zero-fill Arrays
for (int i = 0; i < AccReadings; i++)
{
DataX[i] = 0;
}
for (int j = 0; j < AccReadings; j++)
{
DataY[j] = 0;
}
for (int k = 0; k < AccReadings; k++)
{
DataY2[k] = 0;
}
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000);
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
while (!Serial);
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
devStatus = mpu.dmpInitialize();
mpu.setXGyroOffset(49);
mpu.setYGyroOffset(-18);
mpu.setZGyroOffset(9);
mpu.setZAccelOffset(4427);
if (devStatus == 0)
{
mpu.setDMPEnabled(true);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
dmpReady = true;
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(")"));
}
}
void loop()
{
/*smoothWR();
movementWR();
smoothWP();
movementWP();
smoothSL();
movementSL();*/
ElbowMovement();
radio.write(&data, sizeof(Sensor_Data));
}
void smoothWR()
{
WRtotal = WRtotal - DataX[WRIndex];
DataX[WRIndex] = analogRead(A0);
WRtotal = WRtotal + DataX[WRIndex];
WRIndex = WRIndex + 1;
if (WRIndex >= AccReadings)
{
WRIndex = 0;
}
WRaverage = WRtotal / AccReadings;
//Serial.println(WRaverage);
}
void movementWR()
{
WRaverage = map(WRaverage, 278, 419, 0, 180);
data.WristRoll = constrain(WRaverage, 0, 180);
//Serial.println(data.WristRoll);
}
void smoothWP()
{
WPtotal = WPtotal - DataY[WPIndex];
DataY[WPIndex] = analogRead(A1);
WPtotal = WPtotal + DataY[WPIndex];
WPIndex = WPIndex + 1;
if (WPIndex >= AccReadings)
{
WPIndex = 0;
}
WPaverage = WPtotal / AccReadings;
//Serial.println(WPaverage);
}
void movementWP()
{
WPaverage = map(WPaverage, 280, 421, 0 , 135);
data.WristPitch = constrain(WPaverage, 0, 135);
//Serial.println(data.WristPitch);
}
void smoothSL()
{
SLtotal = SLtotal - DataY2[SLIndex];
DataY2[SLIndex] = analogRead(A2);
SLtotal = SLtotal + DataY2[SLIndex];
SLIndex = SLIndex + 1;
if (SLIndex >= AccReadings)
{
SLIndex = 0;
}
SLaverage = SLtotal / AccReadings;
//Serial.println(SLaverage);
}
void movementSL()
{
SLaverage = map(SLaverage, 410, 270, 0 , 180);
data.ShoulderLift = constrain(SLaverage, 35, 180);
//Serial.println(data.ShoulderLift);
}
void ElbowMovement()
{
// 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)
{
if (mpuInterrupt && fifoCount < packetSize)
{
// try to get out of the infinite loop
fifoCount = mpu.getFIFOCount();
}
}
// 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 & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024)
{
// reset so we can continue cleanly
mpu.resetFIFO();
fifoCount = mpu.getFIFOCount();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
}
else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT))
{
// 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;
// Get Yaw, Pitch and Roll values
#ifdef OUTPUT_READABLE_YAWPITCHROLL
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
// Yaw, Pitch, Roll values - Radians to degrees
ypr[0] = ypr[0] * 180 / M_PI;
ypr[1] = ypr[1] * 180 / M_PI;
ypr[2] = ypr[2] * 180 / M_PI;
// Skip 300 readings (self-calibration process)
if (int l = 0; l <= 300) {
correct = ypr[0]; // Yaw starts at random value, so we capture last value after 300 readings
l++;
}
// After 300 readings
else {
ypr[0] = ypr[0] - correct; // Set the Yaw to 0 deg - subtract the last random Yaw value from the currrent value to make the Yaw 0 degrees
// Map the values of the MPU6050 sensor from -90 to 90 to values suatable for the servo control from 0 to 180
ELaverage = map(ypr[0], -90, 90, 0, 180);
data.ElbowLift = constrain(ELaverage, 30, 110);
ARaverage = map(ypr[1], -90, 90, 0, 180);
data.ArmRotation = constrain(ARaverage, 0, 180);
//Serial.println(data.ElbowLift);
Serial.println(ypr[1]);
}
#endif
}
}
Is there any ways to get rid of the FIFO overflow? Also When i tried to used Jeff Rowberg's example codes MPU6050_DMP6 the program will freeze after a few seconds. Is there any solution to that? These are the example codes that i am using.
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 mpu;
float correct;
int j = 0;
#define OUTPUT_READABLE_YAWPITCHROLL
#define INTERRUPT_PIN 2
bool blinkState = false;
// MPU control/status vars
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
// orientation/motion vars
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
//Interrupt Detection
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();
Wire.setClock(400000);
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(38400);
while (!Serial);
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
devStatus = mpu.dmpInitialize();
mpu.setXGyroOffset(17);
mpu.setYGyroOffset(-69);
mpu.setZGyroOffset(27);
mpu.setZAccelOffset(1551);
if (devStatus == 0)
{
mpu.setDMPEnabled(true);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
dmpReady = true;
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(")"));
}
}
void loop()
{
if (!dmpReady) return;
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer))
{
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
if (j <= 300)
{
correct = ypr[0]; // Yaw starts at random value, so we capture last value after 300 readings
j++;
}
else
{
ypr[0] = ypr[0] - correct;
Serial.print("ypr\t");
Serial.print(ypr[0] * 180/M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180/M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180/M_PI);
}
#endif
}
}
You're using DMP (Digital Motion Processor) with mean calculation running on the MPU itself, this gives more precise and less CPU consumption but you need to update the FIFO frequently or the track goes wrong.
Encountering 'FIFO overflow' means your loop code was too slow, you should increase the speed of another task in your loop code. Or just use other code that not use the DMP.

Arduino FastLED: Trying to group LEDs into pairs of two

I have a strip of leds cut into pairs; each pair is in its own lantern, and I want the lanterns to alternate whatever I put through them.
I am using FastLED library. I have posted what I have come up with. It seems to work in the console; the arrays generated are right(or seem to be)' even[] = {0,1,4,5,8,9...}; odd[] = {2,3,6,7,10,11...}' but lantern #1 does not work as the rest do for some reason.
lantern #1 = leds[even[0]] and leds[even[1]] should both display Eval color but leds[even[1]] is displaying Oval color.
the other lanterns display properly
lantern #2 = leds[odd[0]] and leds[odd[1]] displays Oval color.
lantern #3 = leds[even[2]] and leds[even[3]] displays Eval color.
lantern #4 = leds[odd[2]] and leds[odd[3]] displays Oval color.
etc...
#include <FastLED.h>
#define NUM_LEDS 12
#define DATA_PIN 3
#define POT_PIN A0
int potValue;
int even[NUM_LEDS]; //{0,1,4,5,8,9...}
int odd[NUM_LEDS]; //{2,3,6,7,10,11...}
int Epos = 0; //count position for adding lanterns to even/odd arrays
int Opos = 0;
int lantern = 1; // 1 and 2 switch back and forth between lanterns
int pos = 0; // count 2 leds per lantern
CRGB leds[NUM_LEDS];
void setup() {
Serial.begin(9600);
FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
for (int i=0;i<NUM_LEDS;i++){ //go through leds
if (pos == 2){
pos = 0;
if (lantern == 1){
lantern = 2;
}
else if (lantern == 2){
lantern = 1;
}
}
switch (lantern){
case 1: // even lantern
even[Epos] = i; // i = led on strip
Epos++;
pos++;
break;
case 2: // odd lantern
odd[Opos] = i; // i = led on strip
Opos++;
pos++;
break;
}
}
Serial.print("\n even: ");
for (int x=0;x<NUM_LEDS;x++){
Serial.print(even[x]);
}
Serial.print("\n odd: ");
for (int x=0;x<NUM_LEDS;x++){
Serial.print(odd[x]);
}
}
//////////////////////////////////////////////////////////////////////////
void split(){
potValue = analogRead(POT_PIN);
int Eval;
int Oval;
int Eval = potValue; //color value for even lanterns
int Oval = map(potValue,0,1023, 10,500); //offset color value for odd lanterns
for (int i=0;i<NUM_LEDS;i++){
leds[even[i]] = CHSV(Eval,255,255);
delay(1);
leds[odd[i]] = CHSV(Oval,255,255);
}
FastLED.show();
}
///////////////////////////////////////////////////////////////////////////
void loop() {
split();
}
I am pretty new to Arduino.have I done something wrong? Is this an efficient way to go about this?

Calculate amplitude of a signal after application FFT

I'm using Arduino Due and sensor for noise and I applied FFT library to extract frequency and it's working perfectly. But I don't know how to calculate the amplitudes and print them on console?
Here is the code:
#include "arduinoFFT.h"
#define SAMPLES 32
#define SAMPLING_FREQUENCY 1000
arduinoFFT FFT = arduinoFFT();
unsigned int sampling_period_us;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
void setup() {
Serial.begin(9600);
sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
}
void loop() {
/*SAMPLING*/
for(int i=0; i<SAMPLES; i++)
{
microseconds = micros();
vReal[i] = analogRead(0);
vImag[i] = 0;
while(micros() < (microseconds + sampling_period_us)){
}
}
/*FFT*/
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
Serial.println(peak);
for(int i=0; i<(SAMPLES/2); i++)
{
Serial.print((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES, 1);
Serial.print(" ");
//Serial.println(vReal[i], 1); //View only this line in serial plotter to visualize the bins
}
delay(1000);
while(1);
}
The serial plotter does not have a number of sample to plot functionality.
If you want to view the amplitudes for each window correctly, you will need to use the following code
for(int i=0; i<(SAMPLES/2); i++)
{
// Serial.print((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES, 1);
for(int i=0; i<20; i++)//Adjust the 20 to make space between each samples.
Serial.print(0);
Serial.print(vReal[i]);
}
And then adjust the size of the serial plotter to fit your window.
I hope this helps.

arduino interrupt variable not working

I am a beginner with arduino and I'm trying to make a sinus wave generator. Since I've recently found I can't put everything into main void loop, I'm trying to use interrupts. I have problem with changing variable inside of the interrupt (Delay), I don't know where's the mistake.
Here is my code:
int sine256[] = { //256 sin values from 0 to 2pi
};
int i = 0;
int sensorPin = 7;
int outputPin = 6;
volatile float Delay = 10000;
void setup()
{
Serial.begin(9600);
pinMode(outputPin, OUTPUT);
pinMode(sensorPin, INPUT);
attachInterrupt(digitalPinToInterrupt(sensorPin), freq, RISING);
}
void loop()
{
analogWrite(6,sine256[i]);
i = i + 1;
if(i == 256){
i = 0;
}
Serial.println(Delay);
delayMicroseconds(Delay);
}
void freq() {
Delay = Delay/2;
}
EDIT
Try this:
int sine256[] = { //256 sin values from 0 to 2pi
};
int i = 0;
int sensorPin = 7;
int outputPin = 6;
volatile float Delay = 10000;
void setup()
{
Serial.begin(9600);
pinMode(outputPin, OUTPUT);
pinMode(sensorPin, INPUT);
//attachInterrupt(digitalPinToInterrupt(sensorPin), freq, RISING);
}
void loop()
{
analogWrite(6,sine256[i]);
i = i + 1;
if(i == 256){
i = 0;
}
Serial.println(Delay);
freq();
delay(Delay);
}
void freq() {
Delay = Delay / 2;
}
https://www.arduino.cc/en/Reference/AttachInterrupt
Try taking a look at that.
What model are you using?
The only thing that causes me troubles now is the button; when i press it, it often respond as if i had pressed the button multiple times (2,3 or 4x).
This is my final code for now. Since the execution time for a void loop is 12 microseconds, i've calculated delay required to run a generator on 20,40 & 60Hz.
int sine256[] = { //256 sin values from 0 to 2pi (from 0 to 255)
int i = 0;
int sensorPin = 2;
volatile int outputPin = 7;
volatile float Delay = 1000;
int time1;
int time2;
void setup()
{
Serial.begin(9600);
pinMode(outputPin, OUTPUT);
pinMode(sensorPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(sensorPin), freq, FALLING);
}
void loop()
{
//time1 = micros();
analogWrite(outputPin,sine256[i]);
i = i + 1;
if(i == 256){
i = 0;
}
//time2 = micros();
//Serial.println(time2 - time1);
delay(Delay);
}
void freq() {
outputPin = 6;
if(Delay == 0.02){
analogWrite(6,LOW);
outputPin = 7;
Delay = 1000;
}
if(Delay == 0.04){
Delay = 0.02;
}
if(Delay == 0.09){
Delay = 0.04;
}
if((Delay == 1000)&&(outputPin == 6)){
Delay = 0.09;
}
Serial.println(Delay);
}

Arduino issues with fsr and LCD

I am doing a project which requires the use of arduino uno, 4 force sensors and a 16x2 LCD. I'm trying to display the readings of the force sensors onto the LCD with the implementation of the buttons. For eg. if I press the up button it should display the first force sensor reading. The problem is it just displays a huge number of 143164976.0000 even when no force is applied on it. Please advice on whether there is a problem to my coding.
int iForceSensorReading; // the analog reading from the FSR resistor divider
int iForceSensorReading1;
int iForceSensorReading2;
int iForceSensorReading3;
int iForceSensorVoltage; // the analog reading converted to voltage
int iForceSensorVoltage1;
int iForceSensorVoltage2;
int iForceSensorVoltage3;
unsigned long ulForceSensorResistance;// The voltage converted to resistance, can be very big so make "long"
unsigned long ulForceSensorResistance1;
unsigned long ulForceSensorResistance2;
unsigned long ulForceSensorResistance3;
unsigned long ulForceSensorConductance;
unsigned long ulForceSensorConductance1;
unsigned long ulForceSensorConductance2;
unsigned long ulForceSensorConductance3;
float FsrForce = 0; // Finally, the resistance converted to force
float FsrForce1 = 0;
float FsrForce2 = 0;
float FsrForce3 = 0;
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7
void setup(void){
Serial.begin(9600); // send debugging information via the Serial monitor
lcd.begin(16, 2);
lcd.print("Hand Muscle");
lcd.setCursor(0,1);
lcd.print("Meter");
lcd.setBacklight(WHITE);
}
uint8_t i=0;
void loop(void){
uint8_t buttons = lcd.readButtons();
iForceSensorReading = analogRead(A0);//read index finger pressure
delay(30);
// analog voltage reading ranges from about 0 to 1023 which maps to 0V to 5V (= 5000mV)
iForceSensorVoltage = map(iForceSensorReading, 0, 1023, 0, 5000);
ulForceSensorConductance = conductanceFunction(ulForceSensorResistance, iForceSensorVoltage);
if (ulForceSensorConductance <= 1000){
FsrForce = ulForceSensorConductance / 80;
}
else{
FsrForce = ulForceSensorConductance - 1000;
FsrForce /= 30;
}
iForceSensorReading1 = analogRead(A1);//read middle finger pressure
delay(30);
iForceSensorVoltage1 = map(iForceSensorReading1, 0, 1023, 0, 5000);
if (iForceSensorVoltage1 == 0){
}
else{
ulForceSensorConductance1 = conductanceFunction(ulForceSensorResistance1, iForceSensorVoltage1);
delay(30);
}
if (ulForceSensorConductance1 <= 1000){
FsrForce1 = ulForceSensorConductance1 / 80;
}
else{
FsrForce1 = ulForceSensorConductance1 - 1000;
FsrForce1 /= 30;
}
iForceSensorReading2 = analogRead(A2);// read ring finger pressure
delay(30);
iForceSensorVoltage2 = map(iForceSensorReading2, 0, 1023, 0, 5000);
ulForceSensorConductance2 = conductanceFunction(ulForceSensorResistance2, iForceSensorVoltage2);
if (ulForceSensorConductance2 <= 1000){
FsrForce2 = ulForceSensorConductance2 / 80;
}
else{
FsrForce2 = ulForceSensorConductance2 - 1000;
FsrForce2 /= 30;
}
iForceSensorReading3 = analogRead(A3);//read little finger pressure
delay(30);
iForceSensorVoltage3 = map(iForceSensorReading3, 0, 1023, 0, 5000);
ulForceSensorConductance3 = conductanceFunction(ulForceSensorResistance3, iForceSensorVoltage3);
if (ulForceSensorConductance3 <= 1000)
{FsrForce3 = ulForceSensorConductance3 / 80;
}else
{FsrForce3 = ulForceSensorConductance3 - 1000;
FsrForce3 /= 30;
}
if (buttons) {
lcd.clear();
lcd.setCursor(0,0);
if (buttons & BUTTON_UP) {
lcd.print("Index Finger: ");
lcd.setCursor(0,1);
lcd.print(FsrForce,DEC);
lcd.setBacklight(WHITE);
}
if (buttons & BUTTON_DOWN) {
lcd.print("Little Finger: ");
lcd.setCursor(0,1);
lcd.print(FsrForce3,DEC);
lcd.setBacklight(WHITE);
}
if (buttons & BUTTON_LEFT) {
lcd.print("Middle Finger: ");
lcd.setCursor(0,1);
lcd.print(FsrForce1,DEC);
lcd.setBacklight(WHITE);
}
if (buttons & BUTTON_RIGHT) {
lcd.print("Ring Finger: ");
lcd.setCursor(0,1);
lcd.print(FsrForce2,DEC);
lcd.setBacklight(WHITE);
}
if (buttons & BUTTON_SELECT) {
lcd.print("SELECT ");
lcd.setBacklight(WHITE);
}
}
}
// The voltage = Vcc * R / (R + FSR) where R = 10K and Vcc = 5V
// so FSR = ((Vcc - V) * R) / V
int conductanceFunction(long x, long y)
{long result;
x = 5000 - y; // fsrVoltage is in millivolts so 5V = 5000mV
x *= 10000; // 10K resistor
x /= y;
result = 1000000/x; //ulForceSensorConductance2 = 1000000 measured in micromhos
return result;
}
first likely issue, is this symptom sounds like a signed vs un-signed conflict. I see in your code the following calls
ulForceSensorConductance = conductanceFunction(ulForceSensorResistance, iForceSensorVoltage);
where
int conductanceFunction(long x, long y)
but
int iForceSensorVoltage;
You are passing an int(signed) into the second argument. Using it on math and creating a resultant variable of
long result;
and returning that as a INT.
Where you may have other problems.
You should follow some basic diagnostic procedures.
Assuming this problem is on ALL channels. if not then it is likely electrical.
Focusing on one channel.
PUT IN PRINTS of the various variables, to see what is moving as expected and validate the math is as expected

Resources