Maker.io main logo

Making a compact railway model controller using M5Stack [Maked Powerpack

2023-11-27 | By M5Stack

Share

* Thanks for the source code and project information provided by @Sycom2600

1

 

Video

 

Development material

2

System configuration

It was a little hard to understand in the running video, so I've attached a video of the brushless DC drive, which makes the sound easier to hear.

https://www.youtube.com/shorts/ptZY0kZ62zQ?embeds_referring_euri=https%3A%2F%2Fprotopedia.net%2F&source_ve_path=Mjg2NTksMjg2NjMsMTU2OTE1&feature=emb_ytp_watch_again

It's the same 12V, so nothing has been changed.

About system configuration

hardware:

  • M5StackBasic
  • FET base

 

software:

  • Various LCD drawing functions
  • Arithmetic routine
  • Main loop

 

The impetus for development

M5STACK is a very convenient and easy to develop device. I decided to use this to create a power pack for a model railroad, which was exactly what I needed.

  • The functional requirements were as follows. 

    • 1. Use PWM and PFM control.
    • 2. Prepare a GUI that takes full advantage of the LCD. 
    • 3. No built-in FET board. (As we plan to use M5Stack for other purposes in the future)
    • 4. Implement a protection circuit
    • 5. Make an excitation sound from the motor. 
    • 6. Make a sound from the main unit as well.  
  • Preliminary investigation:

    • Since I had previously created a PWM controller using Arduino UNO, I used the underlying technology as is. The goodness of M5Stack is alive and well.
  • About the development environment:

    • When I set up the environment on my PC, I noticed that the Arduino IDE had changed. (Due to various reasons, I hadn't touched the Arduino IDE for over a year.) I was troubled by an unfamiliar operating feel and an error that prevented ESP32 from compiling. In the end, I returned to the original version (Arduino1). This deployment is the same as ROS. Also, since compiling to M5stack is very, very, very slow, I moved the development environment to Linux. It feels like it's 10 times faster.
  • About the program, I apologize for the inefficient writing style, but this is how it is.

Copy Code
メインルーチン
#include <M5Stack.h> //26pin out
#include <M5GFX.h>
M5GFX lcd;
M5Canvas canvas(&lcd);
int val=0;
float valpwm;//pwmvalue
float prevalpwm=0;
int Mmode=0;
int mascon=0;
int premascon=0;
float prespd=0;
float spd=0;//Scalespeed
int setspeed=120;//Scalespeedlmit
String tex1;
String tex2;
int mdata=0;
int sound =0;
void setup() {

M5.begin();
M5.Power.begin();
lcd.begin();
canvas.setColorDepth(8);
canvas.createSprite(lcd.width(), lcd.height());
M5.Lcd.clear(BLACK);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(RED);
int batt=M5.Power.getBatteryLevel();
M5.Lcd.setCursor(280, 10);
M5.Lcd.printf("%d",batt);


M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(65, 10);
M5.Lcd.println("Running");
M5.Lcd.setCursor(190, 10);
M5.Lcd.println("Battery");
M5.Lcd.setCursor(135, 90);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.print("Speed");
M5.Lcd.setCursor(3,90);
M5.Lcd.print("OP");
M5.Lcd.setCursor(3,110);
M5.Lcd.print("PWM:");
M5.Lcd.setCursor(100, 110);
M5.Lcd.print("%");
M5.Lcd.setCursor(135, 110);
M5.Lcd.print("Carrier");
M5.Lcd.setCursor(270, 110);
M5.Lcd.print("Hz");
M5.Lcd.drawRect(286,143,34,79,DARKGREY);
M5.Lcd.drawRect(248,138,34,84,DARKGREY);
M5.Lcd.drawRoundRect(78,33, 120, 29,3, DARKGREY);


M5.Lcd.drawLine(10, 180, 230, 180, NAVY);//scale 200ms


//M5.Speaker.setVolume(1);
M5.Speaker.mute();

pinMode(26,OUTPUT);
ledcSetup(0,100,8);
ledcAttachPin(26,0) ;
}

void loop() {
M5.update();
if (M5.BtnA.wasReleased()){
tex1="MENU";
subtext(tex1,tex2);
tex2=tex1;
mdata=1;
}else if ( M5.BtnA.pressedFor(2000, 2000)) {
tex1="SETING";
subtext(tex1,tex2);
tex2=tex1;
}else if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(300, 100)) {
if(mascon>-8){
premascon=mascon;
mascon=mascon-1;
masconLCDs(mascon,premascon);
Gmas(mascon,premascon);

}else{
premascon=mascon;
mascon=-8;
masconLCDs(mascon,premascon);
Gmas(mascon,premascon);



}
} else if(M5.BtnC.wasReleased() || M5.BtnC.pressedFor(300, 100)) {
if(mascon<5){
premascon=mascon;
mascon=mascon+1;
masconLCDs(mascon,premascon);
Gmas(mascon,premascon);
}else{ M5.Lcd.fillRect(250, 200, 30,20, BLACK);

premascon=mascon;
mascon=5;
masconLCDs(mascon,premascon);
Gmas(mascon,premascon);
}
}




val=val+mascon;
if(val<0){
val=0;
}else if(val>1275){

val=1275;

}
prespd=spd;
prevalpwm=valpwm;
valpwm=val/5;

spd= SPDdata(valpwm,setspeed);
SpeedLCDs(spd,prespd);
pwmLCDs(valpwm,prevalpwm);


sound=Hzmake(mapping(valpwm));
if(sound>0){
//M5.Speaker.setVolume(1);
ledcSetup(0,sound,8);
ledcWrite(0,valpwm);
//M5.Speaker.tone(sound, 100);
}else{
ledcWrite(0,0);
}
HzLCDs(sound,Hzmake(mapping(prevalpwm)));
delay(10);

HzdataLCD(sound);
}

For LCD drive

Copy Code
LCD駆動用
void masconLCDs(int mascon1,int premascon1){

M5.Lcd.setCursor(3, 60);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.printf(": %d", premascon);
M5.Lcd.setCursor(3, 60);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.printf(": %d", mascon);
delay(10);
}








void subtext(String maintex,String pretex){

M5.Lcd.setCursor(3, 35);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.printf("%s",pretex);
M5.Lcd.setCursor(3, 35);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.printf("%s",maintex);
delay(10);

}









void SpeedLCDs(float SPD1,float preSPD1){

M5.Lcd.setCursor(200, 90);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.printf("%.1f km/h", preSPD1);
M5.Lcd.setCursor(200, 90);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.printf("%.1f km/h", SPD1);
canvas.pushSprite(&lcd, 0, lcd.height());
delay(10);
}











void pwmLCDs(float SPD1,float preSPD1){

int pass=mapping(SPD1);
int repass=mapping(preSPD1);

M5.Lcd.setCursor(30, 90);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.printf(":%.1f:", preSPD1);
M5.Lcd.setCursor(30, 90);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.printf(":%.1f:", SPD1);


M5.Lcd.setCursor(50, 110);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.printf(":%d", repass);
M5.Lcd.setCursor(50, 110);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.printf(":%d", pass);


if(repass>pass){
M5.Lcd.fillRect(80+pass, 35,repass-pass+1,25, BLACK);
}else if(pass>repass){
M5.Lcd.fillRect(80+pass, 35,pass-repass,25 , BLUE);
}else{
M5.Lcd.fillRect(80, 35,2,25 , GREEN);
}


canvas.pushSprite(&lcd, 0, lcd.height());
}

void HzLCDs(int SPD1,int preSPD1){

M5.Lcd.setCursor(225, 110);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.printf("%d", preSPD1);
M5.Lcd.setCursor(225, 110);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.printf("%d", SPD1);

canvas.pushSprite(&lcd, 0, lcd.height());
delay(10);
}
}


