Skip to content

Commit 510527a

Browse files
Merge pull request #276 from dekutree64/dev
Fix for issue #270
2 parents 99b3f9d + b03f8a9 commit 510527a

File tree

7 files changed

+58
-57
lines changed

7 files changed

+58
-57
lines changed

src/common/base_classes/Sensor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ enum Pullup : uint8_t {
4242
*
4343
*/
4444
class Sensor{
45+
friend class SmoothingSensor;
4546
public:
4647
/**
4748
* Get mechanical shaft angle in the range 0 to 2PI. This value will be as precise as possible with

src/sensors/Encoder.cpp

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -99,29 +99,23 @@ void Encoder::handleIndex() {
9999
}
100100

101101

102+
// Sensor update function. Safely copy volatile interrupt variables into Sensor base class state variables.
102103
void Encoder::update() {
103-
// do nothing for Encoder
104+
// Copy volatile variables in minimal-duration blocking section to ensure no interrupts are missed
105+
noInterrupts();
106+
angle_prev_ts = pulse_timestamp;
107+
long copy_pulse_counter = pulse_counter;
108+
interrupts();
109+
// TODO: numerical precision issue here if the pulse_counter overflows the angle will be lost
110+
full_rotations = copy_pulse_counter / (int)cpr;
111+
angle_prev = _2PI * ((copy_pulse_counter) % ((int)cpr)) / ((float)cpr);
104112
}
105113

106114
/*
107115
Shaft angle calculation
108116
*/
109117
float Encoder::getSensorAngle(){
110-
return getAngle();
111-
}
112-
// TODO: numerical precision issue here if the pulse_counter overflows the angle will be lost
113-
float Encoder::getMechanicalAngle(){
114-
return _2PI * ((pulse_counter) % ((int)cpr)) / ((float)cpr);
115-
}
116-
117-
float Encoder::getAngle(){
118-
return _2PI * (pulse_counter) / ((float)cpr);
119-
}
120-
double Encoder::getPreciseAngle(){
121-
return _2PI * (pulse_counter) / ((double)cpr);
122-
}
123-
int32_t Encoder::getFullRotations(){
124-
return pulse_counter / (int)cpr;
118+
return _2PI * (pulse_counter) / ((float)cpr);
125119
}
126120

127121

@@ -131,6 +125,11 @@ int32_t Encoder::getFullRotations(){
131125
function using mixed time and frequency measurement technique
132126
*/
133127
float Encoder::getVelocity(){
128+
// Copy volatile variables in minimal-duration blocking section to ensure no interrupts are missed
129+
noInterrupts();
130+
long copy_pulse_counter = pulse_counter;
131+
long copy_pulse_timestamp = pulse_timestamp;
132+
interrupts();
134133
// timestamp
135134
long timestamp_us = _micros();
136135
// sampling time calculation
@@ -139,8 +138,8 @@ float Encoder::getVelocity(){
139138
if(Ts <= 0 || Ts > 0.5f) Ts = 1e-3f;
140139

141140
// time from last impulse
142-
float Th = (timestamp_us - pulse_timestamp) * 1e-6f;
143-
long dN = pulse_counter - prev_pulse_counter;
141+
float Th = (timestamp_us - copy_pulse_timestamp) * 1e-6f;
142+
long dN = copy_pulse_counter - prev_pulse_counter;
144143

145144
// Pulse per second calculation (Eq.3.)
146145
// dN - impulses received
@@ -161,7 +160,7 @@ float Encoder::getVelocity(){
161160
prev_timestamp_us = timestamp_us;
162161
// save velocity calculation variables
163162
prev_Th = Th;
164-
prev_pulse_counter = pulse_counter;
163+
prev_pulse_counter = copy_pulse_counter;
165164
return velocity;
166165
}
167166

src/sensors/Encoder.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,8 @@ class Encoder: public Sensor{
6161
// Abstract functions of the Sensor class implementation
6262
/** get current angle (rad) */
6363
float getSensorAngle() override;
64-
float getMechanicalAngle() override;
6564
/** get current angular velocity (rad/s) */
6665
float getVelocity() override;
67-
float getAngle() override;
68-
double getPreciseAngle() override;
69-
int32_t getFullRotations() override;
7066
virtual void update() override;
7167

7268
/**

src/sensors/HallSensor.cpp

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,16 @@ void HallSensor::attachSectorCallback(void (*_onSectorChange)(int sector)) {
9494

9595

9696

97-
float HallSensor::getSensorAngle() {
98-
return getAngle();
97+
// Sensor update function. Safely copy volatile interrupt variables into Sensor base class state variables.
98+
void HallSensor::update() {
99+
// Copy volatile variables in minimal-duration blocking section to ensure no interrupts are missed
100+
noInterrupts();
101+
angle_prev_ts = pulse_timestamp;
102+
long last_electric_rotations = electric_rotations;
103+
int8_t last_electric_sector = electric_sector;
104+
interrupts();
105+
angle_prev = ((float)((last_electric_rotations * 6 + last_electric_sector) % cpr) / (float)cpr) * _2PI ;
106+
full_rotations = (int32_t)((last_electric_rotations * 6 + last_electric_sector) / cpr);
99107
}
100108

101109

@@ -104,47 +112,27 @@ float HallSensor::getSensorAngle() {
104112
Shaft angle calculation
105113
TODO: numerical precision issue here if the electrical rotation overflows the angle will be lost
106114
*/
107-
float HallSensor::getMechanicalAngle() {
108-
return ((float)((electric_rotations * 6 + electric_sector) % cpr) / (float)cpr) * _2PI ;
115+
float HallSensor::getSensorAngle() {
116+
return ((float)(electric_rotations * 6 + electric_sector) / (float)cpr) * _2PI ;
109117
}
110118

111119
/*
112120
Shaft velocity calculation
113121
function using mixed time and frequency measurement technique
114122
*/
115123
float HallSensor::getVelocity(){
124+
noInterrupts();
125+
long last_pulse_timestamp = pulse_timestamp;
116126
long last_pulse_diff = pulse_diff;
117-
if (last_pulse_diff == 0 || ((long)(_micros() - pulse_timestamp) > last_pulse_diff) ) { // last velocity isn't accurate if too old
127+
interrupts();
128+
if (last_pulse_diff == 0 || ((long)(_micros() - last_pulse_timestamp) > last_pulse_diff*2) ) { // last velocity isn't accurate if too old
118129
return 0;
119130
} else {
120-
float vel = direction * (_2PI / (float)cpr) / (last_pulse_diff / 1000000.0f);
121-
// quick fix https://github.com/simplefoc/Arduino-FOC/issues/192
122-
if(vel < -velocity_max || vel > velocity_max) vel = 0.0f; //if velocity is out of range then make it zero
123-
return vel;
131+
return direction * (_2PI / (float)cpr) / (last_pulse_diff / 1000000.0f);
124132
}
125133

126134
}
127135

128-
129-
130-
float HallSensor::getAngle() {
131-
return ((float)(electric_rotations * 6 + electric_sector) / (float)cpr) * _2PI ;
132-
}
133-
134-
135-
double HallSensor::getPreciseAngle() {
136-
return ((double)(electric_rotations * 6 + electric_sector) / (double)cpr) * (double)_2PI ;
137-
}
138-
139-
140-
int32_t HallSensor::getFullRotations() {
141-
return (int32_t)((electric_rotations * 6 + electric_sector) / cpr);
142-
}
143-
144-
145-
146-
147-
148136
// HallSensor initialisation of the hardware pins
149137
// and calculation variables
150138
void HallSensor::init(){

src/sensors/HallSensor.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,12 @@ class HallSensor: public Sensor{
5353
int cpr;//!< HallSensor cpr number
5454

5555
// Abstract functions of the Sensor class implementation
56+
/** Interrupt-safe update */
57+
void update() override;
5658
/** get current angle (rad) */
5759
float getSensorAngle() override;
58-
float getMechanicalAngle() override;
59-
float getAngle() override;
6060
/** get current angular velocity (rad/s) */
6161
float getVelocity() override;
62-
double getPreciseAngle() override;
63-
int32_t getFullRotations() override;
6462

6563
// whether last step was CW (+1) or CCW (-1).
6664
Direction direction;

src/sensors/MagneticSensorPWM.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,21 @@ void MagneticSensorPWM::init(){
5656
// initial hardware
5757
pinMode(pinPWM, INPUT);
5858
raw_count = getRawCount();
59+
pulse_timestamp = _micros();
5960

6061
this->Sensor::init(); // call base class init
6162
}
6263

64+
// Sensor update function. Safely copy volatile interrupt variables into Sensor base class state variables.
65+
void MagneticSensorPWM::update() {
66+
if (is_interrupt_based)
67+
noInterrupts();
68+
Sensor::update();
69+
angle_prev_ts = pulse_timestamp; // Timestamp of actual sample, before the time-consuming PWM communication
70+
if (is_interrupt_based)
71+
interrupts();
72+
}
73+
6374
// get current angle (rad)
6475
float MagneticSensorPWM::getSensorAngle(){
6576
// raw data from sensor
@@ -73,6 +84,7 @@ float MagneticSensorPWM::getSensorAngle(){
7384
// read the raw counter of the magnetic sensor
7485
int MagneticSensorPWM::getRawCount(){
7586
if (!is_interrupt_based){ // if it's not interrupt based read the value in a blocking way
87+
pulse_timestamp = _micros(); // ideally this should be done right at the rising edge of the pulse
7688
pulse_length_us = pulseIn(pinPWM, HIGH);
7789
}
7890
return pulse_length_us;
@@ -84,7 +96,10 @@ void MagneticSensorPWM::handlePWM() {
8496
unsigned long now_us = _micros();
8597

8698
// if falling edge, calculate the pulse length
87-
if (!digitalRead(pinPWM)) pulse_length_us = now_us - last_call_us;
99+
if (!digitalRead(pinPWM)) {
100+
pulse_length_us = now_us - last_call_us;
101+
pulse_timestamp = last_call_us; // angle was sampled at the rising edge of the pulse, so use that timestamp
102+
}
88103

89104
// save the currrent timestamp for the next call
90105
last_call_us = now_us;

src/sensors/MagneticSensorPWM.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class MagneticSensorPWM: public Sensor{
3232
void init();
3333

3434
int pinPWM;
35+
36+
// Interrupt-safe update
37+
void update() override;
3538

3639
// get current angle (rad)
3740
float getSensorAngle() override;
@@ -62,6 +65,7 @@ class MagneticSensorPWM: public Sensor{
6265
// time tracking variables
6366
unsigned long last_call_us;
6467
// unsigned long pulse_length_us;
68+
unsigned long pulse_timestamp;
6569

6670

6771
};

0 commit comments

Comments
 (0)