Converting area of intersection to generate a coordinate - arduino

I was working on a project where I get analog values from a resistive touchscreen and turn them into intersection points.
Here is an example:
Here is my code for the data collection using an Arduino Uno and construction of the points using tool called processing.
#define side1 2
#define side2 3
#define side3 4
#define side4 5
#define contact A0
void setup() {
pinMode(contact, INPUT);
pinMode(side1, OUTPUT);
pinMode(side2, OUTPUT);
pinMode(side3, OUTPUT);
pinMode(side4, OUTPUT);
Serial.begin(9600);
}
void loop() {
int sensorValue1;
int sensorValue2;
int sensorValue3;
int sensorValue4;
// SENSOR VALUE 1:
digitalWrite(side1, LOW);
digitalWrite(side2, HIGH);
digitalWrite(side3, HIGH);
digitalWrite(side4, HIGH);
delay(5);
for (int i = 0; i < 10; i++){
sensorValue1 = analogRead(contact);
}
// SENSOR VALUE 2:
digitalWrite(side2, LOW);
digitalWrite(side3, HIGH);
digitalWrite(side4, HIGH);
digitalWrite(side1, HIGH);
delay(5);
for (int i = 0; i < 10; i++){
sensorValue2 = analogRead(contact);
}
// SENSOR VALUE 3:
digitalWrite(side3, LOW);
digitalWrite(side2, HIGH);
digitalWrite(side4, HIGH);
digitalWrite(side1, HIGH);
delay(5);
for (int i = 0; i < 10; i++){
sensorValue3 = analogRead(contact);
}
// SENSOR VALUE 2:
digitalWrite(side4, LOW);
digitalWrite(side3, HIGH);
digitalWrite(side2, HIGH);
digitalWrite(side1, HIGH);
delay(5);
for (int i = 0; i < 10; i++){
sensorValue4 = analogRead(contact);
}
Serial.print(sensorValue1);
Serial.print(",");
Serial.print(sensorValue2);
Serial.print(",");
Serial.print(sensorValue3);
Serial.print(",");
Serial.print(sensorValue4);
Serial.println();
}
This is the Processing code for the construction of the graph.
import processing.serial.*;
Serial myPort; // The serial port
int maxNumberOfSensors = 4;
float[] sensorValues = new float[maxNumberOfSensors];
float sensorValueX;
float sensorValueX1;
float sensorValueY;
float sensorValueY1;
int scaleValue = 2;
void setup () {
size(600, 600); // set up the window to whatever size you want
//println(Serial.list()); // List all the available serial ports
String portName = "COM5";
myPort = new Serial(this, portName, 9600);
myPort.clear();
myPort.bufferUntil('\n'); // don't generate a serialEvent() until you get a newline (\n) byte
background(255); // set inital background
smooth(); // turn on antialiasing
}
void draw () {
//background(255);
//noFill();
fill(100,100,100,100);
ellipse(height,0, scaleValue*sensorValues[0], scaleValue*sensorValues[0]);
ellipse(0,width, scaleValue*sensorValues[1], scaleValue*sensorValues[1]);
ellipse(height,width, scaleValue*sensorValues[2], scaleValue*sensorValues[2]);
ellipse(0,0, scaleValue*sensorValues[3], scaleValue*sensorValues[3]);
//ellipse(sensorValueY, sensorValueX, 10,10);
//println(sensorValueY,sensorValueX);
sensorValueX = ((sensorValues[3]*sensorValues[3])-(sensorValues[2]*sensorValues[2])+600*600)/2000;
sensorValueX1 = ((sensorValues[0]*sensorValues[0])-(sensorValues[1]*sensorValues[1])+600*600)/2000;
sensorValueY = ((sensorValues[3]*sensorValues[3])-(sensorValues[2]*sensorValues[2])+(600*600))/2000;
sensorValueY1 = ((sensorValues[1]*sensorValues[1])-(sensorValues[0]*sensorValues[0])+(600*600))/2000;
line(0, scaleValue*sensorValueX, height,scaleValue* sensorValueX);
line(scaleValue*sensorValueY, 0, scaleValue*sensorValueY, width);
ellipse(scaleValue*sensorValueY, scaleValue*sensorValueX, 20,20);
line(0, scaleValue*sensorValueX1, height,scaleValue* sensorValueX1);
line(scaleValue*sensorValueY1, 0, scaleValue*sensorValueY1, width);
ellipse(scaleValue*sensorValueY1, scaleValue*sensorValueX1, 20,20);
println(scaleValue*sensorValueX,scaleValue*sensorValueY);
}
void serialEvent (Serial myPort) {
String inString = myPort.readStringUntil('\n'); // get the ASCII string
if (inString != null) { // if it's not empty
inString = trim(inString); // trim off any whitespace
int incomingValues[] = int(split(inString, ",")); // convert to an array of ints
if (incomingValues.length <= maxNumberOfSensors && incomingValues.length > 0) {
for (int i = 0; i < incomingValues.length; i++) {
// map the incoming values (0 to 1023) to an appropriate gray-scale range (0-255):
sensorValues[i] = map(incomingValues[i], 0, 1023, 0, width);
//println(incomingValues[i]+ " " + sensorValues[i]);
}
}
}
}
I was wondering how I could convert the intersection of those points to a coordinate? Example: in the image, I showed you, I set the parameters for the dimensions to be (600,600). Is it possible to change that intersection are to a coordinate value? Currently, my code is printing out coordinates however they are diagonals such at the x and y values are equal. I want the coordinates of x and y to have different quantities so that I can get coordinates for different sides in the square. Can somebody help?

