wokwi-features icon indicating copy to clipboard operation
wokwi-features copied to clipboard

DC motor driver L298n

Open gabbyshimoni opened this issue 4 years ago • 12 comments
trafficstars

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

gabbyshimoni avatar Oct 28 '21 07:10 gabbyshimoni

Yeah, I recommended 4 my teacher but need some dc motor and H bridge to simulate robots/cars

RC0D3 avatar May 24 '22 21:05 RC0D3

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)

M-square avatar Jun 03 '22 12:06 M-square

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?

urish avatar Jun 06 '22 10:06 urish

"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:

  1. Direct from a pin, PWM or not, other motor pin to GND
  2. Inverse: the other motor side is to +5V instead, ie the Arduino pin sinks current (PWM acts inverted)
  3. Two pins so both directions are possible, one pin controls the motor, the other is set to HIGH or LOW as a powersupply.
  4. Through the L298n
  5. 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 😈

M-square avatar Jun 06 '22 12:06 M-square

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) !!.........

Sreedharbot avatar Jul 28 '22 18:07 Sreedharbot

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.

urish avatar Aug 15 '22 10:08 urish

Hey @urish, so far, i'm figuring out.. and the code is half in progress..

Sreedharbot avatar Aug 15 '22 18:08 Sreedharbot

"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

drf5n avatar Jan 13 '24 16:01 drf5n

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.

drf5n avatar Jan 13 '24 20:01 drf5n

Here is a sketch with a modified version:

https://wokwi.com/projects/386870492326611969

image
// 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.

drf5n avatar Jan 14 '24 05:01 drf5n

Here's a sketch with a digital version

https://wokwi.com/projects/386822856593519617

image
// 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" }
    },

drf5n avatar Jan 14 '24 16:01 drf5n

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

image

DIYEmbeddedSystems avatar May 21 '24 14:05 DIYEmbeddedSystems