calculating wind speed from frequency value - performance

I have NRG #40 wind speed sensor the output frequency is linear with wind speed
output signal range from 0 Hz to 125 Hz
0 Hz mean =0.35 m/s and 125 Hz =96 m/s and transfer function is
m/s = (Hz x 0.765) + 0.35
How can I interface this sensor with a Arduino mega
previously I connect Adafruit (product ID: 1733) which is output voltage not frequency is linear with wind speed
and this code for Adafruit :
//Setup Variables
const int sensorPin = A0; //Defines the pin that the anemometer output is connected to
int sensorValue = 0; //Variable stores the value direct from the analog pin
float sensorVoltage = 0; //Variable that stores the voltage (in Volts) from the anemometer being sent to the analog pin
float windSpeed = 0; // Wind speed in meters per second (m/s)
float voltageConversionConstant = .004882814; //This constant maps the value provided from the analog read function, which ranges from 0 to 1023, to actual voltage, which ranges from 0V to 5V
int sensorDelay = 1000; //Delay between sensor readings, measured in milliseconds (ms)
//Anemometer Technical Variables
//The following variables correspond to the anemometer sold by Adafruit, but could be modified to fit other anemometers.
float voltageMin = .4; // Mininum output voltage from anemometer in mV.
float windSpeedMin = 0; // Wind speed in meters/sec corresponding to minimum voltage
float voltageMax = 2.0; // Maximum output voltage from anemometer in mV.
float windSpeedMax = 32; // Wind speed in meters/sec corresponding to maximum voltage
void setup()
{
Serial.begin(9600); //Start the serial connection
}
void loop()
{
sensorValue = analogRead(sensorPin); //Get a value between 0 and 1023 from the analog pin connected to the anemometer
sensorVoltage = sensorValue * voltageConversionConstant; //Convert sensor value to actual voltage
//Convert voltage value to wind speed using range of max and min voltages and wind speed for the anemometer
if (sensorVoltage <= voltageMin){
windSpeed = 0; //Check if voltage is below minimum value. If so, set wind speed to zero.
}else {
windSpeed = (sensorVoltage - voltageMin)*windSpeedMax/(voltageMax - voltageMin); //For voltages above minimum value, use the linear relationship to calculate wind speed.
}
//Print voltage and windspeed to serial
Serial.print("Voltage: ");
Serial.print(sensorVoltage);
Serial.print("\t");
Serial.print("Wind speed: ");
Serial.println(windSpeed);
delay(sensorDelay);
}

Asuming you use a Arduino UNO or Nano, a easy way is to connect the sensor to pin D2 or D3, witch can be used as Interrupt pins.
You then make a function, or a ISR, that gets called every time the sensor pulses. Then you attach the newly created function to the Interrupt pin.
So it will look something like this.
byte sensorPin = 2;
double pulses = 0;
double wSpeed = 0;
long updateTimer = 0;
int updateDuration = 3000;
void setup() {
Serial.begin(115200);
pinMode(sensorPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(sensorPin), sensorISR, FALLING);
}
void loop() {
long now = millis();
if(updateTimer < now) {
updateTimer = now + updateDuration;
wSpeed = ((pulses/(updateDuration/1000)) * 0.765) + 0.35;
pulses = 0;
Serial.println("Windspeed is:" + String(wSpeed));
}
}
void sensorISR() {
pulses++;
}
The ISR functions only job is to increment the pulses variable for every pulse. Then every second you can calculate the frequency and speed. If you wait 3 second instead, like above, you will have a better resolution but will have to account for the extra time in the equation.
I have not testet this code.

Related

How should I write angle values into stepper motors similare to servoWriteFloat() for servo motors?

