Problem to declare the one-channel encoder of SparkFun gimbal 3-Phase BLDC motor?

Hello. I built a SimpleFOC PID-control code for two SparkFun gimbal 12V 3-Phase BLDC motors with the encoders AS5048A Gimbal Motor with Encoder - 12V, 467RPM - SparkFun Electronics based on the one-motor example code Position Control example | Arduino-FOC .
However, there is the following problem. The example code uses Encoder encoder = Encoder(A, B, number_of_Pulses_Per_Rotation) to declare an encoder. A and B are two pin numbers for two channels of an encoder. The gimbal SparkFun motor exploits the one-channel encoder AS5048A. The class Encoder works with two-channel encoders. Setting just one pin number in the encoder declaration statement results into the error. Could someone please recommend how to declare the one-channel encoder in the SimpleFOC PID-control code? Thank you.

Instead of Encoder use the MagneticSensorSPI class

Thank you, TS-Russell. If use the MagneticSensorSPI class, we need to use the SPI pins of the encoder AS5048A. We already connected the encoder by using its PWM pins. If we used the SPI pins, we would need to rewire the encoder. In between, its SPI pins (too small) are not easy to solder.

I came up with another solution. The class MagneticSensorPWM can be used with the encoder PWM pins (one channel pin, VDD. GND). In the code, the encoder declaration is MagneticSensorPWM encoder = MagneticSensorPWM(~A12, minimal_pulse_microseconds, maximal_pulse_microseconds) if SparkFun RedBoard Artemis ATP is used. Based on the SimpleFOC webpage “PWM output Magnetic sensor setup” Magnetic sensor PWM | Arduino-FOC , the argument minimal_pulse_microseconds (or min_raw_count) represents the shortest expected length of the high-state digital pulse corresponding to a 0 degree absolute angle position. However, the calibration of the values of the minimal_pulse_microseconds and the maximal_pulse_microseconds is needed because magnetic encoders do not start pulse width at 0 microsecond for the 0 degree. They begin pulse with a brief initialization/synchronization period in according to: MagneticSensorPWM - developement - SimpleFOC Community .

For the encoder AS5048A, the minimal time the pulse is HIGH is typically from 4 us to 12 us, even if its magnet is exactly at the 0 degree. The encoder AS5048A maximal pulse time is around 4119 us. However, the calibration is required to avoid the rotors’ “jumps”. If somebody has any other useful info, please comment. Thank you.

Ah, sorry - brain fart…I meant PWM :slight_smile:

Hello. I built a code to read and print the widths (time) of minimal and maximal pulses of PWM channels of two AS5048A encoders connected to the SparkFun RedBoard Artemis ATP microcontroller board analog pins. The first encoder PWM wire is connected to the pin ~A12. The second encoder PWM wire is connected to the pin ~A13. When my code was executed, the readings of the pulses sometimes jumped to some thousand microseconds. May somebody please specify why such jumps could happen? Maybe something is wrong with the RedBoard Artemis ATP board or with the code? Here is the code:

/* The following code to find the values of min_pulse_us and max_pulse_us
for twp AS5048A encoders based on the example code published here:

NOTE: Pulse width even at zero degree is not equal to zero
*/
//#include <SimpleFOC.h>
//#include <Arduino.h>

const int PWM_pin_encoder1 = A12; // Connect to the AS5048A encoder #1 PWM pin
const int PWM_pin_encoder2 = A13; // Connect to the AS5048A encoder #2 PWM pin
unsigned long Min_pulse_encoder1_us = 100; // Encoder 1 - state minimal pulse width higher than the possible one
unsigned long Max_pulse_encoder1_us = 100000; // Encoder 1 - state maximal pulse width higher than the possible one
unsigned long Min_pulse_encoder2_us = 100; // Encoder 2 - state minimal pulse width higher than the possible one
unsigned long Max_pulse_encoder2_us = 100000; // Encoder 2 - state maximal pulse width higher than the possible one

