L298N Self Balancing robot problem

Hi,

1st of all, many people will think that it's the same post i done few hours ago but it's not the same
so please help if you know the answer in my problem, thanks.

I got a L298N on my balancing robot:


Fig. 1.1 L298N

My Code pins are:

#define ENA 5 //PWM 
#define ENB 6 //PWM
#define IN1 7 //Digital pin
#define IN2 8 //Digital pin
#define IN3 2 //Digital pin
#define IN4 3 //Digital pin
void setup() {
  Serial.begin(9600);
  Wire.begin();
  
    pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);

My only code to balance the robot and control the H-Bridge L298N is this code in loop:

 int sensorValueY = 0;
  int sensorValueY2 = 0;
  int motorPWMa = 0;
  int motorPWMb = 0;
  
  sensorValueY = compAngleY;
  sensorValueY2 = compAngleY;
  motorPWMa = map(sensorValueY, 5, 15, 100, 255);
  motorPWMb = map(sensorValueY2, -5, -15, 100, 255);  

//Backward  
if (compAngleY > 5.00){
  //turn clockwise Motor A
      digitalWrite(IN1, HIGH);   
      digitalWrite(IN2, LOW);  
      analogWrite(ENA, motorPWMa);
//turn clockwise Motor B
      digitalWrite(IN3, HIGH);   
      digitalWrite(IN4, LOW);  
      analogWrite(ENB, motorPWMa);  
}
//Forward
if (compAngleY < -5.00){
    //turn clockwise Motor A
      digitalWrite(IN1, LOW);   
      digitalWrite(IN2, HIGH);  
      analogWrite(ENA, motorPWMb);
//turn clockwise Motor B
      digitalWrite(IN3, LOW);   
      digitalWrite(IN4, HIGH);  
      analogWrite(ENB, motorPWMb);  

}
if(compAngleY > 45 || compAngleY < -45){
  digitalWrite(IN1, LOW);   
      digitalWrite(IN2, LOW); 
}

delay(100);

I created 2 maping codes to create the speed between MPU6050 degree angle and the PWM of
the motors. When I use this code once wheel spins faster than the other (I tested with "case" code and they worked fine). After the robot gets over 20 degree angle or the robots movement is big
the motors start spin in a single direction (for no reason "no code") till it stops by itself (after 8+sec)
or until I reset the board.

Info:
For the MPU6050 i use Complimentary filter.
no other code it's used for H-Bridge (only what's in loop).
..etc

D60

I would suggest doing some tests of the motor speed.

Write another simple sketch which doesn't deal with the balancing aspect of your project, and just tests the motors. Motors won't necessarily run at exactly the same speed when given the same inputs. They are all slightly different. For a normal robot, you can adjust for this by steering the robot to correct the direction. For a balancing robot, having the motors run at the same speed is somewhat more critical.

You may need to modify the speed commands being given to the motors individually, to compensate for the motors' individuality.

DC brushed motors are normally handed - they run faster in one direction than the other
for the same drive due to an advance angle on the brushes - this gives more efficiency
at large forward speeds. If a motor has the terminals marked red and black or +/-,
its likely this is the case. The effect is usually small and is less at low speeds, and most
people ignore it.

Your if( ) statements don't seem to cover any cases where the angle is between 5 and 45 degrees. Or do you expect it to do nothing.

Also, you must have built a very strange robot if you want the motors to both turn clockwise or counterclockwise at the same time.

MarkT:
DC brushed motors are normally handed - they run faster in one direction than the other
for the same drive due to an advance angle on the brushes - this gives more efficiency
at large forward speeds. If a motor has the terminals marked red and black or +/-,
its likely this is the case. The effect is usually small and is less at low speeds, and most
people ignore it.

This is a very interesting fact that I only recently became aware of.

Not only do most people "ignore it", it seems that in general motors with different handedness are not available. I did find one advertized.

I know your logic behind it, but calling output pins IN1, IN2, etc could quickly get confusing (at least it does to me) Consider calling them LeftMotorEnable, LeftMotorForward, LeftMotorReverse, RightMotorEnable, RightMotorForward, RightMotorReverse... it would be far easier to get a picture of what the code is doing if you describe what the pin does in the physical world than it's electrical connection to something we have no schematic to compare to.

First thing I'd do is what Michinyon suggested.. just set the motors to run full speed and see if they run at the same speed... I have NO idea of how this robot looks, so perhaps, if the motors are 'handed', and you have them facing opposite directions one has to turn backward to produce a forward movement in the robot, causing a difference in speed

  //your code
  int sensorValueY = 0;
  int sensorValueY2 = 0;

  int motorPWMa = 0;
  int motorPWMb = 0;
  
  sensorValueY = compAngleY;
  sensorValueY2 = compAngleY;
  motorPWMa = map(sensorValueY, 5, 15, 100, 255);
  motorPWMb = map(sensorValueY2, -5, -15, 100, 255);

