Problems with my 2WD Car

Hello everyone. As a school project I was tasked with creating a 2WD car powered by arduino and will use a controlling software on pc that connects them together using bluetooth (Specifically the HC-06 module). The tests were going great I was making sure the motors, software, connection were working properly but now when I try to move my car any other direction excluding straight my program crashes. This may be a result of poor programming on the Python side but I still wanted to ask here as I might have made some mistakes in the Arduino side aswell. I'm providing codes for both of them below:

#include <SoftwareSerial.h>
#include <QMC5883LCompass.h>

// For Modules
const int bluetoothRX = 7;
const int bluetoothTX = 6;
const int trigger = 5;
const int buzzer = 2;
const int echo = 4;

// For Motor A
const int MotorPinA = 12;
const int MotorSpeedPinA = 3;
const int MotorBrakePinA = 9;

// For Motor B
const int MotorPinB = 13;
const int MotorSpeedPinB = 11;
const int MotorBrakePinB = 8;

const int forward = HIGH;
const int reverse = LOW;

QMC5883LCompass compass;
SoftwareSerial bluetooth(bluetoothRX, bluetoothTX);

int baseHeading = 0;
bool isBaselineSet = false;
bool isMovingForward = false;
bool isMovingBackward = false;

void setup() {
  pinMode(MotorPinA, OUTPUT);
  pinMode(MotorSpeedPinA, OUTPUT);
  pinMode(MotorBrakePinA, OUTPUT);

  pinMode(MotorPinB, OUTPUT);
  pinMode(MotorSpeedPinB, OUTPUT);
  pinMode(MotorBrakePinB, OUTPUT);

  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  pinMode(buzzer, OUTPUT);

  compass.init();
  bluetooth.begin(9600);
}

void loop() {
  if (bluetooth.available()) {
    char receivedCommand = bluetooth.read();

    if (receivedCommand == 'w') {
      if (!isMovingForward) {
        compass.read();
        baseHeading = compass.getAzimuth();
        isBaselineSet = true;
        isMovingForward = true;
        isMovingBackward = false;
      }
      maintainDirection(forward);
    } else if (receivedCommand == 'a') {
      moveMotor('A', forward, 255);
      moveMotor('B', reverse, 255);
    } else if (receivedCommand == 's') {
      if (!isMovingBackward) {
        compass.read();
        baseHeading = compass.getAzimuth();
        isBaselineSet = true;
        isMovingBackward = true;
        isMovingForward = false;
      }
      maintainDirection(reverse);
    } else if (receivedCommand == 'd') {
      moveMotor('A', reverse, 255);
      moveMotor('B', forward, 255);
    } else if (receivedCommand == ' ') {
      moveMotor('A', reverse, 0);
      moveMotor('B', reverse, 0);
      isMovingForward = false;
      isMovingBackward = false;
      isBaselineSet = false;
    }
  }
}

void moveMotor(char motor, int dir, int speed) {
  int motorPin;
  int motorSpeedPin;

  if (motor == 'A') {
    motorPin = MotorPinA;
    motorSpeedPin = MotorSpeedPinA;
  } else if (motor == 'B') {
    motorPin = MotorPinB;
    motorSpeedPin = MotorSpeedPinB;
  }
  digitalWrite(motorPin, dir);        
  analogWrite(motorSpeedPin, speed);  
}

void maintainDirection(int direction) {
  if (isBaselineSet) {
    compass.read();
    int currentHeading = compass.getAzimuth();
    int error = currentHeading - baseHeading;

    if (error < -180) {
      error += 360;
    } else if (error > 180) {
      error -= 360;
    }

    int speedA = 255;
    int speedB = 255;

    if (error > 0) {
      if (direction == forward) {
        speedA = 255 - map(error, 0, 180, 0, 255);
      } else {
        speedB = 255 - map(error, 0, 180, 0, 255);
      }
    } else if (error < 0) {
      if (direction == forward) {
        speedB = 255 - map(-error, 0, 180, 0, 255);
      } else {
        speedA = 255 - map(-error, 0, 180, 0, 255);
      }
    }

    moveMotor('A', direction, speedA);
    moveMotor('B', direction, speedB);
  }
}

Python code which sends the signals of WASD through bluetooth:

import pygame
import serial


ser = serial.Serial("COM3", 9600, timeout= 5)


pygame.init()
pygame.font.init()
FONT = pygame.font.SysFont("Arial", 30)


WINDOW_SIZE = 800
window = pygame.display.set_mode((WINDOW_SIZE, WINDOW_SIZE))
pygame.display.set_caption('TOGG 1X Bluetooth Controller')


BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GRAY = (128, 128, 128)


SHAPE_SIZE = 250
ARROW_SIZE = 200
GAP_SIZE = 50