I am working on a delta robot controlled with stepper motors through arduino uno.
I found a code online that allows me to use Arduino processing IDE but this code was written for servo motors.
So, I am trying to re-adjust this code to work with my stepper motors but I am very new to using arduino and programming so I am facing some difficulties.
I think my main problem is not knowing how to write angle values into stepper motors which is this part of their code:
`
servoWriteFloat(&servo1, t1); //write angles value into the servo
servoWriteFloat(&servo2, t2+10); //write angles value into the servo - the 10 value is due to not perfect alignement of the servo
servoWriteFloat(&servo3, t3+5); //write angles value into the servo - the 5 value is due to not perfect alignement of the servo
`
Here are the component used in this project:
Component used in this project:
Two NEMA 17 stepper motors Frame Size 42x42mm Technique specification: Step Angle: 1.8° – Current /phase: 1.7 A – Resistance /phase: 1.5 Ω – Inductance /phase: 2.8 mH – Holding Torque: 2.2 N.cm – leads: 4 wires – Motor Wight: 0.28 Kg – Motor Length: 40 mm
One NEMA 23 Stepper motor Technique specification: Step Angle: 1.8°– Current /phase: 3 A – Resistance /phase: 1Ω – Inductance /phase: 1.8 mH – Holding Torque: 13 Kg.cm – leads: 8 wires – Motor Wight: 1 Kg – Length: 76 mm
Two A4988 – Stepper Motor Driver Specs:
Minimum operating voltage: 8 V
Maximum operating voltage: 35 V
Continuous current per phase: 1 A
Maximum current per phase: 2 A
Minimum logic voltage: 3 V
Maximum logic voltage: 5.5 V
Microstep resolutions: 1, 1/2, 1/4, 1/8, 1/16
Size: 0.6″ × 0.8″
Weight: 1.3 g
One Drv8825 – Stepper Motor Driver specs
Arduino Shield "NANO CNC Machine V4 Board" Description: There are total 3 ways slots for stepper motor driver modules (Model A4988 or Drv8825 – It sold separately at our store ), and it can drive 3 ways stepper motors each up to 2A. Each way stepper motor has two I/O ports and it means 6 I/O ports can manage 3 stepper motors. It is very convenient to operate.
All connected together to an arduino uno, the connections and the components are almost the same as the ones used in this youtube video
The Following is my attempt to readjust the code to work for stepper motors:
`
#include <Stepper.h>
float xPos = 0; // x axis position
float yPos = 0; // y axis position
float zPos = -190; // z axis position, negative is up, positive is down. Delta bots are usually used up side down...
//float xPos = 78.231;
//float yPos = -78.231;
//float zPos = -377.824;
float t1; //stepper angle t for 'theta', 1 for stepper 1
float t2;
float t3;
int result;
int data = 0;
int serialTeller=0;
#define MAXANGLE 98.73 //maximum angle allowed by the Steppers
#define MINANGLE -42.92 //minimum angle alloweb by the Steppers
// defines pins numbers
const int stepX = 2;
const int dirX = 5;
const int stepY = 3;
const int dirY = 6;
const int stepZ = 4;
const int dirZ = 7;
const int enPin = 8;
void setup() {
// initialize the serial port:
Serial.begin(9600);
// Sets the two pins as Outputs
pinMode(stepX,OUTPUT);
pinMode(dirX,OUTPUT);
pinMode(stepY,OUTPUT);
pinMode(dirY,OUTPUT);
pinMode(stepZ,OUTPUT);
pinMode(dirZ,OUTPUT);
pinMode(enPin,OUTPUT);
digitalWrite(enPin,LOW);
digitalWrite(dirX,HIGH);
digitalWrite(dirY,HIGH);
digitalWrite(dirZ,HIGH);
}
void loop(){
//int variable1 = int(random(100));
//Serial.print(variable1);
char xxPos[4]; // x position taken from processing
char yyPos[4]; // y position taken from processing
char zzPos[4]; // z position taken from processing
char tempo; // temp variable
if (Serial.available() > 12) {
tempo=Serial.read(); //read from serial
int conta=0;
while (tempo != 'X') // wait for the X position
{
tempo=Serial.read();
}
if (Serial.available() >= 11) {
xxPos[0]=Serial.read(); //read X byte
xxPos[1]=Serial.read(); //read X byte
xxPos[2]=Serial.read(); //read X byte
xxPos[3]=Serial.read(); //read X byte
xPos=atoi(xxPos); //transfor bytes in integer
tempo=Serial.read(); //read Y char
yyPos[0]=Serial.read(); //read Y byte
yyPos[1]=Serial.read(); //read Y byte
yyPos[2]=Serial.read(); //read Y byte
yyPos[3]=Serial.read(); //read Y byte
yPos=atoi(yyPos); //transform bytes in integer
tempo=Serial.read(); //read Z Char
zzPos[0]=Serial.read(); //read Z byte
zzPos[1]=Serial.read(); //read Z byte
zzPos[2]=Serial.read(); //read Z byte
zzPos[3]=Serial.read(); //read Z byte
zPos=atoi(zzPos); //transform bytes in integer
}
}
result = delta_calcInverse(xPos, yPos, zPos, t1, t2, t3);
// stepperWriteFloat(&stepX, t1); //How should I rewrite servoWriteFloat for stepper motors?
// stepperWriteFloat(&stepY, t2+10);
// stepperWriteFloat(&stepZ, t3+5);
//Should I write it this way?
digitalWrite(stepX, t1);
digitalWrite(stepY, t2+10);
digitalWrite(stepZ, t2+5);
//or should I write it similare to this ?
//// initialize the stepper library on pins:
//Stepper myStepper1(t1, 2, 5);
//Stepper myStepper2(t2+10, 3, 6);
//Stepper myStepper3(t3+5, 4, 7);
// // set the speed at 60 rpm:
//myStepper1.setSpeed(60);
//// set the speed at 60 rpm:
//myStepper2.setSpeed(60);
//// set the speed at 60 rpm:
//myStepper3.setSpeed(60);
//
//// Serial.println("myStepper1 t1");
// myStepper1.step(t1);
// Serial.println("myStepper1 t2");
// myStepper1.step(t2+10);
// Serial.println("myStepper1 t3");
// myStepper1.step(t3+5);
}
//////////////////// I think this part should remain the same////////////////////
//Note: I copied this part in the same file as the above code because otherwise it gives me and error saying that result is not indicated in this scope//
// print some values in the serial
void printSerial(){
Serial.print(result == 0 ? "ok" : "no");
char buf[10];
dtostrf(xPos, 4, 0, buf);
Serial.print(" X");
Serial.print(buf);
dtostrf(yPos, 4, 0, buf);
Serial.print(" Y");
Serial.print(buf);
dtostrf(zPos, 4, 0, buf);
Serial.print(" Z");
Serial.print(buf);
dtostrf(t1, 6, 2, buf);
Serial.print(" T1");
Serial.print(buf);
dtostrf(t2, 6, 2, buf);
Serial.print(" T2");
Serial.print(buf);
dtostrf(t3, 6, 2, buf);
Serial.print(" T3");
Serial.print(buf);
Serial.println("");
}
The Following is the processing IDE code which I believe works just fine:
//write X value in serial port
xPos="X";
if (XXX > 0)
xPos += '+';
else
xPos += '-';
if (abs(XXX) < 100)
xPos += '0';
if (abs(XXX) < 10)
xPos += '0';
xPos += abs(XXX);
// write Y value in serial port
yPos="Y";
if (YYY > 0)
yPos += '+';
else
yPos += '-';
if (abs(YYY) < 100)
yPos += '0';
if (abs(YYY) < 10)
yPos += '0';
yPos += abs(YYY);
// write Z value in serial port
zPos="Z";
if (ZZZ > 0)
zPos += '+';
else
zPos += '-';
if (abs(ZZZ) < 100)
zPos += '0';
if (abs(ZZZ) < 10)
zPos += '0';
zPos += abs(ZZZ);
// write x,y,z in the serial port
myPort.write(xPos);
myPort.write(yPos);
myPort.write(zPos);
// write x,y,z in the monitor
print(xPos);
print(yPos);
println(zPos);
}
`
I also read this Forum and found out the following: "A stepper - in contrast to a servo - does not know where it is. If you want it to move to an absoulte angle, you must fist determine a starting position - e.g. with an end switch." but I am still not sure how to move on from here, How should I wrtie angle values into stepper motor?
Note: I believe the kinematics code should remain the same in both cases.

