500W electric scooter control and instrumentation with Arduino mega

1. Introduction

DC 500W motor control with an Arduino mega to limit starting current and to vary the speed of the scooter. The battery is in 24V, 10A.h. The following table summarizes their characteristics:

2. Bibliography:

Link download :

sketch_escooter_feed_back_reel_V1.ino
sketch_escooter_feed_back_reel_V1.ino - Google Drive
escooter_ampli_SIMULINK.mdl
escooter_ampli_SIMULINK.mdl - Google Drive
escooter feed back ISIS.DSN
escooter feed back ISIS.DSN - Google Drive
video
**youtube : "study trotinette electric e-scooter 100W et 350W, wiring" **
study trotinette electric e-sccoter 100W et 350W, wiring - YouTube
Article: «Study of electric scooters 100W and 500W (Arduino), Revue 3EI 2017»
Pdf?

Book «I realize my electric vehicle» at DUNOD

3. Open loop program

To test the programming, we simulate the program in ISIS, as can be seen in the following figure. In addition, we have an LCD display to display data (duty cycle corresponding to the PWM at 32Khz, motor current, motor voltage, action on the pushbuttons, 4 push buttons are used.
BP1 to manually increment the duty cycle, BP2 decrement it. BP3 set the duty cycle to 0, corresponding to the brake contact.
The speed of the motor is practically proportional to the duty cycle

uy a shield

There are many cards for Arduino to control DC motors especially of low powers and also of great powers as can be observed on the following links.Robot Power Products - MegaMoto Plus Motor Control Shield for Arduino
http://www.robotshop.com/en/dc-motor-driver-2-15a.html
https://www.pololu.com/file/0J51/vnh3sp30.pdf
https://i58.servimg.com/u/f58/17/56/35/17/a310.jpg
But all these chopper shields measure the current internally but there is no current limitation.

In order to have a current limitation, an analog current loop is required using specialized AOP or IC or a fast digital current loop.
But what should be the value of the limitation current?
The choice of the current value is normally for the 1-hour operation service in order to be able to carry out relatively long climbs without reaching the critical temperature of the engine.
In our case, the limitation current must be

Limiting motor = Power / Upper battery = 500W / 24V = 20A

In addition, the power transistor of the chopper can only support 50A in our case.

But in open loop, it has no current regulation, so as not to exceed the maximum current, a ramp of the duty cycle will be used.
A 0.1 second interruption routine will be used to measure the voltage of the current (sample measurement, sample). This sampling time is arbitrary but does not allow to be faster than the rise time of the current because the electric time constant of the motor is L / R = 1.5 ms.

Open loop operation with a 25.5s (8bit) ramp and 0.1s interrupt routine provides a good understanding of the operation of a DC motor drive.
The display will only be done every 0.2s to have a stability of the digits on the screen. In addition, a digital filtering will be done on the current and the voltage on 4 values therefore on 0.4.

[b] Algo open loop [/b]

Interrupt Routine All 0.1S
Read voltage and current

Loop loop (push button scan)
If BP1 = 1 then increment PWM
If BP2 = 1 then decrement PWM
If BP3 = 1 then PWM = 0
Displaying variables every 0.2s
// include the library code:
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <TimerOne.h>
 
#define SERIAL_PORT_LOG_ENABLE 1
#define Led     13       // 13 for the yellow led on the map
#define BP1     30       // 30 BP1
#define BP2     31       // 31 BP2           
#define BP3     32       // 32 BP3
#define LEDV    33       // 33 led
#define LEDJ    34       // 34 led
#define LEDR    35       // 35 led
#define relay   36       // 36 relay
#define PWM10    10      //11   timer2    

LiquidCrystal lcd(27, 28, 25, 24, 23, 22); // RS=12, Enable=11, D4=5, D5=4, D6= 3, D7=2, BPpoussoir=26
// Configuring variables

unsigned   int UmoteurF = 0;  // variable to store the value coming from the sensor
unsigned   int Umoteur = 0;
unsigned   int Umoteur2 = 0;
unsigned   int Umoteur3 = 0;
unsigned   int Umoteur4 = 0;

unsigned   int ImoteurF = 0;  
unsigned   int Imoteur = 0;
unsigned   int Imoteur2 = 0;
unsigned   int Imoteur3 = 0;
unsigned   int Imoteur4 = 0;
           byte Rcy=0 ;    // 8bit duty cycle
unsigned    int temps;

// the setup function runs once when you press reset or power the board
void setup() {
  pinMode(Led, OUTPUT);   // Arduino card
  pinMode(LEDV, OUTPUT);
  pinMode(LEDR, OUTPUT);
  pinMode(LEDJ, OUTPUT);
  pinMode (PWM10,OUTPUT);     // Pin (10) output timer2

  
//  digitalWrite(LEDV,LOW);
  Timer1.initialize(100000);         // initialize timer1, and set a 0,1 second period =>  100 000
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
  lcd.begin(20, 4);  
  Serial1.begin(9600); 

  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 10  32khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet
                                                  //http://www.pobot.org/Modifier-la-frequence-d-un-PWM.html
  //   analogWriteResolution(bits)      https://www.arduino.cc/en/Reference/AnalogWriteResolution

lcd.setCursor(0,1);
lcd.print("Rcy");

lcd.setCursor(10,1);
lcd.print("Um");

lcd.setCursor(5,1);
lcd.print("Im");

lcd.setCursor(10,1);
lcd.print("Um");

lcd.setCursor(20,1); // 4 lines display * 20 characters
lcd.print("BP1+");

lcd.setCursor(25,1);
lcd.print("BP2-");

lcd.setCursor(29,1);
lcd.print("BP3=0");
}

// Interruptions  tous les 0.1s
void callback()  {
temps++;
//toogle state ledv for check 
  if ( digitalRead(LEDV)== 1 ) {digitalWrite(LEDV,LOW);}
    else {digitalWrite(LEDV,HIGH);}
    
analogWrite(PWM10,Rcy);   // frequency
Umoteur=analogRead(A0);
Imoteur=analogRead(A1);

Imoteur2=Imoteur;
Imoteur3=Imoteur2;
Imoteur4=Imoteur3;
ImoteurF=(Imoteur4+Imoteur3+Imoteur2+Imoteur)/4 ;


Umoteur2=Umoteur;
Umoteur3=Umoteur2;
Umoteur4=Umoteur3;
UmoteurF=(Umoteur4+Umoteur3+Umoteur2+Umoteur)/4 ;
  
}// End routine

// Loop corresponding to main function
void loop() {  

  // BP + LED
  if ((digitalRead(BP1))==1) {
    lcd.setCursor(20,0);      // Column line
    lcd.print("BP1");
    digitalWrite(LEDR, LOW);    
    digitalWrite(LEDJ, LOW); 
    Rcy++;                        // PWM incrementation
    if ( Rcy>254)  {Rcy=254;}
    delay(100);               //8bits * 100ms = 25S increment 25ssecond slope
    }  
    
  if ((digitalRead(BP2))==1) {
    lcd.setCursor(20,0); 
    lcd.print("BP2");
            Rcy--;
     if ( Rcy<2)  {Rcy=2;}  // PWM almost at 0, engine stop
        delay(100);  
    digitalWrite(LEDR, HIGH);
    digitalWrite(LEDJ, HIGH); 
    } 
  if ((digitalRead(BP3))==1) {
    lcd.setCursor(20,0);
    lcd.print("BP3"); 
     Rcy=2;               // PWM almost at 0, engine stop
    }

if (temps>=2)  {
lcd.setCursor(0,0);
lcd.print("                "); // Erase line

lcd.setCursor(0,0);     
lcd.print(Rcy);

lcd.setCursor(5,0);
ImoteurF=(ImoteurF)/20;     //resistance (5/1024)*(10/0.25ohm) si ACS712 66mV/A
                           // For resistance 1ohm (ImoteurF) / 20; Simulation 5/25
lcd.print(ImoteurF);


lcd.setCursor(10,0);
UmoteurF=UmoteurF*10/38;                              //10/38   10/30 simula
if (Umoteur>ImoteurF){UmoteurF=UmoteurF-ImoteurF;  }  //U-R*I

lcd.print(UmoteurF);


temps=0;
}// End if time
   
} // End loop

Since there is a limit of 9000 characters in the forum below

if (Imoteur<4000)                    // No current limitation at (20A * 10) * 20 = 4000
  {if (consigne>Rcy)   {Rcy=Rcy+1;}   // Pwm ramp + 1 * 0.01second pure integrator
   if (consigne<Rcy &&  Rcy!=0)    {Rcy=Rcy-1;}     // The decrementing is done only for the acceleration grip or with BP2
   if ( Rcy>254)  {Rcy=254;}           // Limitation of duty cycle
   analogWrite(PWM10,Rcy);   // Frequency 32kHz timer2}     
    }
if (Imoteur>4000)  { Rcy=Rcy-5;              // No current filtering, to be faster
                    if ( Rcy<6)  {Rcy=5;}       // Rcy is not signed, nor the PWM therefore Rcy minimum must not be less than 6
                  analogWrite(PWM10,Rcy);   // Frequency 32kHz timer2}      
                  }

5. Closed Loop Program, Limited Current Control with Acceleration Handle

An acceleration handle provides a 0.8V voltage when not operated and a 4.5V voltage when the handle is fully engaged.
Instead of using pushbuttons to increase or decrease the speed setpoint, an acceleration handle will be used

Upoignee=analogRead(A3); // The relation in Upoign and the setpoint which corresponds to the duty cycle corresponds to
if (Upoignee>100) { consigne=(Upoignee/2);     //0=a*200+b    et 255=a*800+b   
                   consigne= consigne-100;
                  }               
             else { consigne=0;   }               
if (Upoignee<100) { consigne=0;  }     // redundancy

6. Temperature and safety program of the motor with the current measurement

The outdoor temperature measurement can be easily performed by the LM35 component which charges 0.01V by degrees Celsius

temperature=analogRead(A2); //lm35 0.01V/°C
temperature=temperature/2;       // Temperature coefficient
lcd.setCursor(5,2);
lcd.print("      ");
lcd.setCursor(5,2);
lcd.print(temperature);   // Display in ° C
lcd.setCursor(9,2);      // Erasing secu display
lcd.print("     ");

  if (temperature>80 ) {lcd.setCursor(9,2);         // If motor external temperature is above 80 ° C
                     lcd.print("secuT");  
                     Rcy=0;}

In addition, thermal safety by measuring the motor current will be added.
If the limitation current is greater than 10s then the motor will no longer be powered for 30s.
A "secu" display will appear on the LCD display.
This safety makes it possible to cut the motor on slope too high and when blocking the engine but it would be necessary to add the measurement of the speed in the latter case

if (timesecurite>=10000 ) {flagarret=1;      
 // If limitation current for a current of more than 10s
                              timerepos=0;
                              consigne=0;
                              Rcy=0;   
                              timesecurite=0;}       //   Then stop engine during a downtime  
  if (flagarret==1 ) {lcd.setCursor(9,2);         // If limiting current for a current of more than 20s
                     lcd.print("secU");  }     //   Then stopping the motor for a stop time and display

    
                                            
    if (timerepos>=30000 &&  flagarret==1) {flagarret=0;
                                          lcd.setCursor(9,2);      // After a rest time here of 30s
                                           lcd.print("       ");   }

The display can be observed if the temperature is above 80 ° C

Thermal safety by measuring the motor current (digital thermal relay) which allows to know the image of the internal temperature of the engine would be ideal. But for this, it is necessary to know well the thermal modeling of the motor.

7. Measurement of the energy capacity of the battery

The energy capacity of a battery is in A.H, we willdisplay the value in mA.H to have a high accuracy. The capacity will be in A.Second in the following equation. So to have in mA.H, it will be divided by capacity by3600.
Capacity (A.s) n = I * Te + Cn-1 with Te = 0.01s and I multiplied by 10

So in the interrupt routine

capacity=ImoteurF+capacity ;

And in the display

lcd.setCursor(0,3); // Display of energy capacity
lcd.print("C mA.h=");
capacity1=capacity/(18000);   //18000=3600*5  5=> Current measurement coefficient
lcd.print(capacity1);
To check a current of 10A with an adjustable resistor and after 30s, the capacity must be 83mA.H

8. Power and modeling with SIMULINK

Modeling helps to understand thevehicle and its control. In addition, it is possible to compile the control part directly into the Arduino program from simulation under Simulink. But it will not be possible to simulate the instrumentation with the LCD display.
In the following figure, we can observe the simulation of the programming of the chopper with the current limitation with Simulink. In the following figure, the green box shows the duty cycle control to vary the speed and the red border the current limitation. The controller of the control is here a simple integrator but it is possible to carry out a multitude of control.

In the previous figure, it can be observed that the current is well limited to 25A from 2s to 9.5s. Then, the current reaches 10.8A under established speed regime at 22.5km / h. The dynamics are similar to the tests carried out.
With a slope of 5%, the cyclic ratio reaches only 100% as can be seen in the following figure. The speed will reach painfully 19km / h with a current of 24A and a motor power of 580W.
See article: Study of electric scooters 100W and 500W (Arduino),

9. First conclusion
It is easy to control a 500W DC motor with an Arduino and some components
So repair many scooters that are in DC motors.
But it takes some knowledge (automatic, engine) to know how to properly manage the engine and limit its current so as not to damage it
The display of the speed, the distance, the operating time to know the Watt.km / km can also be realized with a menu 2.

The .ino program as an attached file,
But it is not possible to put an attached file in ISIS electronic labcenter?
What is this forum?
It would be desirable that the compiler could generate the.cof to debug in Isis and test the program line by line ....
Arduino still has to make a lot of effort to be on the same level as other microcontrollers

sketch.pdf (3.23 KB)

10. speed measurement (tachometer)

Velocity measurement is carried out using a hall effect sensor SS495 or A1324 which counts each revolution of the wheel. It is enough to enter the perimeter of the wheel of the scooter (130mm of radius therefore 0.816m in the case
To have the speed, it is enough just to divide the number of turn of wheel on an arbitrary time of 1s to have a minimum speed of 0.81m / s therefore of 2.93 km / h. In addition, an average filter with 3 values will be used to display the speed. At 25km / h, there will be 8.5 laps.
To count the turns, an external interrupt routine will be used on input INT0 21 of the mega card.
http://www.locoduino.org/spip.php?article64
To simulate the speed, a pulse on input 21 will be used with a duty cycle of 10%.

void INT0b21() {
  Tspeed++;   // External interruption to count the number of turns
}

// In the set up declare the interrupt routine when the 5V edge of the magnet detection is done
  attachInterrupt(digitalPinToInterrupt(21), INT0b21, RISING );  // External interruption
// In loop
if (temps09>=5)  {        // 1 second loop
lcd.setCursor(13,2);      // Erasing speed
lcd.print("kph     ");
lcd.setCursor(16,2); 
speed1=Tspeed*2937;      //1tour*816*3.6/1s=2.937km/h
speed2=speed1;           //Tspeed (rate/seconde)
speed3=speed2;
speedF=(speed1+speed2+speed3)/3000;   // To put in kph
lcd.print(speedF,1);    // Display to the nearest tenth
Tspeed=0;   // Reset counter
temps09=0;  //reset time
}

To improve the accuracy of the velocity measurement, it is possible that the sampling time of the velocity measurement is dependent on the velocity.
For example:
For speeds less than 10km / h sample at 1second, but above 10km / h sample at 2 seconds.

11. Distance measurement for autonomy

The distance corresponds to the total number of turns of the wheel multiplied by the perimeter of the wheel.
So do not set the number of turns to 0 for each sample.
On the other hand, the reset of the distance will be done when pressing the reset of the Arduino Mega.
The distance display will be displayed to the nearest second.
At 32km / h, it will take 2 minutes to do 1km as can be seen in the following figure:

void INT0b21() {
  Tspeed++;   // External interruption to count speed
  nbrRate++;
}

lcd.setCursor(13,4);      
lcd.print("km      ");  //
distance=(nbrRate*816)/1000;  //distance m
distance=distance/1000;  //distance km
lcd.setCursor(15,4);      
lcd.print(distance,1);

You can observe the electrical installation with the chopper, the arduino, and the display when the program is set up

12. Synthesis

The RAM space is used only at 4% and ROM space at 3%, for an Arduino mega. So we could take an arduino a little smaller.
But, there are 8 Lipo cells to make the 24V power supply to power the engine via the chopper. Therefore, the voltage measurement of each element will be on the Arduino with a JST connector. This measurement makes it possible to know if a cell with an internal resistance which begins to pose a problem and to know if the balancing of each cell has indeed been carried out.
It is possible to switch to 36V with 12 cells also with the arduino mega without using an external shield that multiplex 24 analog inputs on input A0

It is possible to send all data to a smartphone via Bluetooth HC06 via pins 20, 21, RX1 and TX1. But the application under android realized under JAVA Studio can not be shared on this forum. This part will not be explained.

After having made the instrumentation of this scooter, a study should be carried out on the precision of the measurements, it is possible to read
"Instrumentation of a low-power electrical motor vehicle" eco marathon "type Revue 3EI N ° 81, July 2015

sepduino - Google Search

in writing :

Here are the electrical diagrams, 3 cards are used
A card that will plug into the arduino, measure temperature, current, and that makes the link to the display card

Here is the artwork


A 4 pushbutton card and an LCD display to retrieve old microcontroller system that used HE10 connectors

Here is the double face sticker

A chopper card that will be inserted into the first card

It’s easier to take a controller at 10 euros to control the scooter. :money_mouth_face:
As we can see on the following link :
http://www.electricscooterparts.com/hookup/SPD-YK31C.htm
We just need to connect the battery to the controller, as well as the motor, the on/off button and the the acceleration handle.
It Is possible to use dominoes, but Anderson connectors are easier to use as we can see on the attached picture.

On the other hand, there is no instrumentation to know the state of the remaining energy of the battery, nor the speed, nor the power demanded by the engine.
An cycle analyst could do this instrumentation but it costs 150euros :smiling_imp:

how is the code of your speed measurement working?

speed1=Tspeed2937; //1tour816*3.6/1s=2.937km/h
speed2=speed1; //Tspeed (rate/seconde)
speed3=speed2;
speedF=(speed1+speed2+speed3)/3000; // To put in kph

if speed1 = 15km/h, then you copy this 15 into speed 2, you copy the same 15 into speed 3 and then you add them all togheter in speedF divided by 3 for an average???
this wil always result in the same number.

why don't u use the time between 2 rotations and calculate that speed?
with millis() you can get the time between the first pulse and the second.
for example 200ms.
you travelled 0.816meter in 200ms.
1hour has 3.600.000ms
0.816meter in 200ms => 14688meter in 1hour

so the speed is 14.7km/h

i'm controlling an YK31C controller with an arduino nano and arrived on this topic trying to measure the power the controller is outputting