CENTER = WINDOW_SIZE // 2
CIRCLE_POS = (CENTER, CENTER)
UP_ARROW_POS = (CENTER, CENTER - SHAPE_SIZE // 2 - GAP_SIZE)
DOWN_ARROW_POS = (CENTER, CENTER + SHAPE_SIZE // 2 + GAP_SIZE)
LEFT_ARROW_POS = (CENTER - SHAPE_SIZE // 2 - GAP_SIZE, CENTER)
RIGHT_ARROW_POS = (CENTER + SHAPE_SIZE // 2 + GAP_SIZE, CENTER)


running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False


    keys = pygame.key.get_pressed()


    window.fill(GRAY)


    pygame.draw.circle(window, RED, CIRCLE_POS, SHAPE_SIZE // 2 + 5)


    pygame.draw.polygon(window, BLACK, [(UP_ARROW_POS[0], UP_ARROW_POS[1] - ARROW_SIZE),
                                        (UP_ARROW_POS[0] + ARROW_SIZE // 2, UP_ARROW_POS[1]),
                                        (UP_ARROW_POS[0] - ARROW_SIZE // 2, UP_ARROW_POS[1])])
    pygame.draw.polygon(window, BLACK, [(LEFT_ARROW_POS[0] - ARROW_SIZE, LEFT_ARROW_POS[1]),
                                        (LEFT_ARROW_POS[0], LEFT_ARROW_POS[1] + ARROW_SIZE // 2),
                                        (LEFT_ARROW_POS[0], LEFT_ARROW_POS[1] - ARROW_SIZE // 2)])
    pygame.draw.polygon(window, BLACK, [(DOWN_ARROW_POS[0], DOWN_ARROW_POS[1] + ARROW_SIZE),
                                        (DOWN_ARROW_POS[0] + ARROW_SIZE // 2, DOWN_ARROW_POS[1]),
                                        (DOWN_ARROW_POS[0] - ARROW_SIZE // 2, DOWN_ARROW_POS[1])])
    pygame.draw.polygon(window, BLACK, [(RIGHT_ARROW_POS[0] + ARROW_SIZE, RIGHT_ARROW_POS[1]),
                                        (RIGHT_ARROW_POS[0], RIGHT_ARROW_POS[1] + ARROW_SIZE // 2),
                                        (RIGHT_ARROW_POS[0], RIGHT_ARROW_POS[1] - ARROW_SIZE // 2)])
   
    text_surface = FONT.render('W', True, WHITE)
    window.blit(text_surface, (UP_ARROW_POS[0] - text_surface.get_width() // 2, UP_ARROW_POS[1] - 50))


    text_surface = FONT.render('A', True, WHITE)
    window.blit(text_surface, (LEFT_ARROW_POS[0] - 50, LEFT_ARROW_POS[1] - text_surface.get_height() // 2))


    text_surface = FONT.render('S', True, WHITE)
    window.blit(text_surface, (DOWN_ARROW_POS[0] - text_surface.get_width() // 2, DOWN_ARROW_POS[1] + 50))


    text_surface = FONT.render('D', True, WHITE)
    window.blit(text_surface, (RIGHT_ARROW_POS[0] + 50, RIGHT_ARROW_POS[1] - text_surface.get_height() // 2))


    text_surface = FONT.render('SPACE', True, WHITE)
    window.blit(text_surface, (CIRCLE_POS[0] - text_surface.get_width() // 2, CIRCLE_POS[1] - text_surface.get_height() // 2))


    if keys[pygame.K_w]:
        pygame.draw.polygon(window, WHITE, [(UP_ARROW_POS[0], UP_ARROW_POS[1] - ARROW_SIZE),
                                            (UP_ARROW_POS[0] + ARROW_SIZE // 2, UP_ARROW_POS[1]),
                                            (UP_ARROW_POS[0] - ARROW_SIZE // 2, UP_ARROW_POS[1])], 4)
        ser.write(b'w')


    if keys[pygame.K_a]:
        pygame.draw.polygon(window, WHITE, [(LEFT_ARROW_POS[0] - ARROW_SIZE, LEFT_ARROW_POS[1]),
                                            (LEFT_ARROW_POS[0], LEFT_ARROW_POS[1] + ARROW_SIZE // 2),
                                            (LEFT_ARROW_POS[0], LEFT_ARROW_POS[1] - ARROW_SIZE // 2)], 4)
        ser.write(b'a')


    if keys[pygame.K_s]:
        pygame.draw.polygon(window, WHITE, [(DOWN_ARROW_POS[0], DOWN_ARROW_POS[1] + ARROW_SIZE),
                                            (DOWN_ARROW_POS[0] + ARROW_SIZE // 2, DOWN_ARROW_POS[1]),
                                            (DOWN_ARROW_POS[0] - ARROW_SIZE // 2, DOWN_ARROW_POS[1])], 4)
        ser.write(b's')
       
    if keys[pygame.K_d]:
        pygame.draw.polygon(window, WHITE, [(RIGHT_ARROW_POS[0] + ARROW_SIZE, RIGHT_ARROW_POS[1]),
                                            (RIGHT_ARROW_POS[0], RIGHT_ARROW_POS[1] + ARROW_SIZE // 2),
                                            (RIGHT_ARROW_POS[0], RIGHT_ARROW_POS[1] - ARROW_SIZE // 2)], 4)
        ser.write(b'd')


    if keys[pygame.K_SPACE]:
        pygame.draw.circle(window, WHITE, CIRCLE_POS, SHAPE_SIZE // 2 + 5, 4)
        ser.write(b' ')


    if keys[pygame.K_ESCAPE]:
        pygame.quit()
        ser.close()


    pygame.display.flip()


pygame.quit()

Probably a power supply/ brownout issue. What are you using for power?

Please chop that up. It's confusing, not explaning.
How is the Pc sure that the Arduino is ready for a new command?
I would add temporary Serial.println's. One printing the command read by bluetooth.read and the millis time.
Maybe compass data and others could be interesting.

In other words, find out where the last well executed command is and where it fails.

I'm using 4 batteries in a battery holder totalling up to 6V.

What I was trying to say is that when I press W the car can go straight without any issues but when I try to reverse by pressing S or rotate the car by using A and D keys the program crashes. There is no issues stopping the car by pressing space when I'm going straight aswell. I tried a few prints to try to monitor it but when the program crashes I'm not getting the commands in the Arduino anyway.

Since Arduino programs do not "crash", exactly happens? Does execution of the Arduino program just stop because it is stuck in a loop? If so, the previous advice about tracking the program execution is the way to find the loop.

6vdc is only enough for one motor without power brown-out. Show a wire drawing of your project. Depending on your motor driver, you will need between 7.5vdc and 9vdc power supply.

Sorry for misleasding by crashing I meant the program I wrote in python is crashing not arduino.

I unfortunetly don't have access to Fritzing but the motors that are being used are those generic 250RPM 6V motors, they look like this:
image

Besides these motors (There's two of them) there is a HC06 bluetooth module, HC-SR04 ultrasonic sensor a piezzo buzzer and GY-271 compass module. Wouldn't 6V be enough for all of them?

Then add code to display the current location in you code and see where it crashes. That is how I developed my one and only Python program a couple of years ago.

@ardasutcu - Try this page with individual motor sketches to help you find a solution...

First you need to make absolutely certain that the Arduino program is not restarting due to power issues with the motors. Loss of the serial connection can create issues on the Python side.

I would add some Serial output to the Arduino and have it print "In Setup" after adding Serial.begin( baud) in setup. Make certain you only see the print out once. If you see it more than once, the Arduino is restarting.

If the problem is not due to restarting and loss of the serial connection on the arduino side, then you can explore the python issues.

First thing would be to sort out if it is the sending of the character to the Arduino with the ser.write( ) or the .draw.polygon statements are crashing the python program.

if keys[pygame.K_w]:
        pygame.draw.polygon(window, WHITE, [(UP_ARROW_POS[0], UP_ARROW_POS[1] - ARROW_SIZE),
                                            (UP_ARROW_POS[0] + ARROW_SIZE // 2, UP_ARROW_POS[1]),
                                            (UP_ARROW_POS[0] - ARROW_SIZE // 2, UP_ARROW_POS[1])], 4)
        ser.write(b'w')


    if keys[pygame.K_a]:
        pygame.draw.polygon(window, WHITE, [(LEFT_ARROW_POS[0] - ARROW_SIZE, LEFT_ARROW_POS[1]),
                                            (LEFT_ARROW_POS[0], LEFT_ARROW_POS[1] + ARROW_SIZE // 2),
                                            (LEFT_ARROW_POS[0], LEFT_ARROW_POS[1] - ARROW_SIZE // 2)], 4)
        ser.write(b'a')


    if keys[pygame.K_s]:
        pygame.draw.polygon(window, WHITE, [(DOWN_ARROW_POS[0], DOWN_ARROW_POS[1] + ARROW_SIZE),
                                            (DOWN_ARROW_POS[0] + ARROW_SIZE // 2, DOWN_ARROW_POS[1]),
                                            (DOWN_ARROW_POS[0] - ARROW_SIZE // 2, DOWN_ARROW_POS[1])], 4)
        ser.write(b's')
       
    if keys[pygame.K_d]:
        pygame.draw.polygon(window, WHITE, [(RIGHT_ARROW_POS[0] + ARROW_SIZE, RIGHT_ARROW_POS[1]),
                                            (RIGHT_ARROW_POS[0], RIGHT_ARROW_POS[1] + ARROW_SIZE // 2),
                                            (RIGHT_ARROW_POS[0], RIGHT_ARROW_POS[1] - ARROW_SIZE // 2)], 4)
        ser.write(b'd')


    if keys[pygame.K_SPACE]:
        pygame.draw.circle(window, WHITE, CIRCLE_POS, SHAPE_SIZE // 2 + 5, 4)
        ser.write(b' ')


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