Robot not turning on one set of code, but turns on the other similar set of code

Im making an alarm robot using the Sparkfun Redbot for a class project. When the robot detects something in front of it, or detects a drop off, it would turn 90 degrees. It worked on the Autonomous Navigation Test file, but it doesn't turn with the Prototype code file, both Autonomous Navigation functions are the same.
Autonomous Navigation Code
// SparkFun RedBot Library
#include <RedBot.h>
#include <RedBotSoftwareSerial.h>
// create objects using classes in RedBot library
RedBotButton button;
RedBotMotors motors;
RedBotEncoder encoder(A2, 10);
RedBotSensor leftLine(A3);
RedBotSensor centerLine(A6);
RedBotSensor rightLine(A7);
// global variables for buzzer and LED pin numbers
const int buzzer = 9;
const int led = 13;
// global variables for ultrasonic sensor pin numbers
const int TRIG_PIN = A0;
const int ECHO_PIN = A1;
// global variables to keep track of which scenario to demonstrate
int scenario = 1;
boolean started = false;
// variables for wheel encoder counts and motor powers
long leftCount, rightCount;
long prevLeftCount, prevRightCount;
int leftPower, rightPower;
const int motorPower = 150; // change value if needed - used by driveStraight() function
void setup() {
pinMode(buzzer, OUTPUT);
pinMode(led, OUTPUT);
// ultrasonic sensor setup
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
digitalWrite(TRIG_PIN, LOW);
}
void loop() {
checkButton();
if (started == true) {
if (scenario == 1) scenario1();
else if (scenario == 2) scenario2();
else if (scenario == 3) scenario3();
}
}
void scenario1() {
// Scenario 1: Drive autonomously by avoiding lines and obstacles
unsigned long time = millis(); // get current time in milliseconds
unsigned long endTime = time + 30000; // make end time 30 seconds from now
// while current time is less than end time, run demo
while (time < endTime) {
avoidCollision();
checkDropOff();
time = millis(); // check current time again
}
// time's up
motors.stop();
alertSound();
// set global variables for 2nd scenario
scenario = 2;
started = false;
}
void scenario2() {
// add code for Scenario 2
// set global variables for 3rd scenario
scenario = 3;
started = false;
}
void scenario3() {
// add code for Scenario 3
// reset global variables for 1st scenario
scenario = 1;
started = false;
}
//---------------------------------------------------------
void checkDropOff() {
// IR threshold indicating surface drop-off (table edge, hole, etc.)
int dropOff = 950; // adjust value if necessary
// get IR sensor readings
int leftSensor = leftLine.read();
int centerSensor = centerLine.read();
int rightSensor = rightLine.read();
// see if any IR sensors detect drop-off
if (leftSensor > dropOff || centerSensor > dropOff || rightSensor > dropOff) {
// add code to perform (brake, reverse, change direction, etc.)
motors.brake();
delay(1000);
motors.drive(-150); // back up
delay(500);
motors.brake();
pivotAngle(90);
started = false; // allow test to be repeated
}
}
void checkButton() {
if (button.read() == true) {
// reverse value of "started"
started = !started;
// single-blink and single-beep as feedback
digitalWrite(led, HIGH);
tone(buzzer, 3000);
delay(200);
digitalWrite(led, LOW);
noTone(buzzer);
}
}
void alertSound() {
// modify code to play whatever sound pattern you want
for (int i = 0; i < 3; i++) {
tone(buzzer, 4000);
delay(100);
noTone(buzzer);
delay(100); // pause before next beep
}
}
void driveDistance(float distance, int power) {
// use wheel encoders to drive straight for specified distance at specified power
// set initial power for left and right motors
int leftPower = power;
int rightPower = power;
// amount to offset motor powers to drive straight
int offset = 5;
// if negative distance, make powers & offset also negative
if (distance < 0) {
leftPower *= -1;
rightPower *= -1;
offset *= -1;
}
// adjust distance to improve accuracy
float correction = -1.0; // change value based on test results
if (distance > 0) distance += correction;
else if (distance < 0) distance -= correction;
// variables for tracking wheel encoder counts
long leftCount = 0;
long rightCount = 0;
long prevLeftCount = 0;
long prevRightCount = 0;
long leftDiff, rightDiff;
// RedBot values based on encoders, motors & wheels
float countsPerRev = 192.0; // 192 encoder ticks per wheel revolution
float wheelDiam = 2.56; // wheel diameter = 65 mm = 2.56 in
float wheelCirc = PI * wheelDiam; // wheel circumference = 3.14 x 2.56 in = 8.04 in
// based on distance, calculate number of wheel revolutions
float numRev = distance / wheelCirc;
// calculate target encoder count
float targetCount = numRev * countsPerRev;
// reset encoder counters and start driving
encoder.clearEnc(BOTH);
delay(100);
motors.leftDrive(leftPower);
motors.rightDrive(rightPower);
// keeps looping while right encoder count less than target count
while (abs(rightCount) < abs(targetCount)) {
// get current wheel encoder counts
leftCount = encoder.getTicks(LEFT);
rightCount = encoder.getTicks(RIGHT);
// calculate increase in count from previous reading
leftDiff = abs(leftCount - prevLeftCount);
rightDiff = abs(rightCount - prevRightCount);
// store current counts as "previous" counts for next reading
prevLeftCount = leftCount;
prevRightCount = rightCount;
// adjust left & right motor powers to keep counts similar (drive straight)
// if left rotated more than right, slow down left & speed up right
if (leftDiff > rightDiff) {
leftPower = leftPower - offset;
rightPower = rightPower + offset;
}
// else if right rotated more than left, speed up left & slow down right
else if (leftDiff < rightDiff) {
leftPower = leftPower + offset;
rightPower = rightPower - offset;
}
// apply adjusted motor powers
motors.leftDrive(leftPower);
motors.rightDrive(rightPower);
delay(10); // short delay before next reading
}
// target count reached
motors.brake(); // or use: motors.stop()
delay(500); // brief delay to wait for complete stop
}
void pivotAngle(float angle) {
// use wheel encoders to pivot (turn) by specified angle
// set motor power for pivoting
int power = 100; // turn CW
if (angle < 0) power *= -1; // use negative power to turn CCW
// adjust angle to improve accuracy
float correction = -5.0; // change value based on test results
if (angle > 0) angle += correction;
else if (angle < 0) angle -= correction;
// variable for tracking wheel encoder counts
long rightCount = 0;
// RedBot values based on encoders, motors & wheels
float countsPerRev = 192.0; // 192 encoder ticks per wheel revolution
float wheelDiam = 2.56; // wheel diameter = 65 mm = 2.56 in
float wheelCirc = PI * wheelDiam; // wheel circumference = 3.14 x 2.56 in = 8.04 in
float pivotDiam = 6.125; // pivot diameter = distance between centers of wheel treads = 6.125 in
float pivotCirc = PI * pivotDiam; // pivot circumference = 3.14 x 6.125 in = 19.23 in
// based on angle, calculate distance (arc length)
float distance = abs(angle) / 360 * pivotCirc;
// based on distance, calculate number of wheel revolutions
float numRev = distance / wheelCirc;
// calculate target encoder count
float targetCount = numRev * countsPerRev;
// reset encoder counters and start pivoting
encoder.clearEnc(BOTH);
delay(100);
motors.pivot(power);
// keeps looping while right encoder count less than target count
while (abs(rightCount) < abs(targetCount)) {
// get current wheel encoder count
rightCount = encoder.getTicks(RIGHT);
delay(10); // short delay before next reading
}
// target count reached
motors.brake();
delay(250);
// clearEncoders(); // only needed if using driveStraight() or countLine()
}
void avoidLine() {
/* AVOID LINE
To avoid dark line on light surface:
Use high threshold & see if sensors greater than threshold
To avoid light line on dark surface:
Use low threshold & see if sensors less than threshold
Use test readings from line to determine best value for threshold
*/
// adjust value if necessary
int lineThreshold = 800;
// get IR sensor readings
int leftSensor = leftLine.read();
int rightSensor = rightLine.read();
// when either sensor on line, first brake motors
if (leftSensor > lineThreshold || rightSensor > lineThreshold) {
motors.brake();
delay(250);
}
// when both sensors on line, turn around
if (leftSensor > lineThreshold && rightSensor > lineThreshold) {
long rnd = random(750, 1250);
motors.pivot(100);
delay(rnd);
motors.stop();
}
// when line under left sensor only, pivot right
else if (leftSensor > lineThreshold) {
long rnd = random(500, 750);
motors.pivot(100);
delay(rnd);
motors.stop();
}
// when line under right sensor only, pivot left
else if (rightSensor > lineThreshold) {
long rnd = random(500, 750);
motors.pivot(-100);
delay(rnd);
motors.stop();
}
delay(25); // change delay to adjust line detection sensitivity
}
void avoidCollision() {
// set minimum distance between RedBot and obstacle
float minDist = 8.0; // change value as necessary (need decimal)
// measure distance to nearest obstacle
float sensorDist = measureDistance();
// if obstacle is too close, avoid collision
if (sensorDist <= minDist) {
// add code to perform (brake, change direction, etc.)
motors.brake();
pivotAngle(90);
}
else{
motors.drive(120);
}
delay(60); // need min 60ms between ultrasonic sensor readings
}
float measureDistance() {
// declare local variables for function
unsigned long time1;
unsigned long time2;
unsigned long pulse_time;
float dist_cm;
float dist_in;
// trigger ultrasonic signal for minimum 10 microseconds
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// wait for echo to be received
while (digitalRead(ECHO_PIN) == 0);
// now measure how long echo lasts (pulse time)
time1 = micros(); // get start time in microseconds
while (digitalRead(ECHO_PIN) == 1); // wait until echo pulse ends
time2 = micros(); // get end time
pulse_time = time2 - time1; // subtract to get amount of time
// pulse time of 23200 represents maximum range for sensor
if (pulse_time > 23200) pulse_time = 23200;
/*
CALCULATE DISTANCE TO OBJECT USING PULSE TIME
distance = pulse time * speed of sound / 2
Divide by 2 because pulse time includes signal traveling to object and then back
Speed of sound in air at sea level is approximately 340 m/s
Numbers below are calculated constants for cm or inches
Decimal point in numbers necessary for accurate float calculation
*/
dist_cm = pulse_time / 58.0;
dist_in = pulse_time / 148.0;
// return measurement (dist_cm or dist_in)
return dist_in;
}
Prototype Code:
// SparkFun RedBot Library - Version: Latest
#include <RedBot.h>
#include <RedBotSoftwareSerial.h>
// GLOBAL VARIABLES AND OBJECTS
// create objects using classes in RedBot library
RedBotButton button;
RedBotMotors motors;
RedBotEncoder encoder(A2, 10);
RedBotSensor leftLine(A3);
RedBotSensor centerLine(A6);
RedBotSensor rightLine(A7);
// global variables for buzzer and LED pin numbers
const int buzzer = 9;
const int led = 13;
// global variables for ultrasonic sensor pin numbers
const int TRIG_PIN = A0;
const int ECHO_PIN = A1;
// global variables to keep track of which scenario to demonstrate
int scenario = 1;
boolean started = false;
// variables for wheel encoder counts and motor powers
long leftCount, rightCount;
long prevLeftCount, prevRightCount;
int leftPower, rightPower;
const int motorPower = 150; // change value if needed - used by driveStraight() function
int speaker = 9;
// SETUP FUNCTION
void setup() {
// put your setup code here, to run once:
pinMode(buzzer, OUTPUT);
pinMode(led, OUTPUT);
pinMode(speaker, OUTPUT);
// ultrasonic sensor setup
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
digitalWrite(TRIG_PIN, LOW);
}
// LOOP FUNCTION
void loop() {
checkButton();
if (started == true) {
if (scenario == 1) scenario1();
else if (scenario == 2) scenario2();
else if (scenario == 3) scenario3();
}
}
// CUSTOM FUNCTIONS
void scenario1() {
// add code to perform task scenario 1
tone(speaker, 500);
delay(500); //0.5s
noTone(speaker);
delay(10000); //10s
tone(speaker, 500);
// at end of this task, reset for next task
scenario = 2;
started = false;
}
void scenario2() {
// add code to perform task scenario 2
noTone(speaker);
delay(10000); //10s
tone(speaker, 500);
// at end of this task, reset for next task
scenario = 3;
started = false;
}
void scenario3() {
// add code to perform task scenario 3
unsigned long time = millis(); // get current time in milliseconds
unsigned long endTime = time + 600000; // make end time 10 min from now
// while current time is less than end time, run demo
while (time < endTime) {
avoidCollision();
checkDropOff();
time = millis(); // check current time again
}
// time's up
motors.stop();
alertSound();
// at end of this task, reset for next task
scenario = 1;
started = false;
}
//------------------------------------------------------------------------------------------------
void checkDropOff() {
// IR threshold indicating surface drop-off (table edge, hole, etc.)
int dropOff = 950; // adjust value if necessary
// get IR sensor readings
int leftSensor = leftLine.read();
int centerSensor = centerLine.read();
int rightSensor = rightLine.read();
// see if any IR sensors detect drop-off
if (leftSensor > dropOff || centerSensor > dropOff || rightSensor > dropOff) {
// add code to perform (brake, reverse, change direction, etc.)
motors.brake();
tone(speaker, 1000, 200);
delay(1000);
motors.drive(-150); // back up
delay(1000);
motors.brake();
started = false; // allow test to be repeated
}
}
void checkButton() {
if (button.read() == true) {
// reverse value of "started"
started = !started;
// single-blink and single-beep as feedback
digitalWrite(led, HIGH);
tone(buzzer, 3000);
delay(200);
digitalWrite(led, LOW);
noTone(buzzer);
}
}
void alertSound() {
// modify code to play whatever sound pattern you want
for (int i = 0; i < 3; i++) {
tone(buzzer, 4000);
delay(100);
noTone(buzzer);
delay(100); // pause before next beep
}
}
void driveDistance(float distance, int power) {
// use wheel encoders to drive straight for specified distance at specified power
// set initial power for left and right motors
int leftPower = power;
int rightPower = power;
// amount to offset motor powers to drive straight
int offset = 5;
// if negative distance, make powers & offset also negative
if (distance < 0) {
leftPower *= -1;
rightPower *= -1;
offset *= -1;
}
// adjust distance to improve accuracy
float correction = -1.0; // change value based on test results
if (distance > 0) distance += correction;
else if (distance < 0) distance -= correction;
// variables for tracking wheel encoder counts
long leftCount = 0;
long rightCount = 0;
long prevLeftCount = 0;
long prevRightCount = 0;
long leftDiff, rightDiff;
// RedBot values based on encoders, motors & wheels
float countsPerRev = 192.0; // 192 encoder ticks per wheel revolution
float wheelDiam = 2.56; // wheel diameter = 65 mm = 2.56 in
float wheelCirc = PI * wheelDiam; // wheel circumference = 3.14 x 2.56 in = 8.04 in
// based on distance, calculate number of wheel revolutions
float numRev = distance / wheelCirc;
// calculate target encoder count
float targetCount = numRev * countsPerRev;
// reset encoder counters and start driving
encoder.clearEnc(BOTH);
delay(100);
motors.leftDrive(leftPower);
motors.rightDrive(rightPower);
// keeps looping while right encoder count less than target count
while (abs(rightCount) < abs(targetCount)) {
// get current wheel encoder counts
leftCount = encoder.getTicks(LEFT);
rightCount = encoder.getTicks(RIGHT);
// calculate increase in count from previous reading
leftDiff = abs(leftCount - prevLeftCount);
rightDiff = abs(rightCount - prevRightCount);
// store current counts as "previous" counts for next reading
prevLeftCount = leftCount;
prevRightCount = rightCount;
// adjust left & right motor powers to keep counts similar (drive straight)
// if left rotated more than right, slow down left & speed up right
if (leftDiff > rightDiff) {
leftPower = leftPower - offset;
rightPower = rightPower + offset;
}
// else if right rotated more than left, speed up left & slow down right
else if (leftDiff < rightDiff) {
leftPower = leftPower + offset;
rightPower = rightPower - offset;
}
// apply adjusted motor powers
motors.leftDrive(leftPower);
motors.rightDrive(rightPower);
delay(10); // short delay before next reading
}
// target count reached
motors.brake(); // or use: motors.stop()
delay(500); // brief delay to wait for complete stop
}
void pivotAngle(float angle) {
// use wheel encoders to pivot (turn) by specified angle
// set motor power for pivoting
int power = 100; // turn CW
if (angle < 0) power *= -1; // use negative power to turn CCW
// adjust angle to improve accuracy
float correction = -5.0; // change value based on test results
if (angle > 0) angle += correction;
else if (angle < 0) angle -= correction;
// variable for tracking wheel encoder counts
long rightCount = 0;
// RedBot values based on encoders, motors & wheels
float countsPerRev = 192.0; // 192 encoder ticks per wheel revolution
float wheelDiam = 2.56; // wheel diameter = 65 mm = 2.56 in
float wheelCirc = PI * wheelDiam; // wheel circumference = 3.14 x 2.56 in = 8.04 in
float pivotDiam = 6.125; // pivot diameter = distance between centers of wheel treads = 6.125 in
float pivotCirc = PI * pivotDiam; // pivot circumference = 3.14 x 6.125 in = 19.23 in
// based on angle, calculate distance (arc length)
float distance = abs(angle) / 360 * pivotCirc;
// based on distance, calculate number of wheel revolutions
float numRev = distance / wheelCirc;
// calculate target encoder count
float targetCount = numRev * countsPerRev;
// reset encoder counters and start pivoting
encoder.clearEnc(BOTH);
delay(100);
motors.pivot(power);
// keeps looping while right encoder count less than target count
while (abs(rightCount) < abs(targetCount)) {
// get current wheel encoder count
rightCount = encoder.getTicks(RIGHT);
delay(10); // short delay before next reading
}
// target count reached
motors.brake();
delay(250);
// clearEncoders(); // only needed if using driveStraight() or countLine()
}
void avoidLine() {
/* AVOID LINE
To avoid dark line on light surface:
Use high threshold & see if sensors greater than threshold
To avoid light line on dark surface:
Use low threshold & see if sensors less than threshold
Use test readings from line to determine best value for threshold
*/
// adjust value if necessary
int lineThreshold = 800;
// get IR sensor readings
int leftSensor = leftLine.read();
int rightSensor = rightLine.read();
// when either sensor on line, first brake motors
if (leftSensor > lineThreshold || rightSensor > lineThreshold) {
motors.brake();
delay(250);
}
// when both sensors on line, turn around
if (leftSensor > lineThreshold && rightSensor > lineThreshold) {
long rnd = random(750, 1250);
motors.pivot(100);
delay(rnd);
motors.stop();
}
// when line under left sensor only, pivot right
else if (leftSensor > lineThreshold) {
long rnd = random(500, 750);
motors.pivot(100);
delay(rnd);
motors.stop();
}
// when line under right sensor only, pivot left
else if (rightSensor > lineThreshold) {
long rnd = random(500, 750);
motors.pivot(-100);
delay(rnd);
motors.stop();
}
delay(25); // change delay to adjust line detection sensitivity
}
void avoidCollision() {
// set minimum distance between RedBot and obstacle
float minDist = 8.0; // change value as necessary (need decimal)
// measure distance to nearest obstacle
float sensorDist = measureDistance();
// if obstacle is too close, avoid collision
if (sensorDist <= minDist) {
// add code to perform (brake, change direction, etc.)
motors.brake();
pivotAngle(30);
}
else{
motors.drive(200);
}
delay(60); // need min 60ms between ultrasonic sensor readings
}
float measureDistance() {
// declare local variables for function
unsigned long time1;
unsigned long time2;
unsigned long pulse_time;
float dist_cm;
float dist_in;
// trigger ultrasonic signal for minimum 10 microseconds
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// wait for echo to be received
while (digitalRead(ECHO_PIN) == 0);
// now measure how long echo lasts (pulse time)
time1 = micros(); // get start time in microseconds
while (digitalRead(ECHO_PIN) == 1); // wait until echo pulse ends
time2 = micros(); // get end time
pulse_time = time2 - time1; // subtract to get amount of time
// pulse time of 23200 represents maximum range for sensor
if (pulse_time > 23200) pulse_time = 23200;
/*
CALCULATE DISTANCE TO OBJECT USING PULSE TIME
distance = pulse time * speed of sound / 2
Divide by 2 because pulse time includes signal traveling to object and then back
Speed of sound in air at sea level is approximately 340 m/s
Numbers below are calculated constants for cm or inches
Decimal point in numbers necessary for accurate float calculation
*/
dist_cm = pulse_time / 58.0;
dist_in = pulse_time / 148.0;
// return measurement (dist_cm or dist_in)
return dist_in;
}