void Gmas(int mascon1,int premascon1){

int xval=mascon1*10;
int pxval=premascon1*10;

if(mascon>0){
M5.Lcd.fillRect(288, 220-pxval*1.5, 30,pxval*1.5, BLACK);
M5.Lcd.fillRect(288, 220-xval*1.5, 30,xval*1.5 , GREEN);

delay(10);
}else if(mascon<0){

M5.Lcd.fillRect(250, 220+pxval, 30,-pxval, BLACK);
M5.Lcd.fillRect(250, 220+xval, 30,-xval , RED);

delay(10);

}else{

M5.Lcd.fillRect(250, 200, 30,20, BLACK);
M5.Lcd.fillRect(288, 200, 30,20, BLACK);
delay(10);
}
canvas.pushSprite(&lcd, 0, lcd.height());

}

void HzdataLCD(int Hz){
if(Hz>0){
M5.Lcd.fillRect(20, 140,220,220, BLACK);
int ms=4000/Hz;
int kaisuu=200/ms;
for(int i=0;i<=kaisuu;i++){

int base=20+i*ms;
M5.Lcd.drawLine(base, 180, base,180-40, DARKGREEN);
M5.Lcd.drawLine(ms+base, 180, ms+base,180+40, DARKGREEN);
M5.Lcd.drawLine(ms/2+base, 180+40, ms/2+base,180-40, DARKGREEN);
M5.Lcd.drawLine(base, 180-40, ms/2+base,180-40, DARKGREEN);
M5.Lcd.drawLine(ms/2+base, 180+40, ms+base,180+40, DARKGREEN);
}

M5.Lcd.drawLine(10, 180, 230, 180, NAVY);//scale 200ms
canvas.pushSprite(&lcd, 0, lcd.height());
}else{
M5.Lcd.fillRect(20, 140,220,220, BLACK);


}
}

