I tried implamenting your code hacked together from the other code but u cant get the motor to rotate and the serial monitor just keeps repeating "0" after "start"
#include <util/atomic.h> // For the ATOMIC_BLOCK macro
#define ENCA 18 // YELLOW
#define ENCB 19 // WHITE
#define PWM 3
#define IN2 2
#define IN1 4
int pwm;
int in1;
int in2;
volatile unsigned long count = 0;
unsigned long copyCount = 0;
unsigned long lastRead = 0;
unsigned long interval = 1000;//one second
void setup()
{
Serial.begin(115200);
Serial.println("start...");
pinMode(PWM,OUTPUT);
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
//interrupt on pin3
pinMode(3,INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(3),isrCount,RISING);
}
void loop()
{
digitalWrite(in1,HIGH);
digitalWrite(in2,LOW);
analogWrite(pwm,255);
if (millis() - lastRead >= interval) //read interrupt count every second
{
lastRead += interval;
// disable interrupts,make copy of count,reenable interrupts
noInterrupts();
copyCount = count;
count = 0;
interrupts();
//use copyCount for all calulations and actions in loop
Serial.println(copyCount);
}
}
void isrCount()
{
count++;
}
Yes, with gearing of 478:1 that's 12 pulses per revolution of the motor with the quadrature encoder reading algorithm which only triggers on one edge of one pulse.
I think 12 is a standard count for many of the common gear motors.
Are you saying that you get the motor to turn in your earlier code with this, analogWrite(pwm,100);
but not in the version you posted?
The motor turning or not should not be dependent upon the encoder reading. If the test code you just posted does not turn the motor, can you post the code which does.
this is the current code I'm running to do the tests, its based off the tutorial with changes to the pins for the mega as well as some of the changes that i have been talking to DaveX with. It has a lot of unnecessary stuff in it, I'm trying to widdle a code down to bare bones, one direction of rotation with a fixed repeatable distance.
the motor also seams to be rotating really slow cause in the description of the motor when i bought it said i should be able to get10rpm out of it.
#include <util/atomic.h> // For the ATOMIC_BLOCK macro
#define ENCA 18 // YELLOW
#define ENCB 19 // WHITE
#define PWM 3
#define IN2 2
#define IN1 4
volatile int posi = 0; // specify posi as volatile: https://www.arduino.cc/reference/en/language/variables/variable-scope-qualifiers/volatile/
long prevT = 0;
float eprev = 0;
float eintegral = 0;
void setup() {
Serial.begin(9600);
pinMode(ENCA,INPUT);
pinMode(ENCB,INPUT);
attachInterrupt(digitalPinToInterrupt(ENCA),readEncoder,RISING);
pinMode(PWM,OUTPUT);
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
Serial.println("target pos");
}
void loop() {
// set target position
int target = 5736;
//int target = 6000*sin(1.0* prevT/1e6);
// PID constants
float kp = 1;
float kd = 0.025;
float ki = 0.0;
// time difference
long currT = micros();
float deltaT = ((float) (currT - prevT))/( 1.0e6 );
prevT = currT;
// Read the position in an atomic block to avoid a potential
// misread if the interrupt coincides with this code running
// see: https://www.arduino.cc/reference/en/language/variables/variable-scope-qualifiers/volatile/
int pos = 0;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
pos = posi;
}
// error
int e = pos - target;
// derivative
float dedt = (e-eprev)/(deltaT);
// integral
eintegral = eintegral + e*deltaT;
// control signal
float u = kp*e + kd*dedt + ki*eintegral;
// motor power
int pwr = 255 ;
// motor direction
int dir = 1;
if(u<0){
dir = -1;
}
// signal the motor
setMotor(dir,pwr,PWM,IN1,IN2);
// store previous error
eprev = e;
Serial.print(target);
Serial.print(" ");
Serial.print(pos);
Serial.println();
}
void setMotor(int dir, int pwmVal, int pwm, int in1, int in2){
analogWrite(pwm,pwmVal);
if(dir == 1){
digitalWrite(in1,HIGH);
digitalWrite(in2,LOW);
}
else if(dir == -1){
digitalWrite(in1,LOW);
digitalWrite(in2,HIGH);
}
else{
digitalWrite(in1,LOW);
digitalWrite(in2,LOW);
}
}
void readEncoder(){
int b = digitalRead(ENCB);
if(b > 0){
posi++;
}
else{
posi--;
}
}
int target = 5736*sin(2.0*3.14154/90/2 * prevT/1e6);
Should scan back and forth 1 revolution every 180 seconds.
Still, setting a moving target with the sin is a bit of a distraction.
To move the target an angle, pause for a time, and repeat, you could add something like this completely untested code:
// timing and configuration variables:
static unsigned long lastPosMs = 0;
static bool pausingInPosition = false;
const unsigned long pauseInterval = 1000UL *60;
const int advanceAngle = 37.5; // degrees
...
// oneshot for reaching position:
if (!pausingInPosition && target == pos){
pausingInPosition = true;
lastPauseMs = millis();
//... any other things to do once, you reach position
}
//
if (pausingInPosition &&
millis() - lastPosMs >= pauseInterval){
// finished pausing
target = target + 5736* advanceAngle/360; // advance
pausingInPosition = false;
}
}
if(pausingInPosition){
; // other actions to do repeatedly while paused
}
Non-blocking state-machine wise, target,pospausingInPosition and (millis() - lastPosMs) would be your state variables, and loop should run pretty quick.
Oh, with
it doesn't look like you are using the PID. Maybe that's why it felt like it was doing something when it stopped. You might consider:
int pwr = abs(constrain(u,-255,255)) ;
which would work with the PID code to taper power down when you get close to target.
If you periodically increase target by 5736, you should get periodic turns.
One issue is that you are using nice non-blocking code, as in BlinkWithoutDelay, which runs through loop() very quickly to update the PID, direction, and other things. Adding a delay() or a for loop would break that, so you need to have some event like a button press or timer that says when to start another turn.
My untested code in Programing motor with encoder - #33 by DaveX was trying to run a 1/4 turn, then pause, then cycle again. You could increase change the advanceAngle to 360 and the pauseInterval to 3600UL*1000 to make it full turns an hour apart.
Hmm. It looked like the working code was pwr=255 and dir=-1/1. I wonder what the u from your PID is giving you? With kp = 1 and target = 5376, it should be u=5376, and then with the pwr = abs(constrain(...)) it should be 255 until you are within 17 degrees of a full rotation.
I have the L298N hooked directly to a 12v power supply, I don't have the software to do schematics and I can't really buy or download random software because its a work computer
The intentions is to get the code down to something that as clean as possible, but I couldn't get the code from #29 to work. That's why I have ben using the other one because its from the tutorial
I believe the tutorial hade pwr=100 but I found somewhere that you can put pwr = (anywhere between 0-255) so i switched it to 255 thinking it would make the motor faster