wokwi-features
wokwi-features copied to clipboard
DC motor driver L298n
I'm using the simulator with my students. Their projects include DC motor and motor driver L298n. I'd appreciate support for these two components
Yeah, I recommended 4 my teacher but need some dc motor and H bridge to simulate robots/cars
I want all 3 "types" of motors in the simulator - The HobbyServo, the DCmotor and the Stepper (Bipolar and Unipolar)
Maybe this request should be split up into DC motor and L298n chip, but that would loose it's votes.
The DC motor is easy enough ... <cough, cough> 1: It just is a "LED" with three graphics - standing still, turning clockwise, turning anticlockwise. 2: Turning speed is proportional to the average on/off (How any samples?!) over a short (0.2 second) period, thus responding to "analog write" from the Arduino (or any bit-banging thereof) 3: Mechanical inertia: As with other mechanical or electronics - WokWi is NOT a full physics simulator, just software. So, NO.
The L298n - well it is "just" another driver chip. Note though, it can be used BOTH for 2 DC motors or one BiPolar stepper (which has been implemented)
I want all 3 "types" of motors in the simulator - The HobbyServo, the DCmotor and the Stepper (Bipolar and Unipolar)
At the moment we have the Servo and a Bipolar servo, so we're missing the DCmotor and unipolar stepper, right?
As for the DC motor - any information about the PWM duty vs turning speed ratio?
"I want" is of course not a demand ;-) Yes, two down, two to go, for the Complete Motor Set™.
My understanding is that WokWi is not an electrical simulator nor a mechanical/physics engine, it verifies that microprocessor software functionally produces correct results to drives peripherals. (If the motor is strong enough, or the amperage drawn fries the chip, that is part of RealLife©)
My experience is that PWM gives a close to linear response to turning speed with light load on the motor.
Maximum motor speed is defined by a given motor IRL. For WokWi it is how fast we can show a turning motor (framerate, CPU horsepower). OR, for extra credit, a sound pitch :-) For most code I can imagine, one would just need visual feedback on stop, creep, slow, medium, fast - forwards and backwards (9 different animations) or maybe just stop, clockwise, CCW and a speed indicator.
(Side track: "Speed indicator" made me think of a generalpurpose device for all PWM related output: An analog or digital indicator that simply reports 0-100% of the PWM)
The simulation should be able to drive the DC motor:
- Direct from a pin, PWM or not, other motor pin to GND
- Inverse: the other motor side is to +5V instead, ie the Arduino pin sinks current (PWM acts inverted)
- Two pins so both directions are possible, one pin controls the motor, the other is set to HIGH or LOW as a powersupply.
- Through the L298n
- Through a relay that reverses polarity by another pin.
WokWi does not simulate power consumption. Back EMF protection (a diode) is likewise "beyond scope" for the WokWi. Same reasons as the bipolar stepper.
An execption (but very difficult I think) is : Mechanical Inertia. On Steppers and Servos this is a minor issue only with high speeds/acceleration, but on an ordinary motor it is significant behavioural on stopping. Cutting power the average DC motor (unless heavily loaded) I expect a spin down. The standard cure is to short the motor terminals on stop. In the above list that can only be done by the L298 (or a 2nd relay in (5)). Certainly for code a circuit with the L298 one would include the "Fast Stop". Acceleration on the DC motor on power up is just "nice to have".
😉 That should keep you busy for a week at least 😈
Yes, I luv be a contributor... moreover I have did some part of DC motor (also called as "Bo Motor"). which I have made a video explaining my difficulties..
but, guys still figuring... a way to do the code.. Still reading and watching videos to learn react and storybook, and improve.. thanks @urish for providing details.. for the elementpins and connecting me to this issue!!
If any know have idea or suggestion in code part, Please let me know?.. ("Storybook, Js, React) !!.........
Thanks @Sreedharbot! Any progress with doing the code? Unfortunately, I don't have any specific suggestions on how to progress faster learning all those technologies - it is pretty complex, and it takes time and practice.
Hey @urish, so far, i'm figuring out.. and the code is half in progress..
"I want" is of course not a demand ;-) Yes, two down, two to go, for the Complete Motor Set™.
My understanding is that WokWi is not an electrical simulator nor a mechanical/physics engine, it verifies that microprocessor software functionally produces correct results to drives peripherals. (If the motor is strong enough, or the amperage drawn fries the chip, that is part of RealLife©)
One alternative is to simulate the dynamics of the motor with a function within the Arduino sketch:
https://forum.arduino.cc/t/pid-with-simulated-heater-or-motor/1093539/5?u=davex
https://wokwi.com/projects/362627481524244481
I'm not sure of the canonical source, but I found a wokwi-chip implemented in https://wokwi.com/projects/381510614741899265
This is it's code, but it has an error in the ENB reading code:
- L298N.chip.c :
#include "wokwi-api.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct {
pin_t pin_out1;
pin_t pin_out2;
pin_t pin_out3;
pin_t pin_out4;
pin_t pin_IN1;
pin_t pin_IN2;
pin_t pin_IN3;
pin_t pin_IN4;
pin_t pin_ENA;
pin_t pin_ENB;
uint32_t Vs_attr;
} chip_state_t;
static void chip_pin_change(void *user_data, pin_t pin, uint32_t value);
void chip_init(void) {
chip_state_t *chip = malloc(sizeof(chip_state_t));
chip->pin_ENA = pin_init("EN A",INPUT);
chip->pin_ENB = pin_init("EN B",INPUT);
chip->pin_IN1 = pin_init("IN1",INPUT);
chip->pin_IN2 = pin_init("IN2",INPUT);
chip->pin_IN3 = pin_init("IN3",INPUT);
chip->pin_IN4 = pin_init("IN4",INPUT);
chip->pin_out1 = pin_init("OUT1",ANALOG);
chip->pin_out2 = pin_init("OUT2",ANALOG);
chip->pin_out3 = pin_init("OUT3",ANALOG);
chip->pin_out4 = pin_init("OUT4",ANALOG);
chip->Vs_attr = attr_init_float("Vs", 12.0);
const pin_watch_config_t watch_config = {
.edge = BOTH,
.pin_change = chip_pin_change,
.user_data = chip
};
pin_watch(chip->pin_ENA, &watch_config);
pin_watch(chip->pin_ENB, &watch_config);
pin_watch(chip->pin_IN1, &watch_config);
pin_watch(chip->pin_IN2, &watch_config);
pin_watch(chip->pin_IN3, &watch_config);
pin_watch(chip->pin_IN4, &watch_config);
}
void chip_pin_change(void *user_data, pin_t pin, uint32_t value) {
chip_state_t *chip = (chip_state_t*)user_data;
int ENA = pin_read(chip->pin_ENA);
int ENB = pin_read(chip->pin_ENA);
int IN1 = pin_read(chip->pin_IN1);
int IN2 = pin_read(chip->pin_IN2);
int IN3 = pin_read(chip->pin_IN3);
int IN4 = pin_read(chip->pin_IN4);
float Vs = attr_read_float(chip->Vs_attr);
// motor 1 control
if (IN1)
pin_dac_write(chip->pin_out1,ENA*Vs);
else
pin_write(chip->pin_out1,0);
if (IN2)
pin_dac_write(chip->pin_out2,ENA*Vs);
else
pin_write(chip->pin_out2,0);
//motor 2 control
if (IN3)
pin_dac_write(chip->pin_out3,ENB*Vs);
else
pin_write(chip->pin_out3,0);
if (IN4)
pin_dac_write(chip->pin_out4,ENB*Vs);
else
pin_write(chip->pin_out4,0);
}
- L298N.chip.json :
{
"name": "L298N ",
"author": "Carlos Arino",
"pins": [
"EN A",
"IN1",
"IN2",
"IN3",
"IN4",
"EN B",
"OUT1",
"OUT2",
"OUT3",
"OUT4",
"5V",
"GND"
],
"controls": [
{
"id": "Vs",
"label": "External Voltage (V)",
"type": "range",
"min": 0,
"max": 32,
"step": 1
}
]
}
and this bit of diagram.json:
{ "type": "chip-L298N", "id": "L298N_chip1", "top": -123.78, "left": 244.8, "attrs": {} }
I like the idea of a simple chip between a board and a stepper to highlight that the boards really shouldn't be directly connected to motor-sized loads.
Here is a sketch with a modified version:
https://wokwi.com/projects/386870492326611969
// See https://wokwi.com/projects/386870492326611969
// and https://github.com/wokwi/wokwi-features/issues/220
#include "wokwi-api.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct {
pin_t pin_out1;
pin_t pin_out2;
pin_t pin_out3;
pin_t pin_out4;
pin_t pin_IN1;
pin_t pin_IN2;
pin_t pin_IN3;
pin_t pin_IN4;
pin_t pin_ENA;
pin_t pin_ENB;
uint32_t Vs_attr;
} chip_state_t;
static void chip_pin_change(void *user_data, pin_t pin, uint32_t value);
void chip_init(void) {
chip_state_t *chip = malloc(sizeof(chip_state_t));
chip->pin_ENA = pin_init("EN A",INPUT);
chip->pin_ENB = pin_init("EN B",INPUT);
chip->pin_IN1 = pin_init("IN1",INPUT);
chip->pin_IN2 = pin_init("IN2",INPUT);
chip->pin_IN3 = pin_init("IN3",INPUT);
chip->pin_IN4 = pin_init("IN4",INPUT);
chip->pin_out1 = pin_init("OUT1",ANALOG);
chip->pin_out2 = pin_init("OUT2",ANALOG);
chip->pin_out3 = pin_init("OUT3",ANALOG);
chip->pin_out4 = pin_init("OUT4",ANALOG);
chip->Vs_attr = attr_init_float("Vs", 12.0);
const pin_watch_config_t watch_config = {
.edge = BOTH,
.pin_change = chip_pin_change,
.user_data = chip
};
pin_watch(chip->pin_ENA, &watch_config);
pin_watch(chip->pin_ENB, &watch_config);
pin_watch(chip->pin_IN1, &watch_config);
pin_watch(chip->pin_IN2, &watch_config);
pin_watch(chip->pin_IN3, &watch_config);
pin_watch(chip->pin_IN4, &watch_config);
}
void chip_pin_change(void *user_data, pin_t pin, uint32_t value) {
chip_state_t *chip = (chip_state_t*)user_data;
int ENA = pin_read(chip->pin_ENA);
int ENB = pin_read(chip->pin_ENB);
int IN1 = pin_read(chip->pin_IN1);
int IN2 = pin_read(chip->pin_IN2);
int IN3 = pin_read(chip->pin_IN3);
int IN4 = pin_read(chip->pin_IN4);
float Vs = attr_read_float(chip->Vs_attr);
// motor 1 control
if (IN1)
pin_dac_write(chip->pin_out1,ENA*Vs);
else
pin_write(chip->pin_out1,0);
if (IN2)
pin_dac_write(chip->pin_out2,ENA*Vs);
else
pin_write(chip->pin_out2,0);
//motor 2 control
if (IN3)
pin_dac_write(chip->pin_out3,ENB*Vs);
else
pin_write(chip->pin_out3,0);
if (IN4)
pin_dac_write(chip->pin_out4,ENB*Vs);
else
pin_write(chip->pin_out4,0);
}
{
"name": "L298N ",
"author": "Carlos Arino with mods by DaveX",
"doc":"See https://wokwi.com/projects/386870492326611969 and https://github.com/wokwi/wokwi-features/issues/220",
"pins": [
"EN A",
"IN1",
"IN2",
"IN3",
"IN4",
"EN B",
"",
"OUT4",
"OUT3",
"OUT2",
"OUT1",
"5V",
"GND"
],
"controls": [
{
"id": "Vs",
"label": "External Voltage (V)",
"type": "range",
"min": 0,
"max": 5,
"step": 1
}
]
}
I note that the analog outputs from this chip don't work as inputs to the wokwi bipolar stepper. For one thing, Arduino PWM fed into the inputs read in as 0 or 1023, and then the outputs are scaled to the motor voltage inputs. It might be better to convert it to all digital, since the actual part delivers combines the INx inputs with PWM on the ENA/ENB inputs to produce digital OUTx outputs.
Here's a sketch with a digital version
https://wokwi.com/projects/386822856593519617
// See https://wokwi.com/projects/386870492326611969
// and https://github.com/wokwi/wokwi-features/issues/220
#include "wokwi-api.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct {
pin_t pin_out1;
pin_t pin_out2;
pin_t pin_out3;
pin_t pin_out4;
pin_t pin_IN1;
pin_t pin_IN2;
pin_t pin_IN3;
pin_t pin_IN4;
pin_t pin_ENA;
pin_t pin_ENB;
uint32_t Vs_attr;
} chip_state_t;
static void chip_pin_change(void *user_data, pin_t pin, uint32_t value);
void chip_init(void) {
chip_state_t *chip = malloc(sizeof(chip_state_t));
chip->pin_ENA = pin_init("EN A",INPUT);
chip->pin_ENB = pin_init("EN B",INPUT);
chip->pin_IN1 = pin_init("IN1",INPUT);
chip->pin_IN2 = pin_init("IN2",INPUT);
chip->pin_IN3 = pin_init("IN3",INPUT);
chip->pin_IN4 = pin_init("IN4",INPUT);
chip->pin_out1 = pin_init("OUT1",OUTPUT);
chip->pin_out2 = pin_init("OUT2",OUTPUT);
chip->pin_out3 = pin_init("OUT3",OUTPUT);
chip->pin_out4 = pin_init("OUT4",OUTPUT);
chip->Vs_attr = attr_init_float("Vs", 12.0);
const pin_watch_config_t watch_config = {
.edge = BOTH,
.pin_change = chip_pin_change,
.user_data = chip
};
pin_watch(chip->pin_ENA, &watch_config);
pin_watch(chip->pin_ENB, &watch_config);
pin_watch(chip->pin_IN1, &watch_config);
pin_watch(chip->pin_IN2, &watch_config);
pin_watch(chip->pin_IN3, &watch_config);
pin_watch(chip->pin_IN4, &watch_config);
}
void chip_pin_change(void *user_data, pin_t pin, uint32_t value) {
chip_state_t *chip = (chip_state_t*)user_data;
int ENA = pin_read(chip->pin_ENA);
int ENB = pin_read(chip->pin_ENB);
int IN1 = pin_read(chip->pin_IN1);
int IN2 = pin_read(chip->pin_IN2);
int IN3 = pin_read(chip->pin_IN3);
int IN4 = pin_read(chip->pin_IN4);
float Vs = attr_read_float(chip->Vs_attr);
// motor 1 control
if (IN1)
pin_write(chip->pin_out1,ENA);
else
pin_write(chip->pin_out1,0);
if (IN2)
pin_write(chip->pin_out2,ENA);
else
pin_write(chip->pin_out2,0);
//motor 2 control
if (IN3)
pin_write(chip->pin_out3,ENB);
else
pin_write(chip->pin_out3,0);
if (IN4)
pin_write(chip->pin_out4,ENB);
else
pin_write(chip->pin_out4,0);
}
{
"name": "L298N ",
"author": "Carlos Arino with mods by DaveX",
"doc":"See https://wokwi.com/projects/386870492326611969 and https://github.com/wokwi/wokwi-features/issues/220",
"pins": [
"EN A",
"IN1",
"IN2",
"IN3",
"IN4",
"EN B",
"",
"GND",
"OUT4",
"OUT3",
"OUT2",
"OUT1",
"5V"
],
"controls": [
{
"id": "Vs",
"label": "External Voltage (V)",
"type": "range",
"min": 0,
"max": 5,
"step": 1
}
]
}
Add this to diagram.json to use it:
{
"type": "chip-L298N",
"id": "L298N_chip1",
"top": 317.82,
"left": 148.8,
"attrs": { "Vs": "5" }
},
After your very inspiring propositions, here's my take at it: a custom chip that emulates a full H-bridge (functionally similar to L298N), DC motor, and quadrature encoder assembly. Additionally, it provides a visual representation of the shaft position using the screen framebuffer API.
By interacting with the custom chip, you can introduce an external torque disturbance.
This custom chip might be useful for fine-tuning a position servo PID (example Arduino code).
https://wokwi.com/projects/388538078473492481