Other calculations, output

Copy Code
周波数情報

int Hzmake(int PWs){

int valhz=0;
if(PWs==0){

valhz=0;


}else if(PWs<=6){

valhz=0;


}else if(PWs<=9){

valhz=0;

}else if(PWs<=12){

valhz=0;

}else if(PWs<=14){

valhz=6;

}else if(PWs<=16){

valhz=0;

}else if(PWs<=18){

valhz=0;

}else if(PWs<=20){

valhz=0;

}else if(PWs<=22){

valhz=0;

}else if(PWs<=45){

valhz=0;

}else if(PWs<=55){

valhz=0+PWs*3;

}else {

valhz=0+PWs*2;

}
return valhz;
}

//周波数をvalhzに入力。時間はパーセンテージに応じて割り当てる


int SPDdata(int vol, float sspeed){
float respd=0;

respd=map(vol,0,255,0,sspeed);

return respd;
}

int mapping(int map1){

int Va1=map(map1,0,255,0,100);

return VaI;
}

I try not to write in main as much as possible. In addition, the frequency output part (valhz) is a function of time according to the PWM duty ratio, so it is easy to create based on the correlation of the actual vehicle. In addition, the acceleration is also easy to adjust, so you can change it depending on the vehicle to create a better atmosphere. I filled in the black parts of the LCD to make it less likely to flicker and implemented sprites, but for some reason errors occurred and the waveform output didn't work well or was slow, so I ended up using brute force.

As a side note, I use a crash inverter, SC59A IGBT2 level inverter manufactured by Hitachi, and a Siemens VVVF (501 style).

Performance: PWM is 8-bit, and the frequency is compatible with the audible range. The display data is set with a higher number of drawing tasks as a goal to leverage the performance of the ESP32. The left button on the M5Stack is implemented as a reserved button for expansion. The center button is for reducing the throttle, and the right button is for increasing the throttle. A slight sound is output from pin 26 from the main unit, but if you specify pin 25, it can generate sound directly from the main unit ."  

  • Summary I was able to fully appreciate the ease and versatility of development that characterizes M5Stack, as well as the benefits of using the Arduino language. Also, since the sound from the motor was low, we were also transmitting sound from the main unit, but there was a difference in the sound heard from both, so we would like to make adjustments here as well. And above all, it's the waveform...the flicker is too bad...Finally, since we also have SticC, I'm thinking it would be nice if we could do something with it, but I don't know what to do...

Summary I was able to fully appreciate the ease of development and versatility, as well as the benefits of being able to use the Arduino language, which are features of M5Stack. With M5SticC available, thinking about what I can do here, and what I should do.

Mfr Part # K001-V27
ESP32 BASIC CORE IOT DEVELOPMENT
M5Stack Technology Co., Ltd.
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.