Robot Car - I want to press the button and not hold it

Hello, (my second topic here) I'm currently working on my first project, the SMARS Robot Car by Kevin Thomas. I' m a beginner and therefore do not have much experience and knowledge of programming. However, I wrote the sketch myself and it works. I am currently optimizing my project and have decided on the following:

  • Instead of holding Triangle, Circle, Cross and Square to execute the code, I only want to press whatever I want once (for example: if I press Triangle, obstacleavoidance should be executed permanently).

  • I still want to be able to switch between the actions after pressing another button (for example circle for followingbob) once.

  • I would like to be able to either override the actions manually or, if this is not possible, end them with Select and again be able to control it manually.

I have already tried it with a while(true) loop and ButtonPressed, but it doesn't work. I keep trying to think of new possibilities, but I think I need expert help. Unfortunately I could not find anything similar in the forum.

Here is my Sketch:

#include <PS2X_lib.h>
#include <AFMotor.h>

#define PS2_DAT 9   // data
#define PS2_CMD 10  // command
#define PS2_SEL 2   // attention
#define PS2_CLK 13  // clock

PS2X ps2x;  // create PS2 Controller Class

int error = 0;  // for controller-connenction
byte type = 0;  // for controller-type

AF_DCMotor lmotor(1);  // left motor
AF_DCMotor rmotor(2);  // right motor

int echo = A1;     // echo pin connected to A1
int trigger = A2;  // trig pin connected to A2

long duration;        // variable for ultrasonic-sensor
int theDistance = 0;  // variable for ultrasonic-sensor

int keepDistance = 8;  // variable for ultrasonic-sensor

int infrared = A0;  // variable for infrared-sensor


//-------------------------------------------------- SETUP
void setup() {

  Serial.begin(9600);
  delay(400);  // time to startup, before configuring it

  error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT);  // setup pins for PS2 Controller

  if (error == 0) {  // check for errors
    Serial.print("PS2 Controller successfully found and configured, B.O.B. is waiting :) -> ");
  } else {
    Serial.print("No PS2 Controller found, try again ");
    setup();
  }

  type = ps2x.readType();  // read type of Controller
  switch (type) {
    case 0:
      Serial.print("Unknown Controller type found ");
      break;
    case 1:
      Serial.print("DualShock Controller found ");
      break;
  }

  lmotor.setSpeed(200);  // left motor speed 200
  rmotor.setSpeed(200);  // right motor speed 200
  lmotor.run(RELEASE);   // release left motor
  rmotor.run(RELEASE);   // release right motor

  pinMode(echo, INPUT);      // echo as input
  pinMode(trigger, OUTPUT);  // trigger as output

  pinMode(infrared, INPUT);  // infrared as input
}


//-------------------------------------------------- LOOP
void loop() {

  if (error == !0)  // skip loop if no Controller found
    return;

  if (type == 1) {                  // DualShock Controller
    ps2x.read_gamepad();            // read Controller
    manualcontrol();                // use d-pad for manual control (already active)
    if (ps2x.Button(PSB_TRIANGLE))  // hold triangle to activate obstacle avoidance
      obstacleavoidance();
    if (ps2x.Button(PSB_CIRCLE))  // hold circle to activate following BOB
      followingbob();
    if (ps2x.Button(PSB_CROSS))  // hold cross to activate black-line driving
      blacklinedriving();
    if (ps2x.Button(PSB_SQUARE))  // hold square to activate avoid the black
      avoidtheblack();
    if (ps2x.ButtonPressed(PSB_START))  // press start to activate bobby-dance
      bobbydance();
  }
  delay(50);
}


//-------------------------------------------------- MANUAL CONTROL
void manualcontrol() {

  if (ps2x.Button(PSB_PAD_UP)) {  // move forward
    lmotor.run(FORWARD);
    rmotor.run(FORWARD);
  } else if (ps2x.Button(PSB_PAD_DOWN)) {  // move backward
    lmotor.run(BACKWARD);
    rmotor.run(BACKWARD);
  } else if (ps2x.Button(PSB_PAD_LEFT)) {  // turn left
    lmotor.run(BACKWARD);
    rmotor.run(FORWARD);
  } else if (ps2x.Button(PSB_PAD_RIGHT)) {  // turn right
    lmotor.run(FORWARD);
    rmotor.run(BACKWARD);
  } else {  // stop
    lmotor.run(RELEASE);
    rmotor.run(RELEASE);
  }
}


//-------------------------------------------------- OBSTACLE AVIODANCE
void obstacleavoidance() {

  theDistance = distance();     // store the measured distance
  Serial.println(theDistance);  // print the measured distance

  if (theDistance <= 12) {  // move backward and turn right if distance is less than 12cm
    lmotor.run(BACKWARD);
    rmotor.run(BACKWARD);
    delay(500);
    lmotor.run(FORWARD);
    rmotor.run(BACKWARD);
    delay(500);
  } else {  // otherwise move forward
    lmotor.run(FORWARD);
    rmotor.run(FORWARD);
  }
}


//-------------------------------------------------- FOLLOWING BOB
void followingbob() {

  theDistance = distance();     // store the measured distance
  Serial.println(theDistance);  // print the measured distance

  if (theDistance < keepDistance && theDistance >= 0) {  // move backward if the distance is less than 8cm
    lmotor.run(BACKWARD);
    rmotor.run(BACKWARD);
  }
  if (theDistance > (keepDistance + 3) && theDistance < (keepDistance + 20)) {  // move forward if the distance is more than 11cm
    lmotor.run(FORWARD);
    rmotor.run(FORWARD);
  }
  if (theDistance > (keepDistance + 20)) {  // turn right if the distance is more than 28cm
    lmotor.run(FORWARD);
    rmotor.run(BACKWARD);
  }
  if (theDistance >= keepDistance && theDistance <= (keepDistance + 3)) {  //stop if the distance is between 8cm and 11cm
    lmotor.run(RELEASE);
    rmotor.run(RELEASE);
  }
}


