Get 3 Values from processing to Arduino - 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">);

Related

Arduino FastLED: Trying to group LEDs into pairs of two

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

How to print a number on with HT1632 only accepting text

I just bought a 8x32 lattice board (led matrix) and I control it with Arduino. The problem is that I can only use text with the library I got on github. But not numbers, how can I do it?
I'm going to put the code below, the code of the scrolling text and the part of the code in the library that specifies the function used to set the text.
The arduino code that program the scrolling text is here:
#include <HT1632.h>
#include <font_5x4.h>
#include <images.h>
int i = 0;
int wd;
char disp[] = "Hello, how are you?";
int x = 10;
void setup() {
HT1632.begin(A5, A4, A3);
wd = HT1632.getTextWidth(disp, FONT_5X4_END, FONT_5X4_HEIGHT);
}
void loop() {
HT1632.renderTarget(1);
HT1632.clear();
HT1632.drawText(disp, OUT_SIZE - i, 2, FONT_5X4, FONT_5X4_END,
FONT_5X4_HEIGHT);
HT1632.render();
i = (i + 1) % (wd + OUT_SIZE);
delay(100);
}
The library code that specifies the printing of the text is this:
void HT1632Class::drawText(const char text[], int x, int y, const byte font[],
int font_end[], uint8_t font_height,
uint8_t gutter_space) {
int curr_x = x;
char i = 0;
char currchar;
// Check if string is within y-bounds
if (y + font_height < 0 || y >= COM_SIZE)
return;
while (true) {
if (text[i] == '\0')
return;
currchar = text[i] - 32;
if (currchar >= 65 &&
currchar <=
90) // If character is lower-case, automatically make it upper-case
currchar -= 32; // Make this character uppercase.
if (currchar < 0 || currchar >= 64) { // If out of bounds, skip
++i;
continue; // Skip this character.
}
// Check to see if character is not too far right.
if (curr_x >= OUT_SIZE)
break; // Stop rendering - all other characters are no longer within the
// screen
// Check to see if character is not too far left.
int chr_width = getCharWidth(font_end, font_height, currchar);
if (curr_x + chr_width + gutter_space >= 0) {
drawImage(font, chr_width, font_height, curr_x, y,
getCharOffset(font_end, currchar));
// Draw the gutter space
for (char j = 0; j < gutter_space; ++j)
drawImage(font, 1, font_height, curr_x + chr_width + j, y, 0);
}
curr_x += chr_width + gutter_space;
++i;
}
}
You need to look at snprintf. This allows you to format a string of characters just like printf. It allows you to convert something like a int into a part of a string.
an example:
int hour = 10;
int minutes = 50;
char buffer[60];
int status = snprintf(buffer, 60, "the current time is: %i:%i\n", hour, minutes);
buffer now contains:"the current time is: 10:50" (and several empty characters past the \0).

Arduino nano data points missing