By reading your code I'm assuming that you know the position of all n sensors and the distance from each n sensor to a target. So what you're essentially trying to do is trilateration (as mentioned by Nico Schertler). In other words determining a relative position based on the distance between n points.
Just a quick definition note in case of confusion:
Triangulation = Working with angles
Trilateration = Working with distances
Trilateration requires at least 3 points and distances.
1 sensor gives you the distance the target is away from the sensor
2 sensors gives you 2 possible locations the target can be
3 sensors tells you which of the 2 locations the target is at
The first solution that probably comes to mind is calculating the intersections
between 3 sensors treating them as circles. Given that there might be some error in the distances this means that the circles might not always intersect. Which rules out this solution.
The following code has all been done in Processing.
I took the liberty of making a class Sensor.
class Sensor {
public PVector p; // position
public float d; // distance from sensor to target (radius of the circle)
public Sensor(float x, float y) {
this.p = new PVector(x, y);
this.d = 0;
}
}
Now to calculate and approximate the intersection point between the sensors/circles, do the following:
PVector trilateration(Sensor s1, Sensor s2, Sensor s3) {
PVector s = PVector.sub(s2.p, s1.p).div(PVector.sub(s2.p, s1.p).mag());
float a = s.dot(PVector.sub(s3.p, s1.p));
PVector t = PVector.sub(s3.p, s1.p).sub(PVector.mult(s, a)).div(PVector.sub(s3.p, s1.p).sub(PVector.mult(s, a)).mag());
float b = t.dot(PVector.sub(s3.p, s1.p));
float c = PVector.sub(s2.p, s1.p).mag();
float x = (sq(s1.d) - sq(s2.d) + sq(c)) / (c * 2);
float y = ((sq(s1.d) - sq(s3.d) + sq(a) + sq(b)) / (b * 2)) - ((a / b) * x);
s.mult(x);
t.mult(y);
return PVector.add(s1.p, s).add(t);
}
Where s1, s2, s3 is any of your 3 sensors, do the following to calculate the the intersection point between the given sensors:
PVector target = trilateration(s1, s2, s3);
While it is possible to calculate the intersection between any amount of sensors. It becomes more and more complex the more sensors you want to include. Especially since you're doing it yourself. If you're able to use external Java libraries, then it would be a lot easier.
If you're able to use external Java libraries, then I highly recommend using com.lemmingapex.trilateration. Then you'd be able to calculate the intersection point between 4 sensors by doing:
Considering s1, s2, s3, s4 as instances of the previously mentioned class Sensor.
double[][] positions = new double[][] { { s1.x, s1.y }, { s2.x, s2.y }, { s3.x, s3.y }, { s4.x, s4.y } };
double[] distances = new double[] { s1.d, s2.d, s3.d, s4.d };
NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(
new TrilaterationFunction(positions, distances),
new LevenbergMarquardtOptimizer());
Optimum optimum = solver.solve();
double[] target = optimum.getPoint().toArray();
double x = target[0];
double y = target[1];
The following examples, are examples of the trilateration() method I wrote and not an example of the library above.
Example 1 - No Sensor Error
The 3 big circles being any 3 sensors and the single red circle being the approximated point.
Example 2 - With Sensor Error
The 3 big circles being any 3 sensors and the single red circle being the approximated point.