OK, Why do you set sensorValueY and SensorValueY2 both equal to compAngleY.. why bother with those two variables at all? For as much as I can tell you never used them again anyhow.

Also, if you're mapping from 5 to 15, you aren't constraining it to between 5 and 15.. thus, if you go above 15 with the compAngleY, you will get an output of greater than 255, and I don't know how analogWrite behaves when that happens, especially throwing negatives into the mix

//my version

int motorPWM
 motorPWM = map(compAngleY, 5, 15, 100, 255);
 motorPWM = constrain(motorPWMa,100,255);


//Eliminated the other PWM.. I don't see how one motor should be operating when it's leaning one direction, and the other motor when it's leaning the opposite.. I may be out to lunch, but I think you intended that they move opposite directions, but at the same speed..

Further on down the line, I think a lot could be simplified

boolean Forward = compAngleY>=0;

 //We've defined Forward, and we can use that without any more conditionals to set the directions.. When Forward is false the direction will change

 // Set Motor A direction
      digitalWrite(IN1, Forward);   
      digitalWrite(IN2, !Forward);  
  
//ditto for motor B
      digitalWrite(IN3, Forward);   
      digitalWrite(IN4, !Forward);  

//Move Motors
if (abs(compAngleY >5)){
   analogWrite(ENA, motorPWM); 
   analogWrite(ENB, motorPWM);  
}
else{ //Remember you have to deliberately stop the motor
   digitalWrite(ENA, LOW);
   digitalWrite(ENB, LOW);
}
 

//Now I don't know about you, but I find the above more readable, and I think it does exactly the same thing

if(abs(compAngleY>45)){

      digitalWrite(IN1, LOW);   //I don't see what this does if you're only doing it to one motor.. 
      digitalWrite(IN2, LOW);  //Perhaps this one should be IN3?.. What about the other 2 pins?
     //Whats happening here is you're setting Motor A to brake mode, but not motor B
     //if the angle is greater than 45.. it's falling over? 
}

delay(100);

Rx7man

//if the angle is greater than 45.. it's falling over?

Maximum I would say if the robots gets over 45 degree it's falling over so the 45 deg. it needs to have max
PWM speed on the motors to recover it self.

Now why I use mapping ?