thanks for helping me out with my previous problem.
I am now able to get the data from the arduino to PC using putty with the FSR's attached to a sole and detecting pressures.
The only problem I am facing now is that it seems to be missing instances of Heel strike and Toe Off every now and then.(Image Attached)Plot of data
Blue line represents data from Heel FSR and Red line for Toe FSR
It can be seen from the picture that the arduino is missing a Heel Strike at blue coloured peak No 3 and a toe OFF instant at red peak 5 from the end.
Can any one tell me why this is happening regularly..
I am using arduino nano with baudrate 9600 and 2 FSR's ..On increasing the baudrate above 38400 the loss seems to occur more often
/** Code finds instances of toe off and heel strike using data from FSR's*/
void setup()
{
/*************************************************SERIAL**************************************************/
Serial.begin(9600);
}
/*Variables for FSRS*/
//A0= Toe,A1=Heel
int sum_toe_max = 0,sum_toe_min = 0, sum_heel_max = 0, sum_heel_min = 0 ,toe, heel, temp,diff_toe,diff_heel,data_heel=0, data_toe=0, data_toe2, data_heel2 ;
int heel_max[5] = {0, 0, 0, 0, 0}, toe_max[5] = {0, 0, 0, 0, 0}; /*These arrays holds the top 5 maximas upto the time of calibration*/
int heel_min[5]= {100,100,100,100,100}, toe_min[5]={100,100,100,100,100};/*These arrays holds the top 5 maximas upto the time of calibration*/
float avg_heel_max,avg_heel_min,avg_toe_max,avg_toe_min;/*variables to hold the averages of the valus of max and min arrays*/
float UL=0.80,LL=0.05;/* Setting the Limiters*/
int counter_toe_max = 0, counter_heel_max = 0,counter_toe_min = 0, counter_heel_min = 0;//counter for the number of H and T occured
int cal_limit = 10;/*time for which calibration should go on*/
int timer = 0;/*stores the time elapsed*/
void loop()
{
read_FSR();//Call The FSR function
//read_acc();
}
/*********************************************FSR_TOE***********************************************/
/*Function to read the FSR_TOE data and save to SD*/
void read_FSR()
{
data_toe = analogRead(A0);
data_heel = analogRead(A1);
timer = millis() / 1000;
Serial.print(millis());
Serial.print(" ");
Serial.print(data_toe);
Serial.print(" ");
Serial.println(data_heel);
/*Calibration and finding the maxima uptil cal_limit seconds.*/
if (timer < cal_limit)
{
/*TOE calibration*/
/*To find the top 5 max pressures*/
if (data_toe > toe_max[counter_toe_max])
{
toe_max[counter_toe_max] =data_toe;
counter_toe_max = counter_toe_max + 1;
}
if (counter_toe_max >= 5)
{
counter_toe_max = 0;
}
/*To find the top 5 min pressures*/
if (data_toe < toe_max[counter_toe_min])
{
toe_min[counter_toe_min] = data_toe;
counter_toe_min = counter_toe_min + 1;
}
if (counter_toe_min >= 5)
{
counter_toe_min = 0;
}
/*HEEL FSR calibration*/
/*To find the top 5 max pressures*/
if (data_heel > heel_max[counter_heel_max])
{
heel_max[counter_heel_max] =data_heel;
counter_heel_max = counter_heel_max + 1;
}
if (counter_heel_max >= 5)
{
counter_heel_max = 0;
}
/*To find the top 5 min pressures*/
if (data_heel < heel_min[counter_heel_min])
{
heel_min[counter_heel_min]=data_heel; =
counter_heel_min = counter_heel_min + 1;
}
if (counter_heel_min >= 5)
{
counter_heel_min = 0;
}
}
/*Displaying the maximum and minimum valus array and finding the averages for both the FSR's*/
if (timer == cal_limit && temp == 0)
{
/*Finding sum of the array elements*/
for (int i = 0; i < 5; i++)
{
sum_toe_max = sum_toe_max + toe_max[i];
sum_toe_min = sum_toe_min + toe_min[i];
}
for (int i = 0; i < 5; i++)
{
sum_heel_max = sum_heel_max + heel_max[i];
sum_heel_min = sum_heel_min + heel_min[i];
}
avg_toe_max = sum_toe_max / 5;/*dividing by 5 to get the avg of the 5 values*/
avg_toe_min = sum_toe_min / 5;
avg_heel_max = sum_heel_max / 5;
avg_heel_min = sum_heel_min / 5;
diff_toe = avg_toe_max-avg_toe_min;/*difference between maximas and minimas*/
diff_heel = avg_heel_max-avg_heel_min ;
Serial.println();
Serial.print(F("Avg ToePress max "));
Serial.println(avg_toe_max);
Serial.print(F("Avg ToePress min "));
Serial.println(avg_toe_min);
Serial.print(F("Avg HeelPress max "));
Serial.println(avg_heel_max);
Serial.print(F("Avg HeelPress min "));
Serial.println(avg_heel_min);
Serial.print(F("Diff in avg toe press:"));
Serial.println(diff_toe);
Serial.print(F("Diff in avg heel press:"));
Serial.println(diff_heel);
Serial.print(F("Target HeelPress "));
Serial.println(UL*(avg_heel_max-avg_heel_min));
Serial.print(F("Target ToePress "));
Serial.println(LL*(avg_toe_max-avg_toe_min));
temp = temp + 1;
}
/*Done with calibration( when timer =10s)*/
/*Checking the oncoming data for a condition of Toe Off
Consider it as a toe off if the normalised value of data_toe i.e (data_toe-avg_toe_min)/diff_toe
at the previous instant is greater than LL(Lower Limit) i.e 0.2 times the differnce between the averages of max and min of toe FSR
and the normalised value of data_toe2 at the current instant is lesser than the same*/
if (timer > cal_limit && (data_toe-avg_toe_min)/diff_toe > LL)
{
data_toe2 = analogRead(A0);/*Data toe at the current instant*/
if ((data_toe2-avg_toe_min)/diff_toe < LL)
{
//
Serial.print(timer*1000);
Serial.print(" ");
Serial.print(("f t T "));
Serial.print(data_toe);
Serial.print("Avg min ");
Serial.print(avg_toe_min);
Serial.print("Diff ");
Serial.print(diff_toe);
Serial.println(" TOE");
}
}
/*Checking the oncoming data for a condition of Heel Stike
Consider it as a Heel Strike if the normalised value of data_heel i.e (data_heel2-avg_heel_max)/diff_heel
at the previous instant is lesser than UL(Lower Limit) i.e 0.8 times the differnce between the averages of max and min of heel FSR
and the normalised value of data_heel2 at the current instant is greater than the same*/
if(timer>cal_limit && (data_heel-avg_heel_min)/diff_heel<=UL)
{
data_heel2=analogRead(A1);/*Data heel at the current instant*/
if((data_heel2-avg_heel_min)/diff_heel>=UL)
{
Serial.print(timer*1000);
Serial.print(" ");
Serial.print(("f t H "));
Serial.print(data_heel);
Serial.print(" HEEL");
Serial.println(UL);
Serial.flush();
}
}
}
You define String arr[2][2]={{""}}; but access it later with arr[SD_savr][3]="TO";, arr[SD_savr][4]=Y[0]; and arr[SD_savr][3]="HS";, which is out of bounds and causes undefined behavior, which is the possible cause of your resets.
As you removed SD usage, could you also remove the #include
Does that influence your memory requirements? ( Or even the bad behaviour ? )
Freezing instead of Reset is usually the same cause, just hitting some other address. ;)
I cannot not see any array out of bounds issue with the current code, but that's where I'd double/triple check...
Other questions:
I2C (Wire): you request 14 bytes, but read only 2 of them ? ...
start is a float ? dt should be 0.0, I guess

