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

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;
}

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.

calculating wind speed from frequency value

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.

Processing - lines get bigger progressively

so I have in a file the coordinates and the seconds I want to make a line get bigger progressively. In the file, I have x1, x2 (regarding the first point coordinates), x2, y2 (2nd point coordinates), and the time (in seconds) I want to start growing the line, in the second point direction.
This is my code:
//TO READ LINES
import processing.video.*;
Movie myMovie;
Table table;
float duration, time;
int row_no=1;
int clickcount = 0;
void setup() {
size(640,480);
myMovie = new Movie(this, "draft.mov");
myMovie.loop();
table = loadTable("data/new.csv");
}
void draw() {
duration = myMovie.duration();
time = myMovie.time();
image(myMovie, 0, 0);
if(time>= table.getFloat(row_no, 4)){
strokeWeight(15);
stroke(255,14,255);
float a = table.getFloat(row_no, 0);
float b = table.getFloat(row_no,1);
line(table.getFloat(row_no,0),table.getFloat(row_no, 1), a, b);
a = a + 2;
b = b + 2;
}
}
// Called every time a new frame is available to read
void movieEvent(Movie m) {
m.read();
} `
As Niccolo advises, break your problem down first, take out anything you don't need and go one step at a time.
In terms or taking stuff out, based on the description of your goals, it doesn't sound like code has anything to do with playing back a movie, so take that code out to simplify. (The only reason I could think of for using a movie is to use it's current time to control the lines, but unless you want a movie background you shouldn't need that)
In the draw() loop there are a few things that look odd:
if(time>= table.getFloat(row_no, 4)){ assuming the 5th column in the .csv file holds the cue time for the current row in seconds, this condition will trigger only once potentially as there's nothing incrementing row_no
line(table.getFloat(row_no,0),table.getFloat(row_no, 1), a, b); isn't probably what you're after and might be a typo because a and b have retrieved from the same .csv columns (0 and 1), which means you're line's start and end position are in the exact position (therefore not rendering a line). perhaps you meant line(table.getFloat(row_no,2),table.getFloat(row_no, 3), a, b); ?
a = a + 2; and b = b + 2;: the x,y positions for one of the points may be offset by 2, but the new positions are never used past this point. In the next draw() iteration a and b are redefined, and therefore the offset is lost.
Let's go through breaking the problem down:
I have in a file the coordinates and the seconds I want to make a line get bigger progressively. In the file, I have x1, x2 (regarding the first point coordinates), x2, y2 (2nd point coordinates), and the time (in seconds) I want to start growing the line, in the second point direction.
load and parse the data (rows containing line coordinates (x1,y1,x2,y2) and time(in seconds))
"make a line get bigger progressively" - animate (interpolate) between the current line (.csv row coordinates) and the next line based on the specified time in seconds)
and even further, if starting from scratch, more as a "how to":
interpolate between one value an another (ignoring time for now, keeping task independent and as simple as possible)
keep track of time as a parameter for interpolating between values
parsing .csv rows
interpolating between 4 four values
incrementing .csv rows based on animation time
Luckily, Processing provides a built-in function for linearly interpolating between values lerp()(lerp = linear interpolation for short).
It takes three parameters:
a value to animate from (start)
a value to animate to (stop)
an interpolation amount (between 0.0 and 1.0)
and it returns one value: the value in between the start and stop values.
Think of the interpolation amount as a percentage (0 = 0%, 0.5 = 50%, 1.0 = 100%).
Here's a basic sketch to illustrate the concept:
void draw(){
background(255);
//map time to an interpolation normalized value
float t = map(mouseX,0,width,0.0,1.0);
//interpolate the values
float size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
the snippet a p5.js demo you can run bellow:
function setup() {
createCanvas(100,100);
}
function draw(){
background(255);
//map time to an interpolation normalized value
var t = map(mouseX,0,width,0.0,1.0);
//interpolate the values
var size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>
if you move your mouse on the x axis you'll notice the size goes between 10 and 90 pixels in diameter based on the mouse position.
Step 1 done!
Next up, you can use millis() to keep track of time and simply map() between time in millis (mapping the current time between the start and end time to the 0.0 - 1.0 range):
float seconds = 3.5;
//the time in millis since the last update
int previousMillis;
//the current time in millis
int currentMillis;
//the time in millis until the next event
int nextMillis;
void setup(){
previousMillis = millis();
currentMillis = millis();
nextMillis = currentMillis + (int)(seconds * 1000);
}
void draw(){
background(255);
//update the current timer continously
currentMillis = millis();
//map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
float t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);
//interpolate the values
float size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
and as a p5.js runnable demo:
var seconds = 3.5;
//the time in millis since the last update
var previousMillis;
//the current time in millis
var currentMillis;
//the time in millis until the next event
var nextMillis;
function setup(){
previousMillis = millis();
currentMillis = millis();
nextMillis = currentMillis + (int)(seconds * 1000);
}
function draw(){
background(255);
//update the current timer continously
currentMillis = millis();
//map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
var t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);
//interpolate the values
var size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>
That's step2 done and it looks like you've got a hand of step 3 (parsing the .csv values) already :)
Step 4 should be trivial once you understand how to interpolate one value: just do it 4 times for different variables!
Step 5 is simple as you simply need to check if row_no goes beyond the table's row count.
row_no = row_no + 1;
if(row_no > table.getRowCount()) row_no = 0;
One neat thing you could do is use the modulo operator(%) to do the same as a mathematical expression:
row_no = (row_no + 1) % table.getRowCount();
In conclusion, let's assume you're .csv file looks a little like this:
x1,y1,x2,y2,seconds
5,5,95,5,4
95,5,95,95,3
95,95,5,95,2
5,95,5,5,1
One way to put it all together would be something like this:
Table table;
int row_no = 0;
//the time in millis since the last update
int previousMillis;
//the current time in millis
int currentMillis;
//the time in millis until the next event
int nextMillis;
//where to animate the line from
float x1Start,y1Start,x2Start,y2Start;
//where to animate the line to
float x1Stop,y1Stop,x2Stop,y2Stop;
//currently interpolated line positions
float x1Lerp,y1Lerp,x2Lerp,y2Lerp;
void setup(){
size(100,100);
strokeWeight(3);
fill(0);
table = loadTable("data/new.csv","header, csv");
//printing the table in console, handy just for debugging/double checking values
println("data");
for(int i = 0 ; i <= table.getRowCount(); i++){
print(table.getColumnTitle(i)+"\t");
}
println();
for(int i = 0 ; i < table.getRowCount(); i++){
TableRow row = table.getRow(i);
for(int j = 0; j < row.getColumnCount(); j++){
print(row.getFloat(j) + "\t");
}
println();
}
//fetch lines and seconds from the current and next rows
updateFromRow();
}
void updateFromRow(){
//update times
previousMillis = millis();
currentMillis = millis();
//get the current row and it's line coordinates
TableRow currentRow = table.getRow(row_no);
x1Start = currentRow.getFloat("x1");
y1Start = currentRow.getFloat("y1");
x2Start = currentRow.getFloat("x2");
y2Start = currentRow.getFloat("y2");
//get the next row and it's line coordinates - notice % module is used to easily loop back to 0 once row_no goes beyond the number of table rows
TableRow nextRow = table.getRow((row_no + 1) % table.getRowCount());
x1Stop = nextRow.getFloat("x1");
y1Stop = nextRow.getFloat("y1");
x2Stop = nextRow.getFloat("x2");
y2Stop = nextRow.getFloat("y2");
//get the duration in seconds, convert it to millis( * 1000) and add it to the current millis
nextMillis = currentMillis + (int)(currentRow.getFloat("seconds") * 1000);
println("updated from row: " + row_no);
}
void draw(){
background(255);
//update the current timer continously
currentMillis = millis();
//map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
float t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);
//if the current interpolation value is above 1.0
if(t > 1.0){
t = 0;
//increment the row
row_no++;
//if the current row counter is above the total number of rows, reset back 0
if(row_no >= table.getRowCount()){
row_no = 0;
}
//update values from incremented row (lines and their coordinates + time)
updateFromRow();
}
text("t:"+t,15,20);
//constrain interpolated value between 0.0 and 1.0
float interpolationAmount = constrain(t,0.0,1.0);
//linearly interpolate (lerp) between the current and next line coordinates
x1Lerp = lerp(x1Start,x1Stop,interpolationAmount);
y1Lerp = lerp(y1Start,y1Stop,interpolationAmount);
x2Lerp = lerp(x2Start,x2Stop,interpolationAmount);
y2Lerp = lerp(y2Start,y2Stop,interpolationAmount);
//finally, render the interpolated line
line(x1Lerp,y1Lerp,x2Lerp,y2Lerp);
}
In terms of keeping track of the data, the line coordinates can be stored using PVector instances (...the x,y components set() from .csv data and the line points can be interpolated in pairs via PVector's lerp()).
So far we've only been using linear interpolation, but you might also want to look into easing and tweening.

Processing: Make only some random pixels change colour

I have created some white noise, which I would like to decrease over time (change starting after 2 secs, intensifying after 10 secs etc), slowly tending towards a black screen.
What I can't figure out is, how can I make only some (say, 50% of all pixels) random pixels change colour, while the rest is just black, within the same frame?
So far, I could only make ALL of them change randomly, or ALL of them stay black. Any help would be much appreciated, thank you!!
void setup() {
size(1000, 800);
}
void draw() {
if (millis() < 2000) {
loadPixels();
for ( int i=0; i<pixels.length; i++)
pixels[i] = color(random(255));
updatePixels();
}
if (millis() > 2000) {
loadPixels();
if (random(1) >= 0.5) {
for ( int i=0; i<pixels.length; i++)
pixels[i] = color(random(255));
updatePixels();
} else {
loadPixels();
for ( int i=0; i<pixels.length; i++)
pixels[i] = color(0);
updatePixels();
}
}
if (millis() > 10000) {
loadPixels();
for ( int i=0; i<pixels.length; i++)
pixels[i] = color(random(255));
updatePixels();
}
}
A simple way would be to take into account that random() returns a random value within a range. If you give it a low value, you'll have a low random value.
If you use that value as a colour, the lower the value, the closer to black you are which might work well in your case.
If you have a randomness to 255, you increase the changes of having bright pixels, otherwise(with low random values), pixels will be dark:
//noise image
PImage noise;
//amount of noise image image 0 = 0%, 255 = 100%
int noiseAmt = 255;
void setup(){
noise = createImage(width,height,RGB);
}
void draw(){
//decrease noise over time
noiseAmt--;
if(noiseAmt < 0) noiseAmt = 255;
//apply noise based on noise amount
noiseImage();
//render image
image(noise,0,0);
}
void noiseImage(){
int numPixels = noise.pixels.length;
for(int i = 0 ; i < numPixels; i++){
//random(noiseAmt) is the key - low values = darker pixels
noise.pixels[i] = color(random(noiseAmt));
}
noise.updatePixels();
}
To get a hang of this, here's a slightly modified version of the code which uses the UP/DOWN arrow keys to control noise:
//noise image
PImage noise;
//amount of noise image image 0 = 0%, 255 = 100%
int noiseAmt = 127;
void setup() {
noise = createImage(width, height, RGB);
}
void draw() {
//apply noise based on noise amount
noiseImage();
//render image
image(noise, 0, 0);
}
void noiseImage() {
int numPixels = noise.pixels.length;
for (int i = 0; i < numPixels; i++) {
//random(noiseAmt) is the key - low values = darker pixels
noise.pixels[i] = color(random(noiseAmt));
}
noise.updatePixels();
}
void keyPressed(){
if(keyCode == UP) noiseAmt += 5;
if(keyCode == DOWN) noiseAmt -= 5;
noiseAmt = constrain(noiseAmt,0,255);
println("noiseAmt: " + noiseAmt);
}
Back to the matter of time, you can have a look this answer which covers tracking time using millis(). The only extra part is mapping the fade time to the noise amount, which would be some ratio. It might be easier if we map the time passed as a normalised value (from 0.0 to 1.0) which can easily scale to 0.0 to 255.0 simply by multiplying by 255:
//noise image
PImage noise;
//amount of noise image image 0 = 0%, 255 = 100%
int noiseAmt = 255;
int timestamp,fadeTime = 10000;//fade to black in 10s
void setup(){
noise = createImage(width,height,RGB);
timestamp = millis();
}
void draw(){
//decrease noise over time
int now = millis();
//if the difference between an initial timestamp and the current time is less than 10s
if(now - timestamp <= fadeTime){
//compute the ratio between the time difference and total fadeTime which will be from 0.0 to 1.0
//subtract this difference from 1.0 to flip the ratio direction from 0.0 -> 1.0 to 1.0 -> 0.0
float fadeRatio = 1.0 - ((float)(now-timestamp)/fadeTime);
//this ratio multiplied to 255 will be
noiseAmt = (int)(fadeRatio * 255);
}
//apply noise based on noise amount
noiseImage();
//render image
image(noise,0,0);
}
void noiseImage(){
int numPixels = noise.pixels.length;
for(int i = 0 ; i < numPixels; i++){
//random(noiseAmt) is the key - low values = darker pixels
noise.pixels[i] = color(random(noiseAmt));
}
noise.updatePixels();
}
Processing has some nice functions for dealing with mapping and constraining number ranges:
//noise image
PImage noise;
//amount of noise image image 0 = 0%, 255 = 100%
int noiseAmt = 255;
int timestamp,fadeTime = 10000;//fade to black in 10s
void setup(){
noise = createImage(width,height,RGB);
timestamp = millis();
}
void draw(){
//decrease noise over time
int now = millis();
//if the difference between an initial timestamp and the current time is less than 10s
noiseAmt = (int)map(now - timestamp,0,fadeTime,255,0);
noiseAmt = constrain(noiseAmt,0,255);
//apply noise based on noise amount
int numPixels = noise.pixels.length;
for(int i = 0 ; i < numPixels; i++){
//random(noiseAmt) is the key - low values = darker pixels
noise.pixels[i] = color(random(noiseAmt));
}
noise.updatePixels();
//render image
image(noise,0,0);
}
Note the fadeTime is set to 10s (10000 milliseconds). Feel free to tinker with the fadeTime value.
Instead of posting all of your code in an external website, boil your problem down to an MCVE and include it directly in your question.
That being said, you have two options:
Option 1: Store all of your pixels in some kind of data structure. You might have a 2D array of MyPixel objects, where MyPixel is a class you create that contains all of the information you need to know which instances in that array to change the color of.
Option 2: Draw directly to a PImage. Then you can iterate through that PImage to find a non-black pixel and change it.
Which approach you take is entirely up to you. I'd personally choose the first option, but that's just my personal preference. Try one of these approaches, and post an MCVE when you get stuck. Note that this should be as few lines as possible while still demonstrating the problem, not your whole sketch- we don't need to see your timing logic, for example.

Which is best simple Gaussian blur or FFT of Gaussian blur for sigma=20?

I'm making a program to blur a 16 bit grayscale image in CUDA.
In my program, if I use a Gaussian blur function with sigma = 20 or 30, it takes a lot of time, while it is fast with sigma = 2.0 or 3.0.
I've read in some web site that Guaussian blur with FFT is good for large kernel size or large sigma value:
Is It really true ?
Which algorithm should I use: simple Gaussian blur or Gaussian blur with FFT ?
My code for Guassian Blur is below. In my code , is there something wrong or not ?
enter code here
__global__
void gaussian_blur(
unsigned short* const blurredChannel, // return value: blurred channel (either red, green, or blue)
const unsigned short* const inputChannel, // red, green, or blue channel from the original image
int rows,
int cols,
const float* const filterWeight, // gaussian filter weights. The weights look like a bell shape.
int filterWidth // number of pixels in x and y directions for calculating average blurring
)
{
int r = blockIdx.y * blockDim.y + threadIdx.y; // current row
int c = blockIdx.x * blockDim.x + threadIdx.x; // current column
if ((r >= rows) || (c >= cols))
{
return;
}
int half = filterWidth / 2;
float blur = 0.f; // will contained blurred value
int width = cols - 1;
int height = rows - 1;
for (int i = -half; i <= half; ++i) // rows
{
for (int j = -half; j <= half; ++j) // columns
{
// Clamp filter to the image border
int h = min(max(r + i, 0), height);
int w = min(max(c + j, 0), width);
// Blur is a product of current pixel value and weight of that pixel.
// Remember that sum of all weights equals to 1, so we are averaging sum of all pixels by their weight.
int idx = w + cols * h; // current pixel index
float pixel = static_cast<float>(inputChannel[idx]);
idx = (i + half) * filterWidth + j + half;
float weight = filterWeight[idx];
blur += pixel * weight;
}
}
blurredChannel[c + r * cols] = static_cast<unsigned short>(blur);
}
void createFilter(float *gKernel,double sigma,int radius)
{
double r, s = 2.0 * sigma * sigma;
// sum is for normalization
double sum = 0.0;
// generate 9*9 kernel
int m=0;
for (int x = -radius; x <= radius; x++)
{
for(int y = -radius; y <= radius; y++)
{
r = std::sqrtf(x*x + y*y);
gKernel[m] = (exp(-(r*r)/s))/(3.14 * s);
sum += gKernel[m];
m++;
}
}
m=0;
// normalize the Kernel
for(int i = 0; i < (radius*2 +1); ++i)
for(int j = 0; j < (radius*2 +1); ++j)
gKernel[m++] /= sum;
}
int main()
{
cudaError_t cudaStatus;
const int size =81;
float gKernel[size];
float *dev_p=0;
cudaStatus = cudaMalloc((void**)&dev_p, size * sizeof(float));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
}
createFilter(gKernel,20.0,4);
cudaStatus = cudaMemcpy(dev_p, gKernel, size* sizeof(float), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
}
/* i read image Buffere in unsigned short that code is not added here ,becouse it is large , and copy image data of buffere from host to device*/
/* So, suppose i have unsigned short *d_img which contain image data */
cudaMalloc( (void**)&d_img, length* sizeof(unsigned short));
cudaMalloc( (void**)&d_blur_img, length* sizeof(unsigned short));
static const int BLOCK_WIDTH = 32;
int image_width=1580.0,image_height=1050.0;
int x = static_cast<int>(ceilf(static_cast<float>(image_width) / BLOCK_WIDTH));
int y = static_cast<int>(ceilf(static_cast<float>((image_height) ) / BLOCK_WIDTH));
const dim3 grid (x, y, 1); // number of blocks
const dim3 block(BLOCK_WIDTH, BLOCK_WIDTH, 1);
gaussian_blur<<<grid,block>>>(d_blur_img,d_img,1050.0,1580.0,dev_p,9.0);
cudaDeviceSynchronize();
/* after bluring image i will copied buffer from Device to Host and free gpu memory */
cudaFree(d_img);
cudaFree(d_blur_img);
cudaFree(dev_p);
return 0;
}
Short answer: both algorithms are good with respect to image blurring, so feel free to pick the best (fastest) one for your use case.
Kernel size and sigma value are directly correlated: the greater the sigma, the larger the kernel (and thus the more operations-per-pixel to get the final result).
If you implemented a naive convolution, then you should try a separable convolution implementation instead; it will reduce the computation time by an order of magnitude already.
Now some more insight: they implement almost the same Gaussian blurring operation. Why almost ? It's because taking the FFT of an image does implicitly periodize it. Hence, at the border of the image, the convolution kernel sees an image that has been wrapped around its edge. This is called circular convolution (because of the wrapping). On the other hand, Gaussian blur implements a simple linear convolution.

Resources