//-------------------------------------------------- IN ADDITION FOR OBSTACLE AVOIDANCE AND FOLLOWING BOB
int distance() {

  int echoTime;            // store the time for a ping to bounce off an object
  int calculatedDistance;  // store the calculated distance from the echo time

  digitalWrite(trigger, HIGH);  // ultrasonic pulse for 10ms
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);

  echoTime = pulseIn(echo, HIGH);  // time for the pulse to bounce back to the sensor

  calculatedDistance = echoTime / 2 / 29;  // calculate the distance of the reflected object (half the bounce time multiplied by the speed of sound)
  return calculatedDistance;               // send back the calculated distance
}


//-------------------------------------------------- BLACK-LINE DRIVING
void blacklinedriving() {

  int ifrstate = digitalRead(infrared);  // store the state of the infrared-sensor

  if (ifrstate == 1) {  // move forward if black line detected
    lmotor.run(BACKWARD);
    rmotor.run(BACKWARD);
  } else {  // turn right if not on a black line
    lmotor.run(FORWARD);
    rmotor.run(BACKWARD);
  }
}


//-------------------------------------------------- AVOID THE BLACK
void avoidtheblack() {

  int ifrstate = digitalRead(infrared);  // store the state of the infrared-sensor

  if (ifrstate == 1) {  // move backward and turn right if black line detected
    lmotor.run(FORWARD);
    rmotor.run(FORWARD);
    delay(500);
    lmotor.run(FORWARD);
    rmotor.run(BACKWARD);
    delay(500);
  } else {  // move forward if not on a black line
    lmotor.run(BACKWARD);
    rmotor.run(BACKWARD);
  }
}


//-------------------------------------------------- BOBBY-DANCE
void bobbydance() {

  lmotor.run(FORWARD);
  rmotor.run(FORWARD);
  delay(1000);
  lmotor.run(RELEASE);
  rmotor.run(RELEASE);
  delay(1000);
  lmotor.run(FORWARD);
  rmotor.run(FORWARD);
  delay(200);
  lmotor.run(BACKWARD);
  rmotor.run(BACKWARD);
  delay(200);
  lmotor.run(FORWARD);
  rmotor.run(FORWARD);
  delay(200);
  lmotor.run(BACKWARD);
  rmotor.run(BACKWARD);
  delay(200);
  lmotor.run(FORWARD);
  rmotor.run(FORWARD);
  delay(200);
  lmotor.run(BACKWARD);
  rmotor.run(BACKWARD);
  delay(200);
  lmotor.run(FORWARD);
  rmotor.run(FORWARD);
  delay(200);
  lmotor.run(BACKWARD);
  rmotor.run(BACKWARD);
  delay(1200);
  lmotor.run(RELEASE);
  rmotor.run(RELEASE);
  delay(200);
  lmotor.run(BACKWARD);
  rmotor.run(FORWARD);
  delay(2000);
  lmotor.run(FORWARD);
  rmotor.run(BACKWARD);
  delay(2000);
}

Thanks for helping! :smiley:

Dominik Bubak

You need to detect when the button becomes pressed rather than when it is pressed

Look at the StateChangeDetection example in the IDE. Having detected a button press, set a variable depending on which button was pressed and use that in switch/case to execute the code for the required mode

1 Like

As @UKHeliBob suggests, use button events (got pressed, for example) to change the mode of operation. Select the code based on the mode.

It may be obvious, but one mode is no activity. So you might need a stop button and mode.

One wrinkle you will discover is the bobbydance(), which function will not play nice as it uses delay() to go through a relatively lengthy set of activities during which time there'll be no response from any buttons.

So leave that as a defect for now; I think the others will work well called on the basis of the mode you are in.

When you get the other buttons and the modes they switch amongst working, if the bobbydanxe() flaw bothers you, there are ways to deal with that. Come back and say if it turns out to matter at all.

a7

1 Like

look this over

enum { Manual, Obstacle, Follow, Avoid, Black, Bobby };
int state;

void loop()
{
    if (error == !0)
        return;

    ps2x.read_gamepad();

    if (ps2x.Button(PSB_TRIANGLE))
        state = Obstacle;
    else if (ps2x.Button(PSB_CIRCLE))
        state = Follow;
    if (ps2x.Button(PSB_CROSS))
        state = Black;
    if (ps2x.Button(PSB_SQUARE))
        state = Avoid;
    if (ps2x.ButtonPressed(PSB_START))
        state = Bobby;

    switch (state) {
    case Obstacle:
        obstacleavoidance();
        break;

    case Follow:
        followingbob();
        break;

    case Black:
        blacklinedriving();
        break;

    case Avoid:
        avoidtheblack();
        break;

    case Bobby:
        bobbydance();
        break;

    default:
        manualcontrol();
        break;
    }
    delay(50);
}

see pg 39 for an explanation of enum in the C Programming Language

1 Like

Thank you very much, it worked! And I learned something new. I added Select to get out of the mode and be able to control my vehicle manually again. It is now exactly as I wanted it. Thanks!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.