Controlling the brigthness of LED using Arduino

I wrote a sample code to measure the brightness of LED by controlling the duty cycle of LED connected to Arduino. I want to get the range of least bright light to max bright light for a specific period of period. When i put desired_brightness = 1, the LED is emitting light at 93 lux units, its not the least brightlight. Any suggestion on how to get the least bright light?
int led = 3; // the pin that the LED is attached to
int brightness =0; // how bright the LED is
int incrementfactor = 10; // how many points to fade the LED by
int desired_brightness = 255 ;
int extra_delay = 1000;
void setup() { // declare pin 9 to be an output:
pinMode(led, OUTPUT);
analogWrite(led, desired_brightness);
}
void loop() {
analogWrite(led, desired_brightness);
brightness=brightness+incrementfactor;
if (brightness==desired_brightness) {
delay(extra_delay);
}
}
I've tailored your code a bit. The main problem was you were going to maximum brightness right away, and were never decreasing it. analogWrite() only takes values from 0 to 255. You were starting at 255 and increasing from there, so it just stayed bright. Try this instead, it's the "breathing effect" you see on so many electronics these days, and loops forever:
int ledPin = 3; // the pin that the LED is attached to
int brightness =0; // how bright the LED is
int extra_delay = 1000; // the extra delay at max
int super_delay = 5000; // super delay at min
int direction = 1; // the dimmer-brighter direction
void setup() {
pinMode(ledPin, OUTPUT);
analogWrite(ledPin, 0);
}
void loop() {
analogWrite(ledPin, brightness); // light at certain brightness
//delay(5); // wait a bit, stay at this level so we can see the effect!
delay(50); // longer delay means much slower change from bright to dim
if (direction == 1) // determine whether to go brighter or dimmer
brightness += 1;
else
brightness -= 1;
if (brightness == 255) // switch direction for next time
{
direction = -1;
delay(extra_delay); // extra delay at maximum brightness
}
if (brightness == 0) // switch direction, go brighter next time
{
direction = 1;
delay(super_delay); // super long delay at minimum brightness
}
}
This will go brighter, then dim, and repeat. The delay is very important -- you can reduce it or lengthen it, but without it, the change happens so fast you can't see it by eye, only on an oscilloscope. Hope this helps you!
EDIT:
Added a "super delay" at minimum brightness for measurement of that level.
One thing to keep in mind is that pulse-width modulation like this still gives full driving voltage from the output pin. PWM just alters the ratio of the time the pin is high vs. low. On this Aduino, it's still a voltage swinging instantly and quite rapidly between 0V and 3.3V. To get a true analog voltage from this output, one needs some circuitry to filter the highs and lows of PWM into a smoother average DC voltage. If you want to pursue that, search for "RC low-pass filter" or visit a site like this one.

