Language: EN

coche-robot-2wd-barato-con-arduino-programacion-l298n

Arduino 2WD Robot Car - L298N Programming

We continue with the series dedicated to our first robot project. After seeing the budget, assembly, and electrical diagram, we finally arrive at our first programming session.

And yes, we say first session, because there will be more than one entry dedicated to the robot’s programming. Logical, considering the emphasis we have made that it is a robot that can have multiple different behaviors and programs.

Also, there is a lot to tell for a single session, so we will take it step by step. In this post, we will see how to control the motors with the L298N controller, and it will also help us to see the general dynamics that we will follow in these entries.

I won’t go on more than I know that by now you are eager to see code, code, and code. So let’s get to it.

L298N Control Example

In reality, a basic programming of the robot that makes use of the L298N controller is not at all difficult. In fact, we already saw the necessary code in the entry about the L298N controller.

This is the example we saw in its day, which has functions to move forward, and backward, and a small loop that performs both movements.

const int pinIN1 = 5;
const int pinIN2 = 6;
const int pinIN3 = 7;
const int pinIN4 = 8;
const int pinENA = 9;
const int pinENB = 10;

const int waitTime = 2000;  //espera entre fases
const int speed = 200;    //velocidad de giro

const int pinMotorA[3] = { pinENA, pinIN1, pinIN2 };
const int pinMotorB[3] = { pinENB, pinIN3, pinIN4 };

void setup()
{
  pinMode(pinIN1, OUTPUT);
  pinMode(pinIN2, OUTPUT);
  pinMode(pinENA, OUTPUT);
  pinMode(pinIN3, OUTPUT);
  pinMode(pinIN4, OUTPUT);
  pinMode(pinENB, OUTPUT);
}

void loop()
{
  moveForward(pinMotorA, 180);
  moveForward(pinMotorB, 180);
  delay(waitTime);

  moveBackward(pinMotorA, 180);
  moveBackward(pinMotorB, 180);
  delay(waitTime);

  fullStop(pinMotorA);
  fullStop(pinMotorB);
  delay(waitTime);
}

void moveForward(const int pinMotor[3], int speed)
{
  digitalWrite(pinMotor[1], HIGH);
  digitalWrite(pinMotor[2], LOW);

  analogWrite(pinMotor[0], speed);
}

void moveBackward(const int pinMotor[3], int speed)
{
  digitalWrite(pinMotor[1], LOW);
  digitalWrite(pinMotor[2], HIGH);

  analogWrite(pinMotor[0], speed);
}

void fullStop(const int pinMotor[3])
{
  digitalWrite(pinMotor[1], LOW);
  digitalWrite(pinMotor[2], LOW);

  analogWrite(pinMotor[0], 0);
}

Similar codes to these can be found hundreds of times on the Internet. Cleaner, less clean, but similar. We can continue to add functions to turn, control encoders, activate sensors, etc.

The problem with this programming is that, although simple and didactic, it quickly grows uncontrollably in size and becomes what is called “spaghetti” code.

We don’t want to do this, so let’s see how to move from functional programming to object-oriented programming with a defined architecture.

Robot Car in Objects

Let’s see how to implement motor control in a more organized way. All the following code is available on GitHub at this link, so don’t worry now about copying and pasting the code, we will only focus on how the robot is organized. Therefore, we will only focus on the declarations of each class, not its implementation, which you can consult in the GitHub code. github-full First, it is obvious that we have a robot with two motors. It seems like a big silly thing, but it is the first step to begin the abstraction. We need a “Robot” class and a “motor” class. To these classes, we will add “encoder”, “sensor”; “behavior”, “communication” classes, and we can combine and combine them. But let’s take it step by step.

RobotCar Constants

First, we have a file RobotCar_Constants, which will contain all the constants of our robot (geometry data, connections, etc). In this first example, we only have the six control pins of the L298N.

const int pinIN1 = 5;
const int pinIN2 = 6;
const int pinIN3 = 7;
const int pinIN4 = 8;
const int pinENA = 9;
const int pinENB = 10;

RobotCar L298N

On the other hand, we have a class called RobotCar_L298N, which controls a single motor of the robot. Here we have the declaration of the class, with the main methods to control the direction and speed of the motor.

#ifndef _ROBOTCAR_L298N_h

#define _ROBOTCAR_L298N_h

#include <Arduino.h>

class RobotCar_L298N
{
public:
  void Init(int pinIN1, int pinIN2, int pinENA);
  void Stop() const;
  void MoveForward() const;
  void MoveForward(uint8_t speed) const;
  void MoveBackward() const;
  void MoveBackward(uint8_t speed) const;

private:
  int8_t _pinIN1;
  int8_t _pinIN2;
  int8_t _pinENA;
};


#endif

RobotCar Lib

For its part, the RobotCarLib class, which represents the main class of the robot. At the moment, our robot consists of two motors, left and right, and the functions to move the robot, and turn with two wheels (Turn) or one wheel (SlowTurn).

#ifndef _ROBOTCARLIB_h

#define _ROBOTCARLIB_h

#include "Arduino.h"
#include "RobotCar_L298N.h"

class RobotCarLib
{
public:
  void Init();

  void Stop() const;

  void MoveForward() const;
  void MoveForward(uint8_t speed) const;
  void MoveBackward() const;
  void MoveBackward(uint8_t speed) const;

  void TurnLeft() const;
  void TurnLeft(uint8_t speed);
  void TurnRight() const;
  void TurnRight(uint8_t speed) const;

  void SlowTurnLeft() const;
  void SlowTurnLeft(uint8_t speed) const;
  void SlowTurnRight() const;
  void SlowTurnRight(uint8_t speed) const;

private:
  RobotCar_L298N _motorLeft;
  RobotCar_L298N _motorRight;
};


#endif

Sketch test motors

Finally, we have the sketch, which simply instantiates a robot and performs a series of movements to check its operation.

#include "RobotCarLib.h"

RobotCarLib robot;

const int waitTime = 2000;

void setup()
{
  robot.Init();
}

void loop()
{
  robot.MoveForward();
  delay(waitTime);

  robot.MoveBackward();
  delay(waitTime);

  robot.TurnLeft();
  delay(waitTime);

  robot.TurnRight();
  delay(waitTime);

  robot.Stop();
  delay(waitTime);
}

Testing our Robot’s Code

We upload the code to our robot and check that everything works correctly. If any of the motors rotate in the wrong direction (or both), you can either physically change the cables in the L298N connection terminal, or interchange the IN1 and IN2 pins (for motor A) or IN3 and IN4 for motor B.

Similarly, if you have the motors swapped (the left one is the right and vice versa), simply change the pins of the group IN1, IN2, ENA, with the group IN3, IN4, ENB in the code.

When you manage to get the robot to move in order, forward, backward, turn left, turn right, stop… Congratulations! You have finished this first tutorial, and you have a functioning robot.

This is the result of this first programming session. It’s not too spectacular, but we are already controlling the basic movements.

Unfortunately, for now, we can only move it with functions programmed by time. We cannot control the distance we travel, nor the angle we turn. Moreover, it is possible that your robot does not go completely straight and has a drift to the left or right.

This is the problem of not having the encoders working. But don’t worry, we will see this in the next entries for programming our first robot.

Download the Code

All the code from this post is available for download on Github. github-full