void setup() {
pinMode(PWM_pin_encoder1, INPUT);
pinMode(PWM_pin_encoder2, INPUT);
Serial.begin(115200);
Serial.println(“Rotate both AS5048A encoders 360 degrees to find Min/Max Pulse Values”);
delay(10);
}
// Make loop to read and print Max/Min pulse time of Encoder 1 and Encoder 2
void loop() {
// Read the HIGH state pulse width in microseconds
// Timeout set to 1000000us to capture low/high safely
unsigned long currentPulse1 = pulseIn(PWM_pin_encoder1, HIGH, 1000000);
unsigned long currentPulse2 = pulseIn(PWM_pin_encoder2, HIGH, 1000000);

if (currentPulse1 > 0 && currentPulse2 > 0) {
bool updated = false;

// Reject outliers and look for absolute bounds
if (currentPulse1 < Min_pulse_encoder1_us && currentPulse1 > 0) {
Min_pulse_encoder1_us = currentPulse1;
updated = true;
}
if (currentPulse1 > Min_pulse_encoder1_us && currentPulse1 < 100000) {
Max_pulse_encoder1_us = currentPulse1;
updated = true;
}
// Reject outliers and look for absolute bounds
if (currentPulse2 < Min_pulse_encoder2_us && currentPulse2 > 0) {
Min_pulse_encoder2_us = currentPulse2;
updated = true;
}
if (currentPulse2 > Min_pulse_encoder2_us && currentPulse2 < 100000) {
Max_pulse_encoder2_us = currentPulse2;
updated = true;
}
// Print Max and Min Pulse Time of Encoder #1 and Encoder #2
if (updated) {
Serial.print("Encoder #1 → Min Pulse: “);
Serial.print(Min_pulse_encoder1_us);
Serial.print(” us | Max Pulse: “);
Serial.print(Max_pulse_encoder1_us);
Serial.print(” us ");
Serial.print(“Encoder #2 → Min Pulse: “);
Serial.print(Min_pulse_encoder2_us);
Serial.print(” us | Max Pulse: “);
Serial.print(Max_pulse_encoder2_us);
Serial.print(” us\n”);

delay(1000);
}

}
}

Thank you.

Hi Boris ( @B ),

Please try:

In your global code:

unsigned long Min_pulse_encoder1_us = 100000; // Encoder 1 Minimum - set to a large value initially
unsigned long Max_pulse_encoder1_us = 0; // Encoder 1 Maximum - set to zero initially
unsigned long Min_pulse_encoder2_us = 100000; // Encoder 2 Minimum - set to a large value initially
unsigned long Max_pulse_encoder2_us = 0; // Encoder 2 - Maximum set to zero initially

Then, in your loop():

if (currentPulse1 < Min_pulse_encoder1_us && currentPulse1 > 0) {
Min_pulse_encoder1_us = currentPulse1; // Update the Encoder 1 minimum
updated = true;
}
if (currentPulse1 > Max_pulse_encoder1_us && currentPulse1 > 0) {
Max_pulse_encoder1_us = currentPulse1; // Update the Encoder 1 maximum
updated = true;
}
if (currentPulse2 < Min_pulse_encoder2_us && currentPulse2 > 0) {
Min_pulse_encoder2_us = currentPulse2; // Update the Encoder 2 minimum
updated = true;
}
if (currentPulse2 > Max_pulse_encoder2_us && currentPulse2 > 0) {
Max_pulse_encoder2_us = currentPulse2;
updated = true;
}

I hope this helps,
Paul

Thank you so much, PaulZC. We have just used an oscilloscope to find min/max PWM pulse widths. The first encoder widths are 14us/936us. The second encoder widths are 14us/896us. By the way, they are almost the same that I got by using my code. Just sporadic pulse jumps make me worry. If there can happen longer widths while rotating the motors, what can cause such longer pulse widths that happen from time to time? I just fear that they can disturb the proper PID-control. Thank you.

Hi @B ,

Are these longer pulses real? Have you seen them on the oscilloscope? Or are they being detected by the code only? If they are only detected by the code then it is probably just the code missing a pulse finish/start and reporting a “double” pulse length?

The solution may be to: use interrupts to detect the pulse edges and calculate the pulse width; and add a filter in your code which rejects any “illegal” pulse widths - longer than ~1ms.

I hope this helps,
Paul

Thank you, PaulZC. An oscilloscope gave square waves. Shrinks happened while we checked the second encoder. However, they might happen because I moved the rotor improperly sometimes.

You suggested to reject “illegal” pulse widths by setting the range in code. However, doing so does not remove a physical reason of their existence. If it works out to make the motors work as needed, then it goes.