I built a Micromouse but the motors wont have the same speed. I use arduino UNO and the Motordriver L298N. I use the "Joy-it com-Motor01 Getriebemotor" Motors. Can anyone please help me regulate the speed of these motors? I got everthing else done only the speed of the motors. So please if someone is able to help me with the code Id be really thankful.
Post your code using code tags <CODE>
Welcome to the Arduino forum. I don't know what a micromouse is, but I guess something with two motors and each motor has a wheel.
No one can help you with code if they can't see your code. But, why do you think code is the problem? A quick test is to switch the wires from one motor to the other motor and see if the speed difference is now the opposite.
<
#include <SharpIR.h>
#include <PID_v1_bc.h>
//======================= Pin Secton =======================//
// Define model and input pin:
#define IRPinVorne A0
#define IRPinRechts A1
#define IRPinLinks A2
// Encoder Pins
#define EncoderpinRechts 3 // encoder 1
#define EncoderpinLinks 2 // encoder 2
// Create a new instance of the SharpIR class:
SharpIR sensorVorne = SharpIR(SharpIR::GP2Y0A21YK0F, IRPinVorne);
SharpIR sensorRechts = SharpIR(SharpIR::GP2Y0A21YK0F, IRPinRechts);
SharpIR sensorLinks = SharpIR(SharpIR::GP2Y0A21YK0F, IRPinLinks);
// Motor Rechts Pins
int MotorRechtsEnable = 9; // EnA
int MotorRechtsRueckwaerts = 7; // in1
int MotorRechtsVorwaerts = 8; // in2
// Motor Links Pins
int MotorLinksEnable = 11; // EnB
int MotorLinksVorwaerts = 12; // in3
int MotorLinksRueckwaerts = 13; // in4
bool Zielerreicht = false;
//======================= Value Secton =======================//
enum motion {
VORWAERTS, RUECKWAERTS, STOP, SOLID };
enum moveDirection {
VorwartsFahren, RechtsDrehen, LinksDrehen };
enum motorName {
MOTORLINKS, MOTORRECHTS };
// Variable für Motoren
#define PWMRechtesMotors 150
#define PWMLinkesMotors 150
// Variable für Sensoren
#define mindAbstandRechts 20
#define mindAbstandLinks 20
#define mindAbstandVorne 20
#define InkrementeDrehen 25
#define InkrementeFahren 38
// #define InkrementeUmkehren (InkrementeDrehen*2)
int distanceVorne = 0;
int distanceRechts = 0;
int distanceLinks = 0;
bool wandVorne = false;
bool wandRechts = false;
bool wandLinks = false;
// Variable für Encoder
bool encoderUpdate = true;
int encodercntRechts = 0; //LINKS
int encodercntLinks = 0; //RECHTS
volatile unsigned long lastDebounceTimeEncoderLinks = 0; // Zeitstempel für die letzte Tasteränderung
volatile unsigned long lastDebounceTimeEncoderRechts = 0; // Zeitstempel für die letzte Tasteränderung
const unsigned long debounceDelay = 5; // Entprellungszeit in Millisekunden
volatile unsigned long tempTimeFourteenInkrement = 0;
//Regelparameter
// float Kp = 30; // Proportionaler Verstärkungsfaktor
//======================= Setup Secton =======================//
void setup() {
Serial.begin(9600);
Serial.println("Starting!");
pinMode(IRPinVorne, INPUT);
pinMode(IRPinRechts, INPUT);
pinMode(IRPinLinks, INPUT);
// rechter Motor
pinMode(MotorRechtsEnable, OUTPUT);
pinMode(MotorRechtsVorwaerts, OUTPUT);
pinMode(MotorRechtsRueckwaerts, OUTPUT);
// Linker Motor
pinMode(MotorLinksEnable, OUTPUT);
pinMode(MotorLinksVorwaerts, OUTPUT);
pinMode(MotorLinksRueckwaerts, OUTPUT);
// Encoder als Interrupt
pinMode(EncoderpinRechts, INPUT_PULLUP);
pinMode(EncoderpinLinks, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EncoderpinRechts), inkrementEncoderRechts, CHANGE );
attachInterrupt(digitalPinToInterrupt(EncoderpinLinks), inkrementEncoderLinks, CHANGE );
Serial.println("Setup Done!");
delay(2000);
}
//======================= Function Secton : encoder =======================//
void inkrementEncoderRechts() {
unsigned long currentTime = millis(); // Aktuelle Zeit erfassen
if ((currentTime - lastDebounceTimeEncoderRechts) > debounceDelay) { // Überprüfen, ob die Entprellungszeit vergangen ist
encodercntRechts++;
lastDebounceTimeEncoderRechts = currentTime; // Zeitstempel aktualisieren
}
if (encodercntRechts % 40 == 0){
Serial.println(currentTime - tempTimeFourteenInkrement);
tempTimeFourteenInkrement = currentTime;
}
// encodercntRechts++;
//encoderUpdate = true;
//printEncoder();
//todo check overflow
}
void inkrementEncoderLinks() {
unsigned long currentTime = millis(); // Aktuelle Zeit erfassen
if ((currentTime - lastDebounceTimeEncoderLinks) > debounceDelay) { // Überprüfen, ob die Entprellungszeit vergangen ist
encodercntLinks++;
lastDebounceTimeEncoderLinks = currentTime; // Zeitstempel aktualisieren
}
if (encodercntLinks % 40 == 0){
Serial.println(currentTime - tempTimeFourteenInkrement);
tempTimeFourteenInkrement = currentTime;
}
//encodercntLinks++;
//encoderUpdate = true;
//printEncoder();
//todo check overflow
}
void printEncoder() {
Serial.print("Encoder Rechts: ");
Serial.print(encodercntRechts);
Serial.print(" Encoder Links: ");
Serial.println(encodercntLinks);
}
//======================= Function Secton : sensor =======================//
void messenVorne() {
distanceVorne = sensorVorne.getDistance(false);
// Serial.print("Mean distance Vorne: ");
// Serial.print(distanceVorne);
// Serial.println(" cm");
}
void messenRechts() {
distanceRechts = sensorRechts.getDistance(false);
// Serial.print("Mean distance Rechts: ");
// Serial.print(distanceRechts);
// Serial.println(" cm");
}
void messenLinks() {
distanceLinks = sensorLinks.getDistance(false);
// Serial.print("Mean distance Links: ");
// Serial.print(distanceLinks);
// Serial.println(" cm");
}
void CheckWalls() {
messenVorne();
messenRechts();
messenLinks();
if (distanceRechts < 15) {
wandRechts = true;
} else {
wandRechts = false;
}
if (distanceVorne < 15) {
wandVorne = true;
} else {
wandVorne = false;
}
if (distanceLinks < 15) {
wandLinks = true;
} else {
wandLinks = false;
}
}
void printWalls() {
Serial.print("Wand Vorne: ");
Serial.print(wandVorne);
Serial.print(" distanz: ");
Serial.print(distanceVorne);
Serial.print(" cm");
Serial.print(" Wand Rechts: ");
Serial.print(wandRechts);
Serial.print(" distanz: ");
Serial.print(distanceRechts);
Serial.print(" cm");
Serial.print(" Wand Links: ");
Serial.print(wandLinks);
Serial.print(" distanz: ");
Serial.print(distanceLinks);
Serial.println(" cm");
}
//======================= Function Secton : motor =======================//
void motorControl(enum motorName motor, int pwmValue, enum motion motion) {
if (motor == MOTORLINKS) {
switch (motion) {
case VORWAERTS:
digitalWrite(MotorLinksRueckwaerts, LOW);
digitalWrite(MotorLinksVorwaerts, HIGH);
break;
case RUECKWAERTS:
digitalWrite(MotorLinksRueckwaerts, HIGH);
digitalWrite(MotorLinksVorwaerts, LOW);
break;
case STOP:
digitalWrite(MotorLinksRueckwaerts, LOW);
digitalWrite(MotorLinksVorwaerts, LOW);
// digitalWrite(MotorLinksRueckwaerts, HIGH);
// digitalWrite(MotorLinksVorwaerts, HIGH);
break;
case SOLID:
// do nothing
break;
}
analogWrite(MotorLinksEnable, pwmValue);
} else if (motor == MOTORRECHTS) {
switch (motion) {
case VORWAERTS:
digitalWrite(MotorRechtsRueckwaerts, LOW);
digitalWrite(MotorRechtsVorwaerts, HIGH);
break;
case RUECKWAERTS:
digitalWrite(MotorRechtsRueckwaerts, HIGH);
digitalWrite(MotorRechtsVorwaerts, LOW);
break;
case STOP:
digitalWrite(MotorRechtsRueckwaerts, LOW);
digitalWrite(MotorRechtsVorwaerts, LOW);
// digitalWrite(MotorRechtsRueckwaerts, HIGH);
// digitalWrite(MotorRechtsVorwaerts, HIGH);
break;
case SOLID:
// do nothing
break;
}
analogWrite(MotorRechtsEnable, pwmValue);
}
}
void RobotStoppen() {
motorControl(MOTORRECHTS, 0, STOP);
motorControl(MOTORLINKS, 0, STOP);
}
void RobotMoveStep(enum moveDirection direction, int stepsToMove) {
int tempEncodercntRechts = encodercntRechts;
int tempEncodercntLinks = encodercntLinks;
switch (direction) {
case VorwartsFahren:
motorControl(MOTORRECHTS, PWMRechtesMotors, VORWAERTS);
motorControl(MOTORLINKS, PWMLinkesMotors, VORWAERTS);
break;
case RechtsDrehen:
motorControl(MOTORRECHTS, PWMRechtesMotors, RUECKWAERTS);
motorControl(MOTORLINKS, PWMLinkesMotors, VORWAERTS);
break;
case LinksDrehen:
motorControl(MOTORRECHTS, PWMRechtesMotors, VORWAERTS);
motorControl(MOTORLINKS, PWMLinkesMotors, RUECKWAERTS);
break;
}
int error = 0;
int adjustment = 0;
int pwmLeft = PWMLinkesMotors;
while( (encodercntRechts - tempEncodercntRechts) < stepsToMove || (encodercntLinks - tempEncodercntLinks) < stepsToMove ){
// error = (encodercntRechts - tempEncodercntRechts) - (encodercntLinks - tempEncodercntLinks);
// adjustment = Kp * error;
// pwmLeft = constrain(PWMLinkesMotors + adjustment, 0, 255);
// motorControl(MOTORLINKS, pwmLeft, SOLID);
if((encodercntRechts - tempEncodercntRechts) >= stepsToMove){ // if I comment this the right motor works, if I dont it doesnt
motorControl(MOTORRECHTS, 0, STOP);
Serial.println("Rechter Motor fertig mit einem Step ");
}
if((encodercntLinks - tempEncodercntLinks) >= stepsToMove){
motorControl(MOTORLINKS, 0, STOP);
Serial.println("Linker Motor fertig mit einem Step ");
}
Serial.print(" rechter Encoder: ");
Serial.print(encodercntRechts - tempEncodercntRechts);
Serial.print(" linker Encoder: ");
Serial.println(encodercntLinks - tempEncodercntLinks);
}
Serial.println("Beide Motoren fertig mit einem Step ");
RobotStoppen();
}
// //======================= Logic Secton =======================//
void LabyrinthLoesen (){ //this function ist done, dont look at this
while(Zielerreicht == false){
CheckWalls();
if(wandRechts == false){
RobotMoveStep(RechtsDrehen, InkrementeDrehen);
delay (100);
RobotMoveStep(VorwartsFahren, InkrementeFahren);
}
else if(wandVorne == false){
RobotMoveStep(VorwartsFahren, InkrementeFahren);
}
else if(wandLinks == false){
RobotMoveStep(LinksDrehen, InkrementeDrehen);
delay (100);
RobotMoveStep(VorwartsFahren, InkrementeFahren);
}
else {
RobotMoveStep(RechtsDrehen, InkrementeDrehen*2); // 2x turnright
delay (100);
RobotMoveStep(VorwartsFahren, InkrementeFahren);
}
delay (100);
}
}
//======================= Main Secton =======================//
void loop() {
// LabyrinthLoesen ();
// if(encoderUpdate){
// printEncoder();
// // encoderUpdate = false;
// // }
// delay(1000);
//motorControl(MOTORRECHTS, PWMRechtesMotors, VORWAERTS); //right motor forward
motorControl(MOTORLINKS, PWMLinkesMotors, VORWAERTS); //Left Motor forward
// RobotMoveStep(VorwartsFahren, InkrementeFahren); //both motors forward
delay(2000);
// RobotMoveStep(RechtsDrehen, 20);
// delay(1000);
// RobotMoveStep(LinksDrehen, 20);
// delay(1000);
// RobotStoppen();
// CheckWalls();
// printWalls();
}
Like this?
I tried to upload it can u see it?
No
In the IDE on the Menu bar click on Edit then click on Copy for Forum.
Then just paste your code here
#include <PID_v1_bc.h>
#include <SharpIR.h>
//======================= Pin Secton =======================//
// Define model and input pin:
#define IRPinVorne A0
#define IRPinRechts A1
#define IRPinLinks A2
// Encoder Pins
#define EncoderpinRechts 3 // encoder 1
#define EncoderpinLinks 2 // encoder 2
// Create a new instance of the SharpIR class:
SharpIR sensorVorne = SharpIR(SharpIR::GP2Y0A21YK0F, IRPinVorne);
SharpIR sensorRechts = SharpIR(SharpIR::GP2Y0A21YK0F, IRPinRechts);
SharpIR sensorLinks = SharpIR(SharpIR::GP2Y0A21YK0F, IRPinLinks);
// Motor Rechts Pins
int MotorRechtsEnable = 9; // EnA
int MotorRechtsRueckwaerts = 7; // in1
int MotorRechtsVorwaerts = 8; // in2
// Motor Links Pins
int MotorLinksEnable = 11; // EnB
int MotorLinksVorwaerts = 12; // in3
int MotorLinksRueckwaerts = 13; // in4
bool Zielerreicht = false;
//======================= Value Secton =======================//
enum motion {
VORWAERTS,
RUECKWAERTS,
STOP,
SOLID
};
enum moveDirection {
VorwartsFahren,
RechtsDrehen,
LinksDrehen
};
enum motorName {
MOTORLINKS,
MOTORRECHTS
};
// Variable für Motoren
int PWMRechtesMotors = 100;
int PWMLinkesMotors = 100;
// Variable für Sensoren
#define mindAbstandRechts 20
#define mindAbstandLinks 20
#define mindAbstandVorne 20
#define InkrementeDrehen 250
#define InkrementeFahren 250
// #define InkrementeUmkehren (InkrementeDrehen*2)
int distanceVorne = 0;
int distanceRechts = 0;
int distanceLinks = 0;
bool wandVorne = false;
bool wandRechts = false;
bool wandLinks = false;
// Variable für Encoder
bool encoderUpdate = true;
volatile int encodercntRechts = 0; //LINKS
volatile int encodercntLinks = 0; //RECHTS
const int incrementsPerRevolution = 40;
volatile unsigned long lastDebounceTimeEncoderLinks = 0; // Zeitstempel für die letzte Tasteränderung
volatile unsigned long lastDebounceTimeEncoderRechts = 0; // Zeitstempel für die letzte Tasteränderung
const unsigned long debounceDelay = 2; // Entprellungszeit in Millisekunden
// PID Variablen für Motoren
double SetpointRechts, InputRechts, OutputRechts;
double SetpointLinks, InputLinks, OutputLinks;
// Regelparameter
float Kp = 5.0, Ki = 1.5, Kd = 0.0; // PID-Parameter
unsigned long lastTime = 0;
const unsigned long sampleTime = 100; // Abtastzeit in Millisekunden
// PID-Regler für Motoren
PID myPIDRechts(&InputRechts, &OutputRechts, &SetpointRechts, Kp, Ki, Kd, DIRECT);
PID myPIDLinks(&InputLinks, &OutputLinks, &SetpointLinks, Kp, Ki, Kd, DIRECT);
//======================= Setup Secton =======================//
void setup() {
Serial.begin(9600);
Serial.println("Starting!");
pinMode(IRPinVorne, INPUT);
pinMode(IRPinRechts, INPUT);
pinMode(IRPinLinks, INPUT);
// rechter Motor
pinMode(MotorRechtsEnable, OUTPUT);
pinMode(MotorRechtsVorwaerts, OUTPUT);
pinMode(MotorRechtsRueckwaerts, OUTPUT);
// Linker Motor
pinMode(MotorLinksEnable, OUTPUT);
pinMode(MotorLinksVorwaerts, OUTPUT);
pinMode(MotorLinksRueckwaerts, OUTPUT);
// Encoder als Interrupt
pinMode(EncoderpinRechts, INPUT_PULLUP);
pinMode(EncoderpinLinks, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EncoderpinRechts), inkrementEncoderRechts, CHANGE);
attachInterrupt(digitalPinToInterrupt(EncoderpinLinks), inkrementEncoderLinks, CHANGE);
// PID-Regler initialisieren
SetpointRechts = 150.0 / 255.0 * 210.0 + 90.0; // Zielwert für Motor 1 basierend auf PWM 150
SetpointLinks = 150.0 / 255.0 * 210.0 + 90.0; // Zielwert für Motor 2 basierend auf PWM 150
myPIDRechts.SetMode(AUTOMATIC);
myPIDRechts.SetOutputLimits(0, 255);
myPIDLinks.SetMode(AUTOMATIC);
myPIDLinks.SetOutputLimits(0, 255);
Serial.println("Setup Done!");
delay(2000);
}
//======================= Function Secton : encoder =======================//
void inkrementEncoderRechts() {
unsigned long currentTime = millis(); // Aktuelle Zeit erfassen
if ((currentTime - lastDebounceTimeEncoderRechts) > debounceDelay) { // Überprüfen, ob die Entprellungszeit vergangen ist
encodercntRechts++;
lastDebounceTimeEncoderRechts = currentTime; // Zeitstempel aktualisieren
}
}
void inkrementEncoderLinks() {
unsigned long currentTime = millis(); // Aktuelle Zeit erfassen
if ((currentTime - lastDebounceTimeEncoderLinks) > debounceDelay) { // Überprüfen, ob die Entprellungszeit vergangen ist
encodercntLinks++;
lastDebounceTimeEncoderLinks = currentTime; // Zeitstempel aktualisieren
}
}
void printEncoder() {
Serial.print("Encoder Rechts: ");
Serial.print(encodercntRechts);
Serial.print(" Encoder Links: ");
Serial.println(encodercntLinks);
}
//======================= Function Secton : sensor =======================//
void messenVorne() {
distanceVorne = sensorVorne.getDistance(false);
}
void messenRechts() {
distanceRechts = sensorRechts.getDistance(false);
}
void messenLinks() {
distanceLinks = sensorLinks.getDistance(false);
}
void CheckWalls() {
messenVorne();
messenRechts();
messenLinks();
wandRechts = distanceRechts < 15;
wandVorne = distanceVorne < 15;
wandLinks = distanceLinks < 15;
}
void printWalls() {
Serial.print("Wand Vorne: ");
Serial.print(wandVorne);
Serial.print(" distanz: ");
Serial.print(distanceVorne);
Serial.print(" cm");
Serial.print(" Wand Rechts: ");
Serial.print(wandRechts);
Serial.print(" distanz: ");
Serial.print(distanceRechts);
Serial.print(" cm");
Serial.print(" Wand Links: ");
Serial.print(wandLinks);
Serial.print(" distanz: ");
Serial.print(distanceLinks);
Serial.println(" cm");
}
//======================= Function Secton : motor =======================//
void motorControl(enum motorName motor, int pwmValue, enum motion motion) {
if (motor == MOTORLINKS) {
switch (motion) {
case VORWAERTS:
digitalWrite(MotorLinksRueckwaerts, LOW);
digitalWrite(MotorLinksVorwaerts, HIGH);
break;
case RUECKWAERTS:
digitalWrite(MotorLinksRueckwaerts, HIGH);
digitalWrite(MotorLinksVorwaerts, LOW);
break;
case STOP:
digitalWrite(MotorLinksRueckwaerts, LOW);
digitalWrite(MotorLinksVorwaerts, LOW);
break;
case SOLID:
// do nothing
break;
}
analogWrite(MotorLinksEnable, pwmValue);
} else if (motor == MOTORRECHTS) {
switch (motion) {
case VORWAERTS:
digitalWrite(MotorRechtsRueckwaerts, LOW);
digitalWrite(MotorRechtsVorwaerts, HIGH);
break;
case RUECKWAERTS:
digitalWrite(MotorRechtsRueckwaerts, HIGH);
digitalWrite(MotorRechtsVorwaerts, LOW);
break;
case STOP:
digitalWrite(MotorRechtsRueckwaerts, LOW);
digitalWrite(MotorRechtsVorwaerts, LOW);
break;
case SOLID:
// do nothing
break;
}
analogWrite(MotorRechtsEnable, pwmValue);
}
}
void RobotStoppen() {
motorControl(MOTORRECHTS, 0, STOP);
motorControl(MOTORLINKS, 0, STOP);
}
void RobotMoveStep(enum moveDirection direction, int stepsToMove) {
int tempEncodercntRechts = encodercntRechts;
int tempEncodercntLinks = encodercntLinks;
switch (direction) {
case VorwartsFahren:
motorControl(MOTORRECHTS, PWMRechtesMotors, VORWAERTS);
motorControl(MOTORLINKS, PWMLinkesMotors, VORWAERTS);
break;
case RechtsDrehen:
motorControl(MOTORRECHTS, PWMRechtesMotors, RUECKWAERTS);
motorControl(MOTORLINKS, PWMLinkesMotors, VORWAERTS);
break;
case LinksDrehen:
motorControl(MOTORRECHTS, PWMRechtesMotors, VORWAERTS);
motorControl(MOTORLINKS, PWMLinkesMotors, RUECKWAERTS);
break;
}
while ((encodercntRechts - tempEncodercntRechts) < stepsToMove || (encodercntLinks - tempEncodercntLinks) < stepsToMove) {
unsigned long currentTime = millis();
if (currentTime - lastTime >= sampleTime) {
// Drehzahl berechnen
double timeIntervalInMinutes = sampleTime / 60000.0; // Zeitintervall in Minuten
InputRechts = (encodercntRechts - tempEncodercntRechts / (double)incrementsPerRevolution) / timeIntervalInMinutes; // RPM
InputLinks = (encodercntLinks - tempEncodercntLinks / (double)incrementsPerRevolution) / timeIntervalInMinutes; // RPM
// PID-Berechnung durchführen
myPIDRechts.Compute();
// Synchronisieren der Drehzahl
double error = (double)(encodercntRechts - encodercntLinks) / incrementsPerRevolution;
SetpointLinks = SetpointRechts - error * SetpointRechts;
myPIDLinks.Compute();
// Motoren steuern
motorControl(MOTORRECHTS, OutputRechts, SOLID);
motorControl(MOTORLINKS, OutputLinks, SOLID);
// Debugging-Informationen
lastTime = currentTime;
tempEncodercntRechts = encodercntRechts;
tempEncodercntLinks = encodercntLinks;
} else {
delay(10);
}
Serial.print("Motor Rechts - Input: ");
Serial.print(InputRechts);
Serial.print(" Output: ");
Serial.print(OutputRechts);
Serial.print(" Setpoint: ");
Serial.println(SetpointRechts);
Serial.print("Motor Links - Input: ");
Serial.print(InputLinks);
Serial.print(" Output: ");
Serial.print(OutputLinks);
Serial.print(" Setpoint: ");
Serial.println(SetpointLinks);
}
Serial.println("Beide Motoren fertig mit einem Step ");
Serial.println("stop");
RobotStoppen();
}
//======================= Logic Secton =======================//
void LabyrinthLoesen() {
while (Zielerreicht == false) {
CheckWalls();
if (wandRechts == false) {
RobotMoveStep(RechtsDrehen, InkrementeDrehen);
delay(100);
RobotMoveStep(VorwartsFahren, InkrementeFahren);
} else if (wandVorne == false) {
RobotMoveStep(VorwartsFahren, InkrementeFahren);
} else if (wandLinks == false) {
RobotMoveStep(LinksDrehen, InkrementeDrehen);
delay(100);
RobotMoveStep(VorwartsFahren, InkrementeFahren);
} else {
RobotMoveStep(RechtsDrehen, InkrementeDrehen * 2); // 2x RechtDrehen
delay(100);
RobotMoveStep(VorwartsFahren, InkrementeFahren);
}
delay(100);
}
}
//======================= Main Secton =======================//
void loop() {
RobotMoveStep(VorwartsFahren, InkrementeFahren);
delay(2000);
}
I did it I think
Yes, much bettor
I see you are using PID and I am not an expert in that area.
Yes I do try it...
What speed are they and what speed do you want them to be? Is this for a differential (skid) steering type wheeled robot?
Its just important that they are on the same speed. I dont know its just some basic motors: Joy-IT Getriebemotor (3-9V) inkl. Rad.
Is your project designed so you have totally separate control of the speed of each motor? How different are the speeds in RPM? How different in percent? How much will the fast motor need to be slowed down to match the other motor? Is the difference in speed always the same?
Yes I can seperatly give them speed. Id say like the one is 30% - 40% slower.
The difference is not always the same
Are you running totally separate PID code for each motor?