Using a distance sensor in Processing to control the attributes of shapes

I'm trying to make a program that will use the readings it gets from a distance sensor to control the attributes of circles (size, xy and colour). To do this I'm trying to make it record the current value and apply that to the value when you press the relevant key (Eg. press 's' and it changes the size to whatever the distance was at that point). - Ideally I'd like the circle to change whatever field is next dynamically as you move your hand over the sensor, but that seems a bit beyond me.
I've tried to do as much as I can, but everything I'm not sure of I've commented out. Any tips or advice? I'm really not sure what I'm doing when it comes to classes and constructors.
EDIT: When I run the code, nothing happens.
import processing.serial.*;
int xpos, ypos, s, r, g, b;
Circle circle;
int shapeSize, distance;
String comPortString;
Serial myPort;
void setup(){
size(displayWidth,displayHeight); //Use entire screen size.
//Open the serial port for communication with the Arduino
myPort = new Serial(this, "/dev/cu.usbmodem1411", 9600);
myPort.bufferUntil('\n'); // Trigger a SerialEvent on new line
}
void draw(){
background(0);
delay(50); //Delay used to refresh screen
println(distance);
}
void serialEvent(Serial cPort){
comPortString = (new String(cPort.readBytesUntil('\n')));
if(comPortString != null) {
comPortString=trim(comPortString);
/* Use the distance received by the Arduino to modify the y position
of the first square (others will follow). Should match the
code settings on the Arduino. In this case 200 is the maximum
distance expected. The distance is then mapped to a value
between 1 and the height of your screen */
distance = int(map(Integer.parseInt(comPortString),1,200,1,height));
if(distance<0){
/*If computer receives a negative number (-1), then the
sensor is reporting an "out of range" error. Convert all
of these to a distance of 0. */
distance = 0;
}
}
}
void keyPressed()
{
// N for new circle (and keep old one)
if((key == 'N') || (key == 'n')) {
println("n");
circle = new Circle(1,1,1,1,1,1);
}
//r - change red
if((key == 'R') || (key == 'r')) {
float red = map(distance, 0, 700, 0, 255);
r = int(red);
println("r " + r);
}
//g - change green
if((key == 'G') || (key == 'g')) {
float green = map(distance, 0, 700, 0, 255);
g = int(green);
println("g " + g);
}
//b - change blue
if((key == 'B') || (key == 'b')) {
float blue = map(distance, 0, 700, 0, 255);
b = int(blue);
println("b " + b);
}
//S - change Size
if((key == 'S') || (key == 's')) {
s = distance;
println("s " + s);
}
//X - change x pos
if((key == 'X') || (key == 'x')) {
xpos = distance;
println("x " + xpos);
}
//y - change y pos
if((key == 'Y') || (key == 'y')) {
ypos = distance;
println("y " + ypos);
}
}
class Circle {
Circle(int xpos, int ypos, int s, int r, int g, int b){
ellipse(xpos, ypos, s, s);
color(r, g, b);
}
int getX(){
return xpos;
}
int getY(){
return ypos;
}
}
I would split this into steps/tasks:
Connecting to the Arduino
Reading values from Arduino
Mapping read values
Controlling mapping
You've got the Arduino part pretty much there, but things look messy when trying to map read values to the circle on screen.
For now, for simplicity reasons, let's ignore classes and focus on simply drawing a single ellipse with x,y,size,r,g,b properties.
To get read of jitter you should update the property ellipse continuously, not just when pressing a key. On the key event you should simply change what property gets updated.
You could use extra variables to keep track of what ellipse properties you're updating.
Here's a refactored version of the code based on the points above:
import processing.serial.*;
int xpos,ypos,s,r,g,b;
int distance;
int propertyID = 0;//keep track of what property should be updated on distance
int PROP_XPOS = 0;
int PROP_YPOS = 1;
int PROP_S = 2;
int PROP_R = 3;
int PROP_G = 4;
int PROP_B = 5;
void setup(){
size(400,400);
//setup some defaults to see something on screen
xpos = ypos = 200;
s = 20;
r = g = b = 127;
//initialize arduino - search for port based on OSX name
String[] portNames = Serial.list();
for(int i = 0 ; i < portNames.length; i++){
if(portNames[i].contains("usbmodem")){
try{
Serial arduino = new Serial(this,portNames[i],9600);
arduino.bufferUntil('\n');
return;
}catch(Exception e){
showSerialError();
}
}
}
showSerialError();
}
void showSerialError(){
System.err.println("Error connecting to Arduino!\nPlease check the USB port");
}
void draw(){
background(0);
fill(r,g,b);
ellipse(xpos,ypos,s,s);
}
void serialEvent(Serial arduino){
String rawString = arduino.readString();//fetch raw string
if(rawString != null){
String trimmedString = rawString.trim();//trim the raw string
int rawDistance = int(trimmedString);//convert to integer
distance = (int)map(rawDistance,1,200,1,height);
updatePropsOnDistance();//continously update circle properties
}
}
void updatePropsOnDistance(){
if(propertyID == PROP_XPOS) xpos = distance;
if(propertyID == PROP_YPOS) ypos = distance;
if(propertyID == PROP_S) s = distance;
if(propertyID == PROP_R) r = distance;
if(propertyID == PROP_G) g = distance;
if(propertyID == PROP_B) b = distance;
}
void keyReleased(){//only change what proprty changes on key press
if(key == 'x' || key == 'X') propertyID = PROP_XPOS;
if(key == 'y' || key == 'Y') propertyID = PROP_YPOS;
if(key == 's' || key == 'S') propertyID = PROP_S;
if(key == 'r' || key == 'R') propertyID = PROP_R;
if(key == 'g' || key == 'G') propertyID = PROP_G;
if(key == 'b' || key == 'B') propertyID = PROP_B;
}
//usually a good idea to test - in this case use mouseY instead of distance sensor
void mouseDragged(){
distance = mouseY;
updatePropsOnDistance();
}
If this makes sense, it can easily be encapsulated in a class.
We could use an array to store those properties, but if something like props[0] for x, props1 for y, etc. is harder to read, you could use an IntDict which allows you to index values based on a String instead of a value (so you can do props["x"] instead of props[0]).
Here's an encapsulated version of the code:
import processing.serial.*;
Circle circle = new Circle();
void setup(){
size(400,400);
//initialize arduino - search for port based on OSX name
String[] portNames = Serial.list();
for(int i = 0 ; i < portNames.length; i++){
if(portNames[i].contains("usbmodem")){
try{
Serial arduino = new Serial(this,portNames[i],9600);
arduino.bufferUntil('\n');
return;
}catch(Exception e){
showSerialError();
}
}
}
showSerialError();
}
void showSerialError(){
System.err.println("Error connecting to Arduino!\nPlease check the USB port");
}
void draw(){
background(0);
circle.draw();
}
void serialEvent(Serial arduino){
String rawString = arduino.readString();
if(rawString != null){
String trimmedString = rawString.trim();
int rawDistance = int(trimmedString);
int distance = (int)map(rawDistance,1,200,1,height);
circle.update(distance);
}
}
void keyReleased(){
circle.setUpdateProperty(key+"");//update the circle property based on what key gets pressed. the +"" is a quick way to make a String from the char
}
//usually a good idea to test - in this case use mouseY instead of distance sensor
void mouseDragged(){
circle.update(mouseY);
}
class Circle{
//an IntDict (integer dictionary) is an associative array where instead of accessing values by an integer index (e.g. array[0]
//you access them by a String index (e.g. array["name"])
IntDict properties = new IntDict();
String updateProperty = "x";//property to update
Circle(){
//defaults
properties.set("x",200);
properties.set("y",200);
properties.set("s",20);
properties.set("r",127);
properties.set("g",127);
properties.set("b",127);
}
void draw(){
fill(properties.get("r"),properties.get("g"),properties.get("b"));
ellipse(properties.get("x"),properties.get("y"),properties.get("s"),properties.get("s"));
}
void setUpdateProperty(String prop){
if(properties.hasKey(prop)) updateProperty = prop;
else{
println("circle does not contain property: " + prop+"\navailable properties:");
println(properties.keyArray());
}
}
void update(int value){
properties.set(updateProperty,value);
}
}
In both examples you can test the distance value by dragging your mouse on the Y axis.
Regarding the HC-SR04 sensor, you can find code on the Arduino Playground to get the distance in cm. I haven't used the sensor myself yet, but I notice other people has some issues with it, so it's worth checking this post as well. If you want to roll your own Arduino code, no problem, you can use the HC-SR04 datasheet(pdf link) to get the formula:
Formula: uS / 58 = centimeters or uS / 148 =inch; or: the range = high
level time * velocity (340M/S) / 2; we suggest to use over 60ms
measurement cycle, in order to prevent trigger signal to the echo
signal.
It's important to get accurate values (you'll avoid jitter when using these to draw in Processing). Additionally you can use easing or a moving average.
Here's a basic moving average example:
int historySize = 25;//remember a number of past values
int[] x = new int[historySize];
int[] y = new int[historySize];
void setup(){
size(400,400);
background(255);
noFill();
}
void draw(){
//draw original trails in red
stroke(192,0,0,127);
ellipse(mouseX,mouseY,10,10);
//compute moving average
float avgX = average(x,mouseX);
float avgY = average(y,mouseY);
//draw moving average in green
stroke(0,192,0,127);
ellipse(avgX,avgY,10,10);
}
void mouseReleased(){
background(255);
}
float average(int[] values,int newValue){
//shift elements by 1, from the last to the 2nd: count backwards
float total = 0;
int size = values.length;
for(int i = size-1; i > 0; i--){//count backwards
values[i] = values[i-1];//copy previous value into current
total += values[i];//add values to total
}
values[0] = newValue;//add the newest value at the start of the list
total += values[0];//add the latest value to the total
return (float)total/size;//return the average
}

