Help! Please critique my code - processing and arduino sketch... (scroll down)

Hi all,

I've been using Arduino for about a week now. Bought a new Uno and Motorshield and never done anything with electronics before but I saw the possibilities and couldn't miss out on an opportunity to tinker!

I've recently hacked a cheap RC Car and, using the Arduino Motor Shield I have managed to scour the forums and code the forward, reverse and left, right functions on the car.

What I would now like to do is to control these functions from either W,A,S,D or D-buttons on my mac (eventually gearing up towards xbox/ps controllers akin to Blair's WiFly Mini).

I know this is a question that has been asked before many times, but for my particular example I couldn't find anything that was answered.

I've attached the code that I am using in Arduino:

Any help is greatly appreciated and over course - cited!

Cheers, Adam

  int valD = 0; // variable to store values from drive and steer motors
  int valS = 0;
  
  const int driveD = 12;
  const int steerD = 13;
  
  const int brakeD = 9;
  const int brakeS = 8;
  
  const int steerA = 11;
  const int motorA = 3;

void setup()
{
  
  Serial.begin(9600);
  
  pinMode(driveD,OUTPUT); // Drive Motor - HIGH = Forwards, LOW = BACKWARDS
  pinMode(steerD,OUTPUT); // Steer Motor - HIGH = Left, LOW = Right

  pinMode(brakeD,OUTPUT); // Setup Disable (Brake) the Drive Motor
  pinMode(brakeS,OUTPUT); // Setup Disable (Brake) the Steer Motor 
  
  digitalWrite(brakeD,HIGH); // Enables brake for Drive Motor
  
  digitalWrite(brakeS,HIGH); // Enables brake for Steer Motor
 
}

int left() //create left turn function
{
  // Perform Left Turn
  digitalWrite(brakeS,LOW); // Turn off steering brake
  digitalWrite(steerD,HIGH); // Set direction (Left)
  analogWrite(steerA,255); // Perform Turn  
  valS = analogRead(steerA); // get analog signal value in prep for sending to serial monitor
  Serial.println(valS); // print to serial monitor
  delay(1000);
  digitalWrite(brakeS,HIGH); // Stop turning
  delay(1000);
}

int reverse() // create reverse motion function
{
  //Perform Reverse Drive
  digitalWrite(brakeD, LOW); // Disable Motor Brakes
  digitalWrite(driveD,LOW); // Drive Backwards
  analogWrite(motorA,255); // Set low initial speed
  valD = analogRead(motorA); // get analog signal value in prep for sending to serial monitor
  Serial.println(valD); // print to serial monitor
  delay(1000);
  digitalWrite(brakeD,HIGH); // Stop driving
  delay(1000);
}

int right() // create right turn function
{
    // Perform Right Turn
  digitalWrite(brakeS,LOW); // Turn off steering brake
  digitalWrite(steerD,LOW); // Set direction (Right)
  analogWrite(steerA,255); // Perform Turn  
  valS = analogRead(steerA); // get analog signal value in prep for sending to serial monitor
  Serial.println(valS); // print to serial monitor
  delay(1000);
  digitalWrite(brakeS,HIGH); // Stop turning
  delay(1000);
}

int forward() // create forward motion function
{
    //Perform Forward Drive
  digitalWrite(brakeD, LOW); // Disable Motor Brakes
  digitalWrite(driveD,HIGH); // Drive Forwards
  analogWrite(motorA,255); // Set low initial speed
  valD = analogRead(motorA); // get analog signal value in prep for sending to serial monitor
  Serial.println(valD); // print to serial monitor
  delay(1000);
  digitalWrite(brakeD,HIGH); // Stop driving
  delay(1000);
}

void loop()
{  
  forward() ;
  right();
}

First thing to note is that you're going to have to get rid of the calls to "delay", or your car is going to be unresponsive.
I think the IDE has examples of Processing communications.

I've had a look in the examples in Arduino and Processing and can't find anything in there.

Thanks for the heads up re the delays. I left them in there to make sure everything was working properly originally.

OK I found the examples but I'm still having trouble porting it to what I want to do.

Any help out there?

Thanks

but I'm still having trouble porting it

What is "it", and what is the trouble you're having?

Have you looked in the Playground?

'it' is controlling my motors through the wasd keys, and the trouble I'm having has now been cut down by around 99%!!

I visited this Digitalduino: Arduino Controlled RC Car: Update site and managed to get his code working with my setup.

When I press the 'a' key, the wheels move left, 'w' and the rear wheels go forward, etc, etc.

::: However :::

The keyReleased function is working and I've put a println in there to make sure that is it functioning as expected, but I can't for the life in me get the motors to stop when the key is released.

Here is my code again, heavily modified from the original.

I'm pretty confident the problem is in the Arduino code. I've tried changing a few things that you can see commented out in the TriggerBtn method's else clause, but none of these have worked.

Interestingly when I uncomment the analogWrite(AlgPin,0); in the above, the reverse works slower than normal, as does moving left, but going forwards and right don't work.

All comments are very much welcome while I continue to try and figure this out. Perhaps a Domino's will help!

Processing:

import processing.serial.*;

Serial myPort;  // Create object from Serial class
int[] KeyArray = new int[4];
int PrtChose = 1; //number of the serial port, starts at 0

void setup() {
  size(200, 300);
  noStroke();

  print(Serial.list());

  String portName = Serial.list()[PrtChose];
  myPort = new Serial(this, portName, 57600);
}

void draw()
{

}

void keyPressed() //key pressed
{
  if (key == 'w') //fwd
  {
    KeyArray[0] = 1; //fwd key pressed down, set forward command
  }
  if (key == 's') //down
  {
    KeyArray[1] = 1;
  }
  if (key == 'd') //right
  {
    KeyArray[2] = 1;
  }
  if (key == 'a') //left
  {
    KeyArray[3] = 1;
  }

  writeMsg();
}

void keyReleased() //key released
{
  if (key == 'w') //fwd, fwd has been let up, so set stop fwd message
  {
    KeyArray[0] = 0; //no longer pressed
    println("Released");
  }
  if (key == 's') //down
  {
    KeyArray[1] = 0;
    println("Released");
  }
  if (key == 'd') //right
  {
    KeyArray[2] = 0;
    println("Released");
  }
  if (key == 'a') //left
  {
    KeyArray[3] = 0;
    println("Released");
  }

  writeMsg(); //send updated state over serial
}



void writeMsg()
{
  //so both fwd/back, lft/rght dont activate at same time
  if(KeyArray[0] == 1 && KeyArray[1] == 1)
  {
    KeyArray[0] = 0;
    KeyArray[1] = 0;
  }
  if(KeyArray[2] == 1 && KeyArray[3] == 1)
  {
    KeyArray[2] = 0;
    KeyArray[3] = 0;
  }
  //<0,0,0,0>   <fwd,bck,rght,Lft>
  myPort.write("<" + KeyArray[0] + "," + KeyArray[1] + "," + KeyArray[2] + "," + KeyArray[3] + ">"); //write to serial
  println("<" + KeyArray[0] + "," + KeyArray[1] + "," + KeyArray[2] + "," + KeyArray[3] + ">"); //display in console
}

Arduino:

int started = 0;
char inData[10];
int ended = 0;
char index = 0;
int final = 0;

const int driveD = 12;
const int steerD = 13;
  
const int brakeD = 9;
const int brakeS = 8;
  
const int steerA = 11;
const int driveA = 3;

boolean Fwd = 0;
boolean Bck = 0;
boolean Rght = 0;
boolean Lft = 0;

void setup()
{
  Serial.begin(57600);
}
void loop()
{
  GetBluData(); //input like: <0,0,0,0> then splits and writes values to F,B,R,L
  TriggerBtn(driveD,driveA,Fwd); //set digital pin 2 to value of Fwd ( HIGH or LOW)
  TriggerBtn(driveD,driveA,Bck);
  TriggerBtn(steerD,steerA,Rght);
  TriggerBtn(steerD,steerA,Lft);

}

void TriggerBtn(int PinNum, int AlgPin, boolean ButtonState)
{
  if(ButtonState)
  {
    digitalWrite(brakeD,LOW);
    digitalWrite(brakeS,LOW);
    if (Fwd == 1) // Going forwards
    {
      digitalWrite(PinNum, HIGH);
      analogWrite(AlgPin,255);
    }
    else if (Bck == 1) // Backwards
    {
     digitalWrite(PinNum, LOW);
     analogWrite(AlgPin,255);
    }
    else if (Lft == 1) // Left
    {
     digitalWrite(PinNum, HIGH);
     analogWrite(AlgPin,255);
   }
   else if (Rght == 1) // Right
   {
    digitalWrite(PinNum,LOW);
    analogWrite(AlgPin,255);
   }

  }
  else
  {
     //releases button connected to the pin 
    //analogWrite(AlgPin,0);  
    digitalWrite(brakeS, HIGH);
    digitalWrite(brakeD,HIGH);
    //pinMode(PinNum, INPUT);  // Release the button.
  }
}

void GetBluData()
{
  while(Serial.available() )
  {
  //finds < and >, the beginning and end of command
    char aChar = Serial.read();
    if(aChar == '<')
    {
      started = true;
      index = 0;
      inData[index] = '\0';
    }
    else if(aChar == '>')
    {
      ended = true;
    }

    else if(started)
    {
      inData[index] = aChar;
      index++;
      inData[index] = '\0';          
    }

    else if (aChar =='*')
    {
      final = true;
    }
  }


  if(started && ended)
  {
    const char*  strDelimiter = ",";

    char* p;
    //<0,0,0,0>

//splits to individual ints
    if ( p = strtok(inData, strDelimiter) )  
    {
      Fwd = atoi(p);
    }
    if ( p = strtok(NULL, strDelimiter) )  
    {
      Bck = atoi(p);
    }
    if ( p = strtok(NULL, strDelimiter) )  
    {
      Rght = atoi(p);
    }
    if ( p = strtok(NULL, strDelimiter) )  
    {
      Lft = atoi(p);
    }

    // Get ready for the next time
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';    
  }
}

Thanks again!

Not a bump, but is there anyone who can help?

In the keyPressed() event, there are 4 possible values in the KeyArray array. In the keyReleased() event, there are 4 possible values in the KeyArray array.

In the writeMsg() function, you only deal with 2 of the possible 8 combinations of values in the KeyArray array. Why?

That's only to handle the motors correctly if forwards and backwards or left and right are pressed together.

The real meat of what happens during the key events in the writemsg function is in the myPort.write where it sends out a value in the form of 1,0,0,0 or 0,1,0,0 etc for all the directions.

That make sense?

That make sense?

Yes. But, only you can see what appears in the Processing monitor. The Processing application sends < and >, causing the Arduino to set started and ended. But, the Arduino code then ignores started and ended, and processes the data that was read as though it was a full packet. Why?

void GetBluData()

What does this function NAME have to do with what the function does?

I noticed a few if your functions are declared like "int left()" but they don't seem to be returning anything so "void left()" would be more suitable. Im not sure how much of a performance difference (if any) this would make.

Thanks everyone for replying to these. I've actually taken my code back to the drawing board and tried working at it from the ground up.

There's another post going online any second 'cause I'm still struggling a little bit...