I was making an attempt to use the arduino PID library:
https://github.com/br3ttb/Arduino-PID-Library
i build a setup with first an arduino and then same setup with a stm32f1c8.
Arduino code:
#include <PID_v1.h>
#define MotEnable 9 //Motor Enamble pin Runs on PWM signal
#define MotFwd 6 // Motor Forward pin
#define MotRev 7 // Motor Reverse pin
String readString; //This while store the user input data
int User_Input = 0; // This while convert input string into integer
int encoderPin1 = 2; //Encoder Output 'A' must connected with intreput pin of arduino.
int encoderPin2 = 3; //Encoder Otput 'B' must connected with intreput pin of arduino.
volatile int lastEncoded = 0; // Here updated value of encoder store.
volatile long encoderValue = 0; // Raw encoder value
int PPR = 2400; // Encoder Pulse per revolution.
int angle = 360; // Maximum degree of motion.
int REV = 0; // Set point REQUIRED ENCODER VALUE
int lastMSB = 0;
int lastLSB = 0;
double kp = 4 , ki = 0 , kd = 1; // modify for optimal performance
double input = 0, output = 0, setpoint = 0;
PID myPID(&input, &output, &setpoint, kp, ki, kd, DIRECT);
void setup() {
pinMode(MotEnable, OUTPUT);
pinMode(MotFwd, OUTPUT);
pinMode(MotRev, OUTPUT);
Serial.begin(9600); //initialize serial comunication
pinMode(encoderPin1, INPUT_PULLUP);
pinMode(encoderPin2, INPUT_PULLUP);
digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
digitalWrite(encoderPin2, HIGH); //turn pullup resistor on
//call updateEncoder() when any high/low changed seen
//on interrupt 0 (pin 2), or interrupt 1 (pin 3)
attachInterrupt(0, updateEncoder, CHANGE);
attachInterrupt(1, updateEncoder, CHANGE);
//TCCR1B = TCCR1B & 0b11111000 | 1; // set 31KHz PWM to prevent motor noise
myPID.SetMode(AUTOMATIC); //set PID in Auto mode
myPID.SetSampleTime(1); // refresh rate of PID controller
myPID.SetOutputLimits(-250, 250); // this is the MAX PWM value to move motor, here change in value reflect change in speed of motor.
}//end setup
void loop() {
while (Serial.available()) { //Check if the serial data is available.
delay(3); // a small delay
char c = Serial.read(); // storing input data
readString += c; // accumulate each of the characters in readString
}
if (readString.length() >0) { //Verify that the variable contains information
Serial.println(readString.toInt()); //printing the input data in integer form
User_Input = readString.toInt(); // here input data is store in integer form
}
/*
if( input<5){
User_Input = 360;
}
if(input > 2350){
User_Input = 0;
}
*/
REV = map (User_Input, 0, angle, 0, PPR); // mapping degree into pulse
setpoint = REV; //PID while work to achive this value consider as SET value
input = encoderValue ; // data from encoder consider as a Process value
//myPID.Compute(); // calculate new output
//pwmOut(output);
Serial.print(" enc: ");
Serial.println(input);
}//end loop
void pwmOut(int out) {
if (out > 0) { // if REV > encoderValue motor move in forward direction.
analogWrite(MotEnable, out); // Enabling motor enable pin to reach the desire angle
forward(); // calling motor to move forward
}
else {
analogWrite(MotEnable, abs(out)); // if REV < encoderValue motor move in forward direction.
reverse(); // calling motor to move reverse
}
readString=""; // Cleaning User input, ready for new Input
}//End pwmOut
void updateEncoder(){
int MSB = digitalRead(encoderPin1); //MSB = most significant bit
int LSB = digitalRead(encoderPin2); //LSB = least significant bit
int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
lastEncoded = encoded; //store this value for next time
}
void forward () {
digitalWrite(MotFwd, HIGH);
digitalWrite(MotRev, LOW);
}
void reverse () {
digitalWrite(MotFwd, LOW);
digitalWrite(MotRev, HIGH);
}
void finish () {
digitalWrite(MotFwd, LOW);
digitalWrite(MotRev, LOW);
}
[jansun – Sat Jan 05, 2019 1:51 pm] –
…
Now, the arduino works fine and the STM32 code not. I build everything the same and with the stm32 the motor keeps spinning. Icant find anything in the code and for me it looks like the lib code should be compatible with stmduino? Encoder direction are oke, but the output of the PID dont react like the arduino code.Someone a clue?
The “clue” is the sketch does not work as expected; therefore, either your code or the library is to blame. If the 8-bit AVR boards & code work, likely the issue is something to do with what is commonly called porting – the code correction and adjustment for the architectural assumptions made by libraries. An example is that an AVR integer is 16-bits and the STM32 integer is 32-bits.
Years ago, a number of common libraries were ported by members: here
Beyond that, members have posted successes in the forum here
IMO, the biggest problem is members that “want” a paticular library but lack the knowledge to execute the port themselves. This is probably where Arduino, as a concept, does the most harm; the library concept allows coders to work beyond their skill level and be satisfied with their mediocre coding skill.
What is broken here is not the AVR library, but your expectation. You just need to jump into learning how libraries work and how to modify library code to match your expectations. This effort will make you far more knowledgeable and a much better programmer able to move across chip architecture and software tool sets.
Or, you could just beg the forum for someone to “fix” the library for you.
Ray
[stevestrong – Sat Jan 05, 2019 6:05 pm] –
You did not set the mode of pins PB6/7.
thanks!
[edogaldo – Sat Jan 05, 2019 5:29 pm] –
I can see several differences in the two versions, for example the usage of 2 external interrupts in the Arduino version that I can’t see in the STM version, so the two sketches don’t seem equivalent on a first check..
I cant use the encoder code like the arduino code (google direct port manipulation why), this part is indeed different, but it looks like this part works.
[mrburnette – Sat Jan 05, 2019 4:37 pm] –
What is broken here is not the AVR library, but your expectation. You just need to jump into learning how libraries work and how to modify library code to match your expectations. This effort will make you far more knowledgeable and a much better programmer able to move across chip architecture and software tool sets.
Im working on this. what i already did is copied the lib to a separate tab so i can change the library and “debug” it. I was hoping for a stupidity like stevestrong mentioned, but unfortunately this didnt solve the issue. I dont like to beg for someone else solving my code, but i am for some c++ lessons
It looks off-topic, but to understand and fix the PID libraray i’ve made a simple led blink library code and im stuck right now.
.h:
#ifndef Led_h
#define Led_h
#include "Arduino.h"
class Led{
public:
Led(int pin);
void init();
void toggleLed();
void handler_led();
private:
};
#endif
you may find it helpful to go back to what you meant by a “library”.
in general, you want a library to be a black box with appropriate inputs and outputs. and whenever possible, have a good boundary that separates the software side of things from the hardware side of thing.
A PID routine is one that should be totally implemented in software, with a well defined input and output set of variables. in the MCU environment, such a routine may be called periodically by the hardware to perform data capture, calculation and output attenuation.
it is unhelpful, from that perspective, to have a set of PID library routines that 1) comingles your hardware and software implementaton – such a routine is application specific and hard to port to your next application / platform; and/or 2) has pre-sets that the user cannot affect.
here is an example of my PID implementation: https://dannyelectronics.wordpress.com/ … -attiny85/
the particular PID routines it used are application and instance independent, meaning that the same code can be invoked on the same platform by different tasks in different instances, to minimize foot-print.
obviously the whole thing hinges on your particular definition of “library”. Mine isn’t the absolute or only way of doing it.
[jansun – Sat Jan 05, 2019 8:01 pm] –
Error:
no matching function for call to 'HardwareTimer::attachCompare1Interrupt(<unresolved overloaded function type>)'
[stevestrong – Sat Jan 05, 2019 10:50 pm] –[jansun – Sat Jan 05, 2019 8:01 pm] –
Error:
no matching function for call to 'HardwareTimer::attachCompare1Interrupt(<unresolved overloaded function type>)'
Make that function standalone and it will work.
[stevestrong – Sun Jan 06, 2019 1:57 pm] – And pointing to a class member function is very tricky…
Yes, that’s another layer of complexity not needed at this stage.
Food for thought, if you’re following the C++ gravy train.
[stevestrong – Sun Jan 06, 2019 1:57 pm] –
Ah, that will not work at all because the function you want to attach is a class member. And pointing to a class member function is very tricky…
Make that function standalone and it will work.
Of course, why didnt I see this? Maybe I have to take a look in how to point to a function in another class for starters. But.. for now indeed not needed for this stage, im gonna put the timer in setup on fist tab, would do the job.
Thanks!