RGB Serial Issue

I am trying to make a Arduino program where it receives signals from the Serial monitor and then lights LED's accordingly, i have it set up with RGB. But I have a problem where all three LED's light like the blue one only should. here is my code:
#define SENSOR 0
#define R_LED 11
#define G_LED 10
#define B_LED 9
#define BUTTON 12
int val = 0;
int times = 0;
int btn = LOW;
int old_btn = LOW;
int state = 0;
int r = 0;
int g = 0;
int b = 0;
byte inByte = 0;
char buffer[5];
void setup() {
Serial.begin(9600);
pinMode(BUTTON, INPUT);
}
void loop() {
val = analogRead(SENSOR);
Serial.println(val);
if (Serial.available() > 0) {
inByte = Serial.read();
if (inByte == '#') {
r = Serial.read() + 1;
r = r * 25;
g = Serial.read() + 1;
g = g * 25;
b = Serial.read() + 1;
b = b * 25;
}
}
btn = digitalRead(BUTTON);
if ((btn == HIGH) && (old_btn == LOW)){
state = 1 - state;
}
old_btn = btn;
if (state == 1){
analogWrite(R_LED, r);
analogWrite(G_LED, g);
analogWrite(B_LED, b);
}else{
analogWrite(R_LED, 0);
analogWrite(G_LED, 0);
analogWrite(B_LED, 0);
}
delay(100);
}
Note: I am sure it is a coding issue, not a mechanical one,for your information.
If I understand what you're doing correctly, some code such as #987 will be sent on the serial monitor every time you want the color to change, correct? In that case, the issue is that when you do r = Serial.read() + 1; (and the same goes for b and g), Serial.read() is returning the ASCII code for a character from '0' through '9' (48 - 57). Try this:
r = Serial.read() - '0' + 1;
r = r * 25;
g = Serial.read() - '0' + 1;
g = g * 25;
b = Serial.read() - '0' + 1;
b = b * 25;
This will subtract the ASCII code for '0' first, so the numbers will be in the proper 0-9 range.
In your code, you're doing the identical thing to all three lights.
Why would you expect blue to behave differently?
analogWrite(R_LED, r);
analogWrite(G_LED, g);
analogWrite(B_LED, b);

Resources