What you need to compute is the point that it nearest to the a set of circles,
let denote their centers by (x1,y1), (x2,y2), (x3,y3), (x4,y4) and their radii by r1,r2,r3,r4.
You want to find (x,y) that minimizes
F(x,y) = Sum_i [ square( d2( (x,y), (xi,yi)) - ri) ]
This can be achieved by using Newton's algorithm. Newton's algorithm works from an "initial guess" (let's say at the center of the screen), improved iteratively by solving a series of linear systems (in this case, with 2 variables, easy to solve).
M P = -G
where M is the (2x2) matrix of the second order derivatives of F with respect to x and y (called the Hessian), and G the vector of the first order derivatives of F with
respect to x and y (the gradient). This gives the "update" vector P, that tells how to move the coordinates:
Then (x,y) is updated by x = x + Px, y = y + Py, and so on and so forth (recompute M and G, solve for P, update x and y, recompute M and G, solve for P, update x and y). In your case it will probably converge in a handful of iterations.
Since you got two variables only, the 2x2 linear solve is trivial, and the expression of F and its derivatives is simple, thus you can implement it without needing an external library.
Note1: the Levenberg-Marquardt algorithm mentioned in the other answer is a variant of Newton's algorithm (specialized for sum of squares, like here, and that neglects some terms, and that regularizes the matrix M by adding small numbers to its diagonal coefficients). More on this here.
Note2: a simple gradient descent will also probably work (a bit simpler to implement, since it only uses first order derivatives), but given that you only got two variables to implement, the 2x2 linear solve is trivial, so Newton is probably worth it (requires a much much smaller number of iterations for convergence, may be critial if your system is interactive).

Related

Receiving denormalized output texture coordinates in Frag shader

Update
See rationale at the end of my question below
Using WebGL2 I can access a texel by its denormalized coordinates (sorry don't the right lingo for this). That means I don't have to scale them down to 0-1 like I do in texture2D().
However the input to the fragment shader is still the vec2/3 in normalized values.
Is there a way to declare in/out variables in the Vertex and Frag shaders so that I don't have to scale the coordinates?
somewhere in vertex shader:
...
out vec2 TextureCoordinates;
somewhere in frag shader:
...
in vec2 TextureCoordinates;
I would like for TextureCoordinates to be ivec2 and already scaled.
This question and all my other questions on webgl related to general computing using WebGL. We are trying to do tensor (multi-D matrix) operations using WebGL.
We map our data in a few ways to a Texture. The simplest approach we follow is -- assuming we can access our data as a flat array -- to lay it out along the texture's width and go up the texture's height until we're done.
Since our thinking, logic, and calculations are all based on tensor/matrix indices -- inside the fragment shader -- we'd have to map back to/from the X-Y texture coordinates to indices. The intermediate step here is to calculate an offset for a given position of a texel. Then from that offset we can calculate the matrix indices from its strides.
Calculating an offset in webgl 1 for very large textures seems to be taking much longer than webgl2 using the integer coordinates. See below:
WebGL 1 offset calculation
int coordsToOffset(vec2 coords, int width, int height) {
float s = coords.s * float(width);
float t = coords.t * float(height);
int offset = int(t) * width + int(s);
return offset;
}
vec2 offsetToCoords(int offset, int width, int height) {
int t = offset / width;
int s = offset - t*width;
vec2 coords = (vec2(s,t) + vec2(0.5,0.5)) / vec2(width, height);
return coords;
}
WebGL 2 offset calculation in the presence of int coords
int coordsToOffset(ivec2 coords, int width) {
return coords.t * width + coords.s;
}
ivec2 offsetToCoords(int offset, int width) {
int t = offset / width;
int s = offset - t*width;
return ivec2(s,t);
}
It should be clear that for a series of large texture operations we're saving hundreds of thousands of operations just on the offset/coords calculation.
It's not clear why you want do what you're trying to do. It would be better to ask something like "I'm trying to draw an image/implement post processing glow/do ray tracing/... and to do that I want to use un-normalized texture coordinates because " and then we can tell you if your solution is going to work and how to solve it.
In any case, passing int or unsigned int or ivec2/3/4 or uvec2/3/4 as a varying is supported but not interpolation. You have to declare them as flat.
Still, you can pass un-normalized values as float or vec2/3/4 and the convert to int, ivec2/3/4 in the fragment shader.
The other issue is you'll get no sampling using texelFetch, the function that takes texel coordinates instead of normalized texture coordinates. It just returns the exact value of a single pixel. It does not support filtering like the normal texture function.
Example:
function main() {
const gl = document.querySelector('canvas').getContext('webgl2');
if (!gl) {
return alert("need webgl2");
}
const vs = `
#version 300 es
in vec4 position;
in ivec2 texelcoord;
out vec2 v_texcoord;
void main() {
v_texcoord = vec2(texelcoord);
gl_Position = position;
}
`;
const fs = `
#version 300 es
precision mediump float;
in vec2 v_texcoord;
out vec4 outColor;
uniform sampler2D tex;
void main() {
outColor = texelFetch(tex, ivec2(v_texcoord), 0);
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// create buffers via gl.createBuffer, gl.bindBuffer, gl.bufferData)
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-.5, -.5,
.5, -.5,
0, .5,
],
},
texelcoord: {
numComponents: 2,
data: new Int32Array([
0, 0,
15, 0,
8, 15,
]),
}
});
// make a 16x16 texture
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = 16;
ctx.canvas.height = 16;
for (let i = 23; i > 0; --i) {
ctx.fillStyle = `hsl(${i / 23 * 360 | 0}, 100%, ${i % 2 ? 25 : 75}%)`;
ctx.beginPath();
ctx.arc(8, 15, i, 0, Math.PI * 2, false);
ctx.fill();
}
const tex = twgl.createTexture(gl, { src: ctx.canvas });
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// no need to set uniforms since they default to 0
// and only one texture which is already on texture unit 0
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
main();
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
So in response to your updated question it's still not clear what you want to do. Why do you want to pass varyings to the fragment shader? Can't you just do whatever math you want in the fragment shader itself?
Example:
uniform sampler2D tex;
out float result;
// some all the values in the texture
vec4 sum4 = vec4(0);
ivec2 texDim = textureSize(tex, 0);
for (int y = 0; y < texDim.y; ++y) {
for (int x = 0; x < texDim.x; ++x) {
sum4 += texelFetch(tex, ivec2(x, y), 0);
}
}
result = sum4.x + sum4.y + sum4.z + sum4.w;
Example2
uniform isampler2D indices;
uniform sampler2D data;
out float result;
// some only values in data pointed to by indices
vec4 sum4 = vec4(0);
ivec2 texDim = textureSize(indices, 0);
for (int y = 0; y < texDim.y; ++y) {
for (int x = 0; x < texDim.x; ++x) {
ivec2 index = texelFetch(indices, ivec2(x, y), 0).xy;
sum4 += texelFetch(tex, index, 0);
}
}
result = sum4.x + sum4.y + sum4.z + sum4.w;
Note that I'm also not an expert in GPGPU but I have an hunch the code above is not the fastest way because I believe parallelization happens based on output. The code above has only 1 output so no parallelization? It would be easy to change so that it takes a block ID, tile ID, area ID as input and computes just the sum for that area. Then you'd write out a larger texture with the sum of each block and finally sum the block sums.
Also, dependant and non-uniform texture reads are a known perf issue. The first example reads the texture in order. That's cache friendly. The second example reads the texture in a random order (specified by indices), that's not cache friendly.

Arduino PID DC Motor Position Control

I'm doing a control engineering project, implementing a PID motor position control for automatic antenna tracking system. The system contain a dc motor, absolute encoder, and a motor driver.
Everything work as expected, but one thing. The motor cannot stop at set point value near 0 degree (350 - 359, 0 - 10 degree). The used code:
#include <PID_v1.h>
int RPWM = 5;
int LPWM = 6;
int L_EN = 7;
int R_EN = 8;
boolean pin_state[10];
byte input_pin[] = {1, 2, 3, 4, 9, 10, 11, 12, 13};
int dec_position = 0;
int dc = 0;
double kp = 50, ki = 45, kd = 2;
double input = 0, output = 0, setpoint = 0;
volatile long encoderPos = 0;
PID myPID(&input, &output, &setpoint, kp, ki, kd, DIRECT);
void setup() {
pinMode(L_EN, OUTPUT);
pinMode(R_EN, OUTPUT);
pinMode(RPWM, OUTPUT);
pinMode(LPWM, OUTPUT);
for (byte i = 0; i < 9; i++) {
pinMode(input_pin[i], INPUT);
}
TCCR1B = TCCR1B & 0b11111000 | 1;
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(1);
myPID.SetOutputLimits(-255, 255);
digitalWrite(L_EN, HIGH);
digitalWrite(R_EN, HIGH);
}
void loop() {
if (Serial.available() > 0) {
String baca = Serial.readString();
setpoint = baca.toInt();
}
ReadEncoder();
input = dc;
myPID.Compute();
pwmOut(output);
}
void pwmOut(int out) {
if (out > 0) {
analogWrite(RPWM, out);//Sets speed variable via PWM
}
else {
analogWrite(LPWM, abs(out));//Sets speed variable via PWM
}
}
void ReadEncoder() {
// FOR READING ENCODER POSITION, GIVING 0-359 OUTPUT CORRESPOND TO THE ENCODER POSITION
for (byte i = 0; i < 9; i++) {
pin_state[i] = !(digitalRead(input_pin[i]));
}
dec_position = (pin_state[8] * 256) + (pin_state[7] * 128) + (pin_state[6] * 64) + (pin_state[5] * 32) + (pin_state[4] * 16) + (pin_state[3] * 8) + (pin_state[2] * 4) + (pin_state[1] * 2) + pin_state[0];
dc = map(dec_position, 0, 500, 0, 360);
}
When the set point is a value between 10 - 350 the sytem worked well. But when it is not, the motor never stop rotating.
I know the problem is due to a little position overshoot cause the encoder to read a very large error.
For instance, if the setpoint is 0 degree, the motor rotate to reach it. Motor rotation is slowing down as its "now" position approaching 0 degree, but the system is not overshoot free. Therefore, even 1 degree overshoot cause the error value is -359 (set point - now position) and the motor rotate again to reach the desired position.
Need help how to overcome this problem. Sorry for bad english.
Here's the solution
double error;
if (SP>PV) {
if (abs(SP-PV) < abs(-360 + SP - PV)) error = SP - PV;
else error = -360 + SP - PV;
}
else{
if(abs(SP-PV)< abs(360 - PV + SP)) error = SP - PV;
else error = 360 - SP + PV;
}
Instead off simple present value minus the set point for error. The code above return shortest path from present value to set point.
i didn't read your code yet. However, to reach "set point" (SV) you should give for "present value" (PV) an error allowance (EA)
For example: EA = SV - PV.
If EA = (-2,+2)degree then it reach "now position"
And, you should not use degree for angle, you should convert it to position (calculate by pulse)
Hope that concept can help you.

Haversine Formula Error - Incorrect Distance - Arduino

Currently taking part in a project that requires to take readings from a gps module and then using these calculate the distance between the readings and a fixed waypoint. The Gps works and gives the values of LAT - 54.9289 and LON - -1.368 this should give a distance of about 3,200 meters. however it gives around 6105. I also have a feeling that 6105 is km to haha. Im wondering if its not taking the negative numbers correctly or if i have some variable conflicts in the code. Any light shed on this would be great, thanks.
#include <TinyGPS.h>
#include <SoftwareSerial.h>
#include <rgb_lcd.h>
#include <Wire.h>
//Sets TX And RX Pins
SoftwareSerial GPS(2,3);
TinyGPS gps;
void gpsdump(TinyGPS &gps);
bool feedgps();
void CheckGPS();
void GetCoords();
long lat, lon;
float LAT, LON; // Latitude is gained from GPS and stored in another variable to avoid errors - Should change with changing GPS value - Which would alter distance to waypoint.
float LAT1,LON1;
rgb_lcd lcd;
void setup()
{
// Sets Baud Rate
GPS.begin(9600);
Serial.begin(115200);
}
// Determines The Distance Between Current Location And Waypoint
void GetDistance()
{
// Calculating Distance Between Waypoints
double Distance_Lat; // Distance between Lattitude values
double Distance_Lon; // Distance between Lonitude values
double Distance_Total = 0;// Total Distance
double val,val2; // Subsidary variable for holding numbers. - No actual value represented.
double fLAT1,fLAT2;
double LAT2 = 54.900000; // Waypoint Latitude
double LON2 = -1.368072; // Waypoint Longitude
// Initialising Calculation
Distance_Lat = radians(LAT2-LAT1); // Must be done in radians
fLAT1 = radians(LAT1);
fLAT2 = radians(LAT2);
Distance_Lon = radians((LON2)-(LON1));
// Calculating Distance - Using Haversines Formulae
Distance_Total = (sin(Distance_Lat/2.0)*sin(Distance_Lat/2.0));
val = cos(fLAT1);
val = val*(cos(fLAT2));
val = val*(sin(Distance_Lon/2.0));
val = val*(sin(Distance_Lon/2.0));
Distance_Total = Distance_Total + val;
Distance_Total = 2*atan2(sqrt(Distance_Total),sqrt(1.0-Distance_Total));
Distance_Total = Distance_Total*6371.0000; // Converting to meters.
Serial.println("Distance: ");
Serial.println(Distance_Total);
//---------------------------------------------------------------------------------
}
// Returns Latitude And Longitude As Decimal Degrees (DD).
void GetCoords()
{
long lat, lon;
CheckGPS();
Serial.print("Latitude : ");
Serial.print(LAT/1000000,7);
Serial.print(" :: Longitude : ");
Serial.println(LON/1000000,7);
}
void CheckGPS()
{
bool newdata = false;
unsigned long start = millis();
// Every 1 seconds, Print an update
while (millis() - start < 1000)
{
if (feedgps ())
newdata = true;
if (newdata)
gpsdump(gps);
}
}
// Checks If The GPS Has Any Data To Transmit
bool feedgps()
{
while (GPS.available())
if (gps.encode(GPS.read()))
return true;
else
return false;
}
// Transmits GPS Data And Gets Latitude And Longitude Positions.
void gpsdump(TinyGPS &gps)
{ gps.get_position(&lat, &lon);
LAT = lat;
LON = lon;
//Keeps The GPS Fed To Avoid Checksum Errors.
feedgps();
}
void loop()
{
// Function That Returns The GPS Coordinates In DD.
GetCoords();
GetDistance();
}
The haversine formula I'm looking at on Wikipedia at right now, https://en.wikipedia.org/wiki/Haversine_formula, has arcsin(sqrt(Distance_Total)) where you have your atan2.

Get 3 Values from processing to Arduino

I have a color tracking program in Processing, which works with a Kinect. When I click somewhere in the picture it saves this color and draws an ellipse around it. I just want to send 3 int values (one for red, green and blue) over myPort.write() to Arduino and save these 3 values in Arduino in 2 variables. My goal is to light a red LED if the red variable is the highest, and the green LED if green is the highest and so on.
I've tried several examples I found whiel googling, but nothing works. I don't know how Arduino should get the correct values in the variables!
EDIT: Here you have my Processing code. I glued it together from several other tutorials until I nearly cried..
import processing.serial.*;
Serial myPort;
import SimpleOpenNI.*;
SimpleOpenNI kinect;
// Frame
PImage currentFrame;
color trackColor;
int r1, g1, b1, r2, g2, b2;
void setup()
{
size(640, 480);
String portName = Serial.list()[0]; //change the 0 to a 1 or 2 etc. to match your port
myPort = new Serial(this, portName, 9600);
kinect = new SimpleOpenNI(this);
kinect.enableRGB();
trackColor = color (255, 0, 0);
smooth ();
currentFrame = createImage (640, 480, RGB);
}
void draw()
{
kinect.update();
currentFrame = kinect.rgbImage ();
image(currentFrame, 0, 0);
currentFrame.loadPixels();
// Before we begin searching, the "world record" for closest color is set to a high number that is easy for the first pixel to beat.
float worldRecord = 500;
// XY coordinate of closest color
int closestX = 0;
int closestY = 0;
// Begin loop to walk through every pixel
for (int x = 0; x < currentFrame.width; x ++ ) {
for (int y = 0; y < currentFrame.height; y ++ ) {
int loc = x + y*currentFrame.width;
// What is current color
color currentColor = currentFrame.pixels[loc];
r1 = (int)red(currentColor);
g1 = (int)green(currentColor);
b1 = (int)blue(currentColor);
r2 = (int)red(trackColor);
g2 = (int)green(trackColor);
b2 = (int)blue(trackColor);
// Using euclidean distance to compare colors
float d = dist(r1, g1, b1, r2, g2, b2); // We are using the dist( ) function to compare the current color with the color we are tracking.
// If current color is more similar to tracked color than
// closest color, save current location and current difference
if (d < worldRecord) {
worldRecord = d;
closestX = x;
closestY = y;
}
}
}
// We only consider the color found if its color distance is less than 10.
// This threshold of 10 is arbitrary and you can adjust this number depending on how accurate you require the tracking to be.
if (worldRecord < 10) {
// Draw a circle at the tracked pixel
fill(trackColor);
strokeWeight(4.0);
stroke(0);
ellipse(closestX, closestY, 30, 30);
}
if (mousePressed == true) {
color c = get(mouseX, mouseY);
//println("r: " + red(c) + " g: " + green(c) + " b: " + blue(c));
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*(currentFrame.width);
trackColor = currentFrame.pixels[loc];
println("red " + r2);
println("green " + g2);
println("blue " + b2);
int colors[] = {r2, g2, b2};
for(int i=0; i < 3; i++) {
myPort.write(colors[i]);
}
}
println("ClosestX " + closestX);
myPort.write(closestX);
}
And my Arduino Code, where I don't know how to get several values.
int val;
int ledPin = 13;
int freq;
int piezoPin = 9;
int redLED = 3;
int greenLED = 5;
int blueLED = 7;
int red, green, blue;
void setup() {
pinMode(ledPin, OUTPUT); // Set pin as OUTPUT
Serial.begin(9600); // Start serial communication at 9600 bps
digitalWrite(ledPin, LOW);
}
void loop() {
if (Serial.available() > 0)
{ // If data is available to read,
val = Serial.read(); // read it and store it in val
}
if(red > green && red > blue) {
digitalWrite(redLED, HIGH); //light Red LED
}
if(green > red && green > blue) {
digitalWrite(greenLED, HIGH); //light Red LED
}
if(blue > red && blue > green) {
digitalWrite(blueLED, HIGH); //light Red LED
}
//Piezo buzzing higher when X-Position of tracked color is higher.
if (val < 100) {
freq = 50;
}
else if (val < 200) {
freq = 200;
}
else if (val < 300) {
freq = 400;
}
else if (val < 400) {
freq = 600;
}
else if (val < 500) {
freq = 800;
}
else (freq = 1000);
tone(piezoPin, freq);
}
EDIT2: Yes, additionally to lighing the LEDs I also want to have a sound from a piezo buzzer, but that works pretty well, so no questions on that... yet.
Help, please!!
Serial communication to your arduino works with a single byte at a time.
As luck would have it, the three components of a Processing Color are also three bytes.
One for red(0-255)
One for green(0-255)
One for blue(0-255)
Now all we need is a little more info so we can keep them separate.
Because a byte's minimum and maximum values are 0-255, there's no safe character we can use to keep track of the three different bytes, so we need a way to figure out where the info we send begins and ends.
An easy way to do this, is to set up a header and a footer for your messages ; something like :
<color>[byte (red)][byte (green)][byte (blue)]</color>
If we are going to read and decipher messages formatted like this, we are going to need a little buffer that will store the values we receive from Processing, so we can read them back and see if we can match the message format.
So, on the Arduino side, we need this :
String buffer = "";
String messageBegin = "<color>";
String messageEnd = "</color>";
//we read our serial data in the SerialEvent() function
//this is called *after* a loop(), and only if there is serial data in the buffer.
void serialEvent()
{
while(Serial.available())
{
buffer += (char)Serial.read();
}
}
void loop()
{
//now, inside loop, we no longer need to worry about gathering data from serial.
//we do still need to figure out if our message is complete, and then parse it.
//if our buffer contains both the beginning and the end of a message
//in the right order.
int beginIndex = buffer.lastIndexOf(messageBegin);
int endIndex = buffer.lastIndexOf(messageEnd);
if(beginIndex != -1 && endIndex != -1 && beginIndex < endIndex)
{
//we have a complete message!
//our red color starts 7 characters after where the message begins,
//because our "messageBegin" is 7 characters long
string lastMessage = buffer.substring(beginIndex+7);
//this is arguably not the prettiest way to get our byte values back.
//see if you can do better for bonus points!
byte messageAsBytes[80];
lastMessage.getBytes(messageAsBytes, messageAsBytes.length());
//we can now finally reconstruct the value we had from processing!
byte r = (byte)messageAsBytes[0];
byte g = (byte)messageAsBytes[1];
byte b = (byte)messageAsBytes[2];
//if we get a complete message, we can clear our buffer. (don't forget to do this!)
buffer = "";
}
}
On the processing side, all we need to do is make sure our messagebegin and messageend are sent along for the ride :
myPort.write("<color">);
for(int i=0; i < 3; i++) {
myPort.write(colors[i]);
}
myPort.write("</color">);

why fundamental Frequency and magnitude are not null when microphone is off?

I would like to make real time audio processing with Qt and display the spectrum using FFTW3.
What I've done in steps:
I capture any sound from computer device and fill it into the buffer.
I assign sound samples to double array
I compute the fundamental frequency.
when I'm display the fundamental frequency and Magnetitude when the microphone is on but no signal(silence) , the fundamental frequency is not what I expected , the code don't always return zero , sometimes the code returns 1500Hz,2000hz as frequency
and when the microphone is off (mute) the code don't return zero as fundamamental frequency but returns a number between 0 and 9000Hz. Any help woulbd be appreciated
here is my code
QByteArray *buffer;
QAudioInput *audioInput;
audioInput = new QAudioInput(format, this);
//Check the number of samples in input buffer
qint64 len = audioInput->bytesReady();
//Limit sample size
if(len > 4096)
len = 4096;
//Read sound samples from input device to buffer
qint64 l = input->read(buffer.data(), len);
int input_size= BufferSize;
int output_size = input_size; //input_size/2+1;
fftw_plan p3;
double in[output_size];
fftw_complex out[output_size];
short *outdata = (short*)m_buffer.data();// assign sample into short array
int data_size = size_t(outdata);
int data_size1 = sizeof(outdata);
int count = 0;
double w = 0;
for(int i(chanelNumber); i < output_size/2; i= i + 2) //fill array in
{
w= 0.5 * (1 - cos(2*M_PI*i/output_size)); // Hann Windows
double x = 0;
if(i < data_size){
x = outdata[i];
}
if(count < output_size){
in[count] = x;// fill Array In with sample from buffer
count++;
}
}
for(int i=count; i<output_size; i++){
in[i] = 0;
}
p3 = fftw_plan_dft_r2c_1d(output_size, in, out, FFTW_ESTIMATE);// create Plan
fftw_execute(p3);// FFT
for (int i = 0; i < (output_size/2); i++) {
long peak=0;
double Amplitudemax=0;
double r1 = out[i][0] * out[i][0];
double im1 = out[i][3] * out[i][4];
double t1 = r1 + im1;
//double t = 20*log(sqrt(t1));
double t = sqrt(t1)/(double)(output_size/2);
double f = (double)i*8000 / ((double)output_size/2);
if(Magnitude > AmplitudeMax)
{
AmplitudeMax = Magnitude;
Peak =2* i;
}
}
fftw_destroy_plan(p3);
return Peak*(static_cast<double>(8000)/output_Size);
What you think is silence might contain some small amount of noise. The FFT of random noise will also appear random, and thus have a random magnitude peak. But it is possible that noise might come from equipment or electronics in the environment (fans, flyback transformers, etc.), or the power supply to your ADC or mic, thus showing some frequency biases.
If the noise level is low enough, normally one checks the level of the magnitude peak, compares it against a threshold, and cuts off frequency estimation reporting below this threshold.

Resources