I try to use maping to make a PWM speen on the motors comparing to degree angle, if i have a constant speed
the robot will get disbalances every time when it gonna try to balance at top "0 deg." position. In this way PWM map working at a "car" ABS breaking. (that's my logic)

I build 1st time a selfbalancing robot and i try to work on my own code.

michinyon

I would suggest doing some tests of the motor speed.

Write another simple sketch which doesn't deal with the balancing aspect of your project, and just tests the motors.

I already done that with a example program for L298N and the speed/direction of the motors are right positioned.

That's the robot before i used mapping code. It does not balance itself i need to hold my hands around in case falls over but still not a good balance, i would say 30% balancing.

After that I saw people using PID on their code to balance their robots but I tried to study PID
didn't understood how exactly works in code, I read a article thay said it's not necesary to use PID
in case your code works for your balancing robot so I gave a try with mapping but worst than earier codes :smiley:

OK, now that I see how it looks I have a better idea of what you need to happen :slight_smile:

The code the way you have it isn't really going to work because you can't have it move and balance itself at the same time..

I think the 100ms delay is too big to get it to accurately balance, and also the 5* tilt needed to actuate the motors may be a little big.. PID would definitely be useful here, especially the derivative part. I've just been doing a lot of work with PID on my own project

You need to put it all into functions.. and lay it out a little like this

//couple global variables.. 
/assuming compAngleY already is one, or you may need to pass it to the Balance function

int MaxSpeed = 255;
int MinSpeed = 50;

void Loop(){

int Balance();
int Turn = GetTurnRate();
int Movement = GetMovement();

MoveMotorA(Balance+Movement+Turn);
MoveMotorB(Balance+Movement-Turn);


int Balance(){

int MinTilt = 1;
int MaxTilt = 20;
boolean Forward = compAngleY>=0;

int BalanceOutput;

 BalanceOutput = map(abs(compAngleY),MinTilt, MaxTilt, MinSpeed, MaxSpeed);
 BalanceOutput = constrain(BalanceOutput,MinSpeed,MaxSpeed);
if (abs(tilt)<MinTilt){
  BalanceOutput  = 0;
}
if (!Forward){
  BalanceOutput *= -1; //invert the sign if going backward
}
Return BalanceOutput;

int GetMovement(){
 //Some code here that returns a SIGNED value for direction
}

int GetRotation(){
//some code here that returns a SIGNED value for turning left or right
}


void MoveMotorA(int speed){
boolean Forward = (speed>0);
      digitalWrite(IN1, Forward);   
      digitalWrite(IN2, !Forward);  
int PWMa = constrain(abs(speed),MinSpeed,MaxSpeed);
analogWrite(ENA, PWMa);
}

void MoveMotorA(int speed){
boolean Forward = (speed>0);
      digitalWrite(IN3, Forward);   
      digitalWrite(IN4, !Forward);  
int PWMb = constrain(abs(speed),MinSpeed,MaxSpeed);
analogWrite(ENB, PWMb);
}

Now you have a good basis to work from.. and it's readable and split into logical blocks.

I'm going to spend the day thinking about how to implement a PID on this.. It's something I do while cutting hay :slight_smile:

Rx7man
i appreciate your help and time and your code looks nice but for start I just try to balance the robot,
to get a perfect balance and understand what exactly im doing.

There is few parts in your code that i didn't understood why they are there for, for example

MoveMotorA(Balance+Movement+Turn);
MoveMotorB(Balance+Movement-Turn);

and 

int PWMa = constrain(abs(speed),MinSpeed,MaxSpeed);
// to controll the PWM of the speed in the forward position and angular speed?

Would be nice if you make a small comment in the parts of the code so I could know what exactly they are for.

Right now i try put the code you wrote for me in my code and make everything works.

Sorry about not commenting better (I'm always guilty of that).

I was thinking more (I just finished cutting hay), and my logic for movement isn't going to work as I had planned originally, but nevertheless, I'll explain the rest of it

MoveMotorA controls motor A... it consists of 3 components, a balance component, a forward motion component, and a turning component.

Exactly the same for motor B, except the turn component has the opposite sign (the wheels have to turn opposite directions in order for any real turning to take effect.

The second part

Since the analogWrite only take positive numbers, but our function takes positive and negative numbers, the rotational speed and direction of rotation have to be put into separate components

So this part determines which direction we need to run the motor

Forward = (speed>0);

The other part limits the value to positive numbers (abs), and then limits them to something analogWrite can handle..

just got company pulling in, I'll continue later

All that need to be in loop? I tried your code, doesn't looks like it's working.
How the void's gonna work in loop? voids are like classes which you need to determin how they gonna
work in loop, im confused.

voids are just functions that aren't expected to return a value...

It's not necessary to get a return value back from the motor control, thus it's void

The other functions are there specifically to return a value, thus they need to define the return type as int.

Meanwhile, on the motor logic and why I said what I was thinking about wasn't going to work, and why

If you just tell the two motors to move forward, it will tilt over backward, you kinda have to make it tilt forward first by moving backward, then move forward...
So I thought rather than telling it to move forward, you could tell it to tilt forward (rather than aiming for a 0 tilt, aim for a couple degrees of tilt in the direction you want to move.. the trouble with that is as long as its tilted, it will ACCELERATE forward, and when you tell it to return to 0 tilt, it will continue moving forward, you have to tell it to tilt backward until it stops. I haven't quite worked out the logic for that in my mind yet.. but I know that these are problems you'll run into.

OOps, I saw what perhaps confused you..

I had written

void Loop(){

int Balance();
int Turn = GetTurnRate();
int Movement = GetMovement();
.
.
.
int Balance(){
.
.
.
}

Should have been

int Balance = GetBalance();
.
.
.
//then the declaration of the function
int GetBalance(){
.
.
.
}

Yea, i was like what the hak is that :smiley:
anyway, all that shouldn't be in loop right? or should?

How exactly im gonna make the loop codE?

Above void setup, the tilt should be int tilt=0; ??

Blatantly a typo :wink:

That second function should be for motor B not A. Guess it should be called MoveMotorB()

I noticed that a bit later too.. copy/paste error.

I can't read a thing on what you posted there.

All that can be in the loop code, and you don't need to have a delay either.. as fast as it'll run is just fine. but I did forget a closing brace

so loop should look a little more like

void Loop(){

int Balance = GetBalance();
int Turn = GetTurnRate();
int Movement = GetMovement();

MoveMotorA(Balance+Movement+Turn);
MoveMotorB(Balance+Movement-Turn);
}

That second function should be for motor B not A. Guess it should be called MoveMotorB()

Well that's not the only problem :smiley:

I think i will give up and work on other projects. :confused: