PWM Slider and Processing

Hi all

I am new to Processing, and am trying to create a simple PWM slider interface. I found a library that contains the slider that I need, and want to send the data to my arduino to control PWM on an LED. The problem is, is that the PWM data seems to be acting as a digital command, even though I use analogWrite(). The LED is off when I move the slider up to 127, until it reaches 128, where the LED turns on. So really, the slider only has two commands, when it should have 255.

This is perplexing to me, and I've tried many things, to no avail.

thanks

Processing Code:

import controlP5.*;
import processing.serial.*;

ControlP5 controlP5;

Serial arduino;
PFont myriad;

int Speed = 0;

void setup() 
{
  size(400, 400);
  myriad = loadFont("MyriadPro-Regular-25.vlw");
  textFont(myriad, 25);
  
  String portName = Serial.list()[0];
  arduino = new Serial(this, portName, 9600);
  
  controlP5 = new ControlP5(this);
  controlP5.addSlider("Speed", 0, 255, 0, 50, 125, 255, 12);
}

void draw() 
{
  background(150, 0, 0);
  fill(0, 0, 150);
  text(Speed, 25, 50);
  arduino.write(Speed);
}

Arduino Code:

int incomingData;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available())
  {
    incomingData = Serial.read();
    analogWrite(A0, incomingData);
  }
}

You probably have to convert your incoming stream of characters into numbers that analogWrite can use properly.

The arduino.write() statement wrote out the value in binary, not as a string of characters. No conversion of the data is required on the Arduino side.

So either on the Processing side, or on the Arduino side, you must convert your silder value into a single 8-bit byte.

That's already being done...

The problem is on the Arduino side. The alias A0 refers to the analog pin 0 being used as a digital pin. The analog pins do not support PWM. So, expecting an LED connected to an analog pin to vary in brightness is not a reasonable expectation.

Thanks — it works perfectly. I just used a PWM digital pin.

Just so that I don't start a whole new thread, I'll ask my question on here.

I'm trying to set up a Processing interface for my serial controlled RC car. I've (tried) to base the code off of the SimpleWrite example in Processing. When I run the program, I get no response at all from my arduino. Maybe it's a loop problem?

Processing

import controlP5.*;
import processing.serial.*;

ControlP5 controlP5;

Serial arduino;
PFont myriad;

int Speed = 0;
char function;

void setup() 
{
  size(400, 400);
  myriad = loadFont("MyriadPro-Regular-25.vlw");
  textFont(myriad, 25);
  
  String portName = Serial.list()[0];
  arduino = new Serial(this, portName, 9600);
  
  controlP5 = new ControlP5(this);
  controlP5.addSlider("Speed", 0, 255, 0, 50, 25, 255, 12);
}

void draw() 
{
  background(150, 0, 0);
  fill(0, 0, 150);
  text(Speed, 5, 40);
  //arduino.write(function + Speed);
  
  if(mouseOverForward() == true)
  {
    fill(0, 0, 255);
    function = 'f';
    arduino.write(function + Speed);
  }
  
  else
  {
    fill(0, 0, 150);
    function = 'e';
    arduino.write(function + Speed);
  }

  rect(150, 75, 100, 100);
  
  if(mouseOverReverse() == true)
  {
    fill(0, 0, 255);
    function = 'r';
    arduino.write(function + Speed);
  }
  
  else
  {
    fill(0, 0, 150);
    function = 'e';
    arduino.write(function + Speed);
  }
  
  rect(150, 200, 100, 100);
  
  if(mouseOverRight() == true)
  {
    fill(0, 0, 255);
    function = 'a';
    arduino.write(function + Speed);
  }
  
  else
  {
    fill(0, 0, 150);
    function = 'e';
    arduino.write(function + Speed);
  }
  
  rect(275, 150, 40, 80);
  
  if(mouseOverLeft() == true)
  {
    fill(0, 0, 255);
    function = 'b';
    arduino.write(function + Speed);
  }
  
  else
  {
    fill(0, 0, 150);
    function = 'e';
    arduino.write(function + Speed);
  }
  
  rect(85, 150, 40, 80);

  if((mousePressed == true) && (mouseX >= 25) && (mouseX <= 75) && (mouseY >= 325) && 
  (mouseY <= 375))
  {
    fill(0, 0, 255);
    function = 'c';
    arduino.write(function + Speed);
  }
  
  else
  {
    fill(0, 0, 150);
    function = 'e';
    arduino.write(function + Speed);
  }
  
  rect(25, 325, 50, 50);
  
  if((mousePressed == true) && (mouseX >= 90) && (mouseX <= 140) && (mouseY >= 325) &&
  (mouseY <= 375))
  {
    fill(0, 0, 255);
    function = 'd';
    arduino.write(function + Speed);
  }
  
  else
  {
    fill(0, 0, 150);
    function = 'e';
    arduino.write(function + Speed);
  }
  
  rect(90, 325, 50, 50);
}