Boiling water (hacking into Kettle)using Arduino UNO and Ultrasonic sensor and Temperature sensor

I am making this machine thing(using arduino) that uses ultrasonic sensor to detect if you are close to it and then it starts boiling water (i hacked into this kettle for this function, and connected it to a relay), and once the temperature reaches a certain degree (using temperature sensor) it then stops the relay (that controls the power of the kettle), and tilts the kettle using the servo motor into a separate cup.
As of now my code easily turns on the relay and the kettle when it detects that the temperature of water is not hot enough, but after the temperature has reached a certain amount (i used 35 in this case just as a try) the servo wouldn't stop doing the rotation. The code makes it rotate at the three degrees and then it should stop (right?) but then it keeps rotating. Is there any way to fix this? Also, how do i finish the rotation part and make the program go on to use the ultrasonic sensor again and begin the process?
(FYI i am using a DF Robot or Seeed Studio's Ultrasonic sensor and temperature sensor and a 5 kg servo motor)
I am using arduino's library for relay control, ping library for the ultrasonic sensor, and temperature sensor
#include <Servo.h>
#include <SoftwareSerial.h>
int val; //
int tempPin = 1;
int relaypin = 13;
Servo myservo;
const int pingPin = 7;
int ledpin = 10;
void setup()
{
Serial.begin(9600);
pinMode(relaypin, OUTPUT); // taking relay input
myservo.attach(2);
myservo.write(90); // servo position
pinMode(ledpin, OUTPUT);
}
void loop()
{
long duration, cm; //*following code is for ultrasonic sensor
pinMode ( pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(1);
digitalWrite(pingPin, HIGH);
delayMicroseconds(2);
digitalWrite(pingPin, LOW);
pinMode (pingPin, INPUT);
duration = pulseIn (pingPin, HIGH);
cm= microsecondsToCentimeters(duration);
val = analogRead(tempPin);
float mv = ( val/1024.0)*5000;
float temp = mv/10;
//float farh = (temp*9)/5 + 32; *last line for ultrasonic sensor
//digitalWrite(relaypin, HIGH); //start the boiling
//delay (10);
if (cm <= 20)
{
if (temp <= 27)
{
digitalWrite(relaypin, HIGH); //start the machine
// myservo.write(75); //tilting the servo
// delay (2000); //pause for 2 seconds
// myservo.write(65);
// delay (2000); //pause for 2 seconds
// myservo.write(45);
// delay (2000);
// myservo.write(35);
// delay (2000);
// myservo.write(90);
// delay(5000);
}
else if(temp >= 35)
{
digitalWrite(relaypin, LOW); //stops the machine
delay(5000);
myservo.write(75); //tilting the servo
delay (2000); //pause for 20 seconds
myservo.write(65);
delay (2000); //pause for 20 seconds
myservo.write(45);
delay (2000);
myservo.write(35);
delay (2000);
myservo.write(90);
delay(5000);
}
}
}
long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}
Could it be that after the servo did the rotation the temperature is still >= 35? In that case the rotation code will be executed again and again until temp is falling below 35.
BTW: in your code you have a delay(2000) but the comment says // pause for 20 seconds. In fact you are only delaying for 2 seconds here. Maybe that's another reason why you get unexpected behavior? If you just wait long enough with the kettle being turned off the temperature is falling to a level which will not trigger the rotation code again.
Regarding beginning the process again: I'm not sure if you are aware that the code in loop() is just repeatedly executed until you turn off the Arduino. So as soon as the temperature is <= 27 and you are close enough to the ultrasonic sensor the code for starting the machine is just executed again.
Revised code:
(note: Thank you for your response, Josef. so i ended up changing the code and somehow made it run the way i wanted it to, to some extent. I used a counter variable to end the loop but I was wondering if there is a way to get into the loop again after exiting the loop? ideally i would want it to run everytime someone comes close and then repeat the process when someone comes close to it again. I realized the delay and fixed it, and same i know about the loop() function.)
#include <Servo.h>
#include <SoftwareSerial.h>
#define trigPin 8
#define echoPin 7
int val;
int tempPin = A0;
int relaypin = 13;
Servo myservo;
int ledpin = 10;
boolean complete = false;
void setup()
{
Serial.begin(9600);
pinMode(relaypin, OUTPUT); // taking relay input
myservo.attach(12);
myservo.write(90); // servo position
pinMode(ledpin, OUTPUT);
SensorSetup();
}
void loop()
{
int actualDistance = MeasureDistance();
Serial.print(actualDistance);
Serial.println(" cm");
delay(500);
val = analogRead(tempPin);
float mv = ( val/1024.0)*5000;
float temp = mv/10;
//float farh = (temp*9)/5 + 32; *last line for ultrasonic sensor
//digitalWrite(relaypin, HIGH); //start the boiling
//delay (10);
Serial.println(temp);
if (actualDistance <= 25)
{
while (temp >= 20 && temp <=45)
{
digitalWrite(relaypin, HIGH); //start the machine
Serial.println(actualDistance);
}
}
else if(actualDistance >= 20)
{
if (temp >= 55 && complete == false)
{
Serial.println(actualDistance);
digitalWrite(relaypin, LOW); //stops the machine
delay(5000);
myservo.write(75); //tilting the servo
delay (2000); //pause for 2 seconds
myservo.write(65);
delay (2000); //pause for 2 seconds
myservo.write(45);
delay (2000);
myservo.write(35);
delay (2000);
myservo.write(25);
delay (2000);
myservo.write(15);
delay (2000);
myservo.write(0);
delay (2000);
myservo.write(25);
delay (2000);
myservo.write(35);
delay (2000);
myservo.write(45);
delay (2000);
myservo.write(60);
delay (2000);
myservo.write(90);
delay(5000);
complete = true;
}
}
}
void SensorSetup(){
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
int MeasureDistance(){ // a low pull on pin COMP/TRIG triggering a sensor reading
long duration;
digitalWrite(trigPin, LOW); // Added this line
delayMicroseconds(2); // Added this line
digitalWrite(trigPin, HIGH);
delayMicroseconds(10); // Added this line
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
long distance = (duration / 2) / 29.1;
return (int)distance;
}

Quadcopter stability pid code

I'm building a quad-copter using an accelerometer and gyro. The form looks like this one:
My pitch is controlled by the front and back motors.
My roll is controlled by the left and right motors.
I used PID and servo libraries.
Here's my pitch stability code:
double Kp=3.15, Ki=4.3, Kd=0.6;
int throttle = 1000;
PID PitchPID(&PitchInput, &PitchOutput, &PitchSetpoint, Kp, Ki, Kd, DIRECT);
PitchPID.SetMode(AUTOMATIC);
backESC.attach(3);
frontESC.attach(5);
// arme the motors
backESC.writeMicroseconds(2000);
frontESC.writeMicroseconds(2000);
delay(5000);
backESC.writeMicroseconds(700);
frontESC.writeMicroseconds(700);
delay(2000);
void loop{
// i have the angle and pitch
int xAngle = GetX();
int Pitch = GetPitch();
PitchInput = (Pitch) ;
PitchSetpoint = 0;
PitchPID.SetOutputLimits(-150,150);
PitchPID.Compute();
backPower = PitchOutput;
frontPower = (PitchOutput*-1);
frontESC.writeMicroseconds(backPower + throttle);
backESC.writeMicroseconds(frontPower + throttle);
}
As you can see, I don't yet have a real algorithm to stabilize the quad.
I would be grateful for some help. I have already tried some samples. It didn't go well. Even help without using my PID library would be appreciated.

Resources