boolean mouseOverForward() 
{
  return ((mouseX >= 150) && (mouseX <= 250) && (mouseY >= 75) && (mouseY <= 175));
}


boolean mouseOverReverse()
{
  return ((mouseX >= 150) && (mouseX <= 250) && (mouseY >= 200) && (mouseY <= 300));
}

boolean mouseOverRight()
{
  return ((mouseX >= 275) && (mouseX <= 315) && (mouseY >= 150) && (mouseY <= 230));
}

boolean mouseOverLeft()
{
  return ((mouseX >= 85) && (mouseX <= 125) && (mouseY >= 150) && (mouseY <= 230));
}

Arduino

#include <AFMotor.h>

String readString, function, mspeed;

AF_DCMotor motor1(1);
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);

const int rightLEDs = 9;
const int leftLEDs = 10;
const int buttonPin = 2;
const int buzzerPin = A0;

int buttonState = 0;
int ledState = HIGH;

void setup() 
{
  pinMode(rightLEDs, OUTPUT);
  pinMode(leftLEDs, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  digitalWrite(rightLEDs, HIGH);
  digitalWrite(leftLEDs, HIGH);
  Serial.begin(9600);
}

void loop() 
{
  while (Serial.available()) 
  {
    delay(1);  
    if (Serial.available() > 0) 
    {
      char c = Serial.read();
      readString += c;
    } 
  }

  if(readString.length() > 0) 
  {
    function = readString.substring(0, 1); 
    mspeed = readString.substring(1, 4);     


    if(function == 'f') function = "FORWARD";
    if(function == 'r') function = "REVERSE";
    if(function == 'a') function = "RIGHT_TURN";
    if(function == 'b') function = "LEFT_TURN";
    if(function == 'c') function = "HEADLIGHTS";
    if(function == 'd') function = "HORN";
    if(function == 'e') function = "RELEASE";

    word newSpeed;

    char carray1[9]; 
    mspeed.toCharArray(carray1, sizeof(carray1));
    newSpeed = atoi(carray1);

    buttonState = digitalRead(buttonPin);
    if(buttonState == LOW)
    {
      if(function == "FORWARD")
      {
        motor1.setSpeed(newSpeed);
        motor2.setSpeed(newSpeed);
        motor3.setSpeed(newSpeed);
        motor4.setSpeed(newSpeed);

        motor1.run(FORWARD);
        motor2.run(FORWARD);
        motor3.run(FORWARD);
        motor4.run(FORWARD);
      }
      
      if(function == "REVERSE")
      {
        motor1.setSpeed(newSpeed);
        motor2.setSpeed(newSpeed);
        motor3.setSpeed(newSpeed);
        motor4.setSpeed(newSpeed);

        motor1.run(BACKWARD);
        motor2.run(BACKWARD);
        motor3.run(BACKWARD);
        motor4.run(BACKWARD);
      }
      
      if(function == "RIGHT_TURN")
      {
        motor1.setSpeed(newSpeed);
        motor2.setSpeed(newSpeed);
        motor3.setSpeed(newSpeed);
        motor4.setSpeed(newSpeed);

        motor1.run(FORWARD);
        motor2.run(FORWARD);
        motor3.run(BACKWARD);
        motor4.run(BACKWARD);
      }
      
      if(function == "LEFT_TURN")
      {
        motor1.setSpeed(newSpeed);
        motor2.setSpeed(newSpeed);
        motor3.setSpeed(newSpeed);
        motor4.setSpeed(newSpeed);

        motor1.run(BACKWARD);
        motor2.run(BACKWARD);
        motor3.run(FORWARD);
        motor4.run(FORWARD);
      }
      
      if(function == "HEADLIGHTS")
      {
        ledState = !ledState;
        digitalWrite(rightLEDs, ledState);
        digitalWrite(leftLEDs, ledState);
      }
      
      if(function == "HORN")
      {
        analogWrite(buzzerPin, 255);
      }
      
      if(function == "RELEASE");
      {
        motor1.run(RELEASE);
        motor2.run(RELEASE);
        motor3.run(RELEASE);
        motor4.run(RELEASE);
      }
    }
  }
}
    arduino.write(function + Speed);

What do you think this is doing? If you think that it is going to write two bytes, 'f' and Speed, to the serial port, I'm afraid you are wrong. It just added 'f' and Speed and wrote ONE value to the serial port.

Two bytes == two writes.

I'm trying to write one byte. Look at the Arduino program. I think it's a problem with the Arduino reading it.

Has anyone done something like this before, or maybe it can't be done.

Of course it can be done. What you are asking the Processing application to do is to add 'f'' and whatever value is in speed, and write those out as a single byte.

Then, you are expecting, in the Arduino sketch, to get a string of characters.

If you don't send a string, using the print() method in Processing, you can't expect to read a string on the Arduino.

Sending a string, and reading it the way you are is going to be an exercise in frustration.

Serial data transmission is SLOW. The delay() in reading the data is stupid. You need to make Processing send an end of packet marker, and you need to make the Arduino read all available serial data, up to the end-of packet marker.

If, on any given pass through loop, there is serial data, but no end-of-packet marker, just append the data to the string. If the end of packet marker is present, break out of the while loop. Then, test whether the last character read is the end of packet marker. If it is, you can use the data that was read. Then, reset the string to an empty string.

Note that there will not always be three characters in the value. A value between 100 and 180 will have 3 characters. But, a value from 10 to 99 will only have 2. A value from 0 to 9 will only have 1.

Is there any way to make the speed variable constantly a three character variable? I.E. if speed = 30, it would send 030?

I was also just looking at the example you posted when I was sending commands from the Serial Monitor. It looks like it would work, but it doesn't address the way I want to break up the string. How would I take two parts of the string?

char inData[10];
byte index = 0;
char EOP = ';';

void loop()
{
  while(Serial.available() > 0)
  {
     char inByte = Serial.read();
     if(index < 10)
     {
        inData[index] = inByte;
        inData[index+1] = '\0';
     }
  }

  if(inData[index] == EOP)
  {
    // Parse and use the data
    if(strcmp(inData, "on")
        // Do whatever on means
    else if(strcmp(inData, "off")
        // Do whatever off means

    inData[0] = '\0';
    index = 0;
  }
}

Is there any way to make the speed variable constantly a three character variable? I.E. if speed = 30, it would send 030?

Probably, but sending 2;, 30;, or 120; is so much easier.

It looks like it would work, but it doesn't address the way I want to break up the string. How would I take two parts of the string?

The code you have will not stop reading from the serial port when the EOP character arrives. So, testing that the last character read is EOP is not a guarantee that the received data does not contain an embedded EOP character. Try this, instead:

bool ended;

void loop()
{
  ended = false;
  while(Serial.available() > 0)
  {
     char inByte = Serial.read();
     if(inByte == EOP)
     {
        ended = true;
        break;
     }
     else
     {
       if(index < 10)
       {
          inData[index] = inByte;
          inData[index+1] = '\0';
       }
     }
  }

  if(ended)
  {
     // Parse the data
  }
}

As for parsing the data, what you have won't work. You are trying to compare all the data received to "on" or "off". The strtok() function takes a NULL-terminated array of characters, like inData, (or NULL - more about that in a minute) and a collection of delimiters, and returns a pointer to a string (NULL-terminated array of characters) that is delimited by one of the delimiters.

For example, if inData contains "on 125", and this code is executed:

char *token = strtok(inData, " ");

token will point to "on", which strcmp() will be happy to evaluate.

If strtok() is called with a NULL as the first argument, it keeps parsing the last string, so

token = strtok(NULL, " ");

will result in token pointing to "125", which, coincidentally, atoi() will happily convert to a number.

For more help, you need to describe what you are sending to the Arduino that you need it to parse.

What I'm trying to do is have a processing interface where I have 4 arrows for forward, reverse, right, and left. I want it to continuously send. If my mouse is over forward, I want it to move forward at the speed that the slider is set to. An end of string marker may not be good if it is continuously reading.

If my mouse is over forward, I want it to move forward at the speed that the slider is set to.
An end of string marker may not be good if it is continuously reading.

When the mouse is moved over "forward", the Processing app will send ONE command to move forward at some speed, followed by an end of packet marker.

When the mouse is moved off "forward", the Processing app will send ONE command to stop, followed by an end of packet marker.

An end of packet marker is necessary. There will be no "continuously reading" going on.

Now, if you mean that you have a "scroll bar" defined as "forward", then there should be a value changed callback. When that callback is invoked, it should send ONE command to move forward at some speed, followed by an end of packet marker.

But, regardless of how the form is defined, there need not be any "continuously reading" going on.

For the "Horn" function, use tone() instead of analogWrite. http://www.arduino.cc/en/Reference/Tone