Skip to content

Commit 784f67a

Browse files
authored
Fix HR PID race condition with training program speed changes (#4553)
1 parent 1df45c5 commit 784f67a

3 files changed

Lines changed: 35 additions & 5 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ src/inner_templates/googlemaps/cesium-key.js
5353
/tst/Devices/.vs
5454
src/inner_templates/googlemaps/cesium-key.js
5555
src/qdomyos-zwift.pro.user.49de507
56-
/.vs
56+
/.vs

src/homeform.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,8 @@ void homeform::trainProgramSignals() {
15901590
disconnect(trainProgram, &trainprogram::lap, this, &homeform::Lap);
15911591
disconnect(trainProgram, &trainprogram::changeSpeed, ((treadmill *)bluetoothManager->device()),
15921592
&treadmill::changeSpeed);
1593+
disconnect(trainProgram, &trainprogram::changeSpeed, this,
1594+
&homeform::onTrainingProgramSpeedChanged);
15931595
disconnect(trainProgram, &trainprogram::changeInclination, ((treadmill *)bluetoothManager->device()),
15941596
&treadmill::changeInclination);
15951597
disconnect(trainProgram, &trainprogram::changeNextInclination300Meters, bluetoothManager->device(),
@@ -1647,6 +1649,9 @@ void homeform::trainProgramSignals() {
16471649
connect(trainProgram, &trainprogram::stop, this, &homeform::StopFromTrainProgram);
16481650
connect(trainProgram, &trainprogram::lap, this, &homeform::Lap);
16491651
connect(trainProgram, &trainprogram::toastRequest, this, &homeform::onToastRequested);
1652+
// Connect training program speed changes to reset HR PID timer
1653+
connect(trainProgram, &trainprogram::changeSpeed, this,
1654+
&homeform::onTrainingProgramSpeedChanged);
16501655
if (bluetoothManager->device()->deviceType() == TREADMILL) {
16511656
connect(trainProgram, &trainprogram::changeSpeed, ((treadmill *)bluetoothManager->device()),
16521657
&treadmill::changeSpeed);
@@ -1738,6 +1743,13 @@ void homeform::onToastRequested(QString message) {
17381743
}
17391744
}
17401745

1746+
void homeform::onTrainingProgramSpeedChanged(double speed) {
1747+
// Record the timestamp when the training program changed speed
1748+
// This is used by the HR PID controller to avoid race conditions
1749+
lastTrainingProgramSpeedChange = QDateTime::currentDateTime();
1750+
}
1751+
1752+
17411753
QStringList homeform::tile_order() {
17421754

17431755
QStringList r;
@@ -7300,6 +7312,12 @@ void homeform::update() {
73007312

73017313
if (!stopped && !paused && bluetoothManager->device()->currentHeart().value() && zone > 0 &&
73027314
bluetoothManager->device()->currentSpeed().value() > 0.0f) {
7315+
// Skip HR PID adjustments for a period after training program changes speed
7316+
// This prevents race conditions where HR PID overwrites training program speed changes
7317+
qint64 msSinceSpeedChange = lastTrainingProgramSpeedChange.msecsTo(QDateTime::currentDateTime());
7318+
bool recentSpeedChange = (msSinceSpeedChange < (delta * 1000));
7319+
7320+
if (!recentSpeedChange) {
73037321
if (bluetoothManager->device()->deviceType() == TREADMILL) {
73047322

73057323
const double step = 0.2;
@@ -7411,6 +7429,7 @@ void homeform::update() {
74117429
((rower *)bluetoothManager->device())->changeResistance(currentResistance + step);
74127430
}
74137431
}
7432+
} // Close the if (!recentSpeedChange) block
74147433
}
74157434
}
74167435
} else if ((settings.value(QZSettings::treadmill_pid_heart_min, QZSettings::default_treadmill_pid_heart_min)
@@ -7468,6 +7487,12 @@ void homeform::update() {
74687487
<< QStringLiteral("HRmin:") << hrmin << QStringLiteral("HRmax:") << hrmax
74697488
<< QStringLiteral("fromTrainProgram:") << fromTrainProgram;
74707489

7490+
// Skip HR PID adjustments for a period after training program changes speed
7491+
// This prevents race conditions where HR PID overwrites training program speed changes
7492+
qint64 msSinceSpeedChange = lastTrainingProgramSpeedChange.msecsTo(QDateTime::currentDateTime());
7493+
bool recentSpeedChange = (msSinceSpeedChange < (delta * 1000));
7494+
7495+
if (!recentSpeedChange) {
74717496
if (bluetoothManager->device()->deviceType() == TREADMILL) {
74727497

74737498
const double step = 0.2;
@@ -7589,10 +7614,11 @@ void homeform::update() {
75897614
qDebug() << QStringLiteral("ROWING PID HR - HR < HRmin, INCREASING resistance from")
75907615
<< currentResistance << QStringLiteral("to") << (currentResistance + step);
75917616
((rower *)bluetoothManager->device())->changeResistance(currentResistance + step);
7592-
} else {
7593-
qDebug() << QStringLiteral("ROWING PID HR - No action taken (in zone or at limits)");
7594-
}
7595-
}
7617+
} else {
7618+
qDebug() << QStringLiteral("ROWING PID HR - No action taken (in zone or at limits)");
7619+
}
7620+
}
7621+
} // Close the if (!recentSpeedChange) block
75967622
}
75977623
}
75987624
}

src/homeform.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,9 @@ class homeform : public QObject {
974974
QTimer *backupTimer;
975975
QTimer *automaticShiftingTimer;
976976

977+
// HR PID controller state - tracks when training program changes speed to prevent race conditions
978+
QDateTime lastTrainingProgramSpeedChange = QDateTime::fromMSecsSinceEpoch(0);
979+
977980
// FIT backup threading
978981
QThread *fitBackupThread;
979982
FitBackupWriter *fitBackupWriter;
@@ -1089,6 +1092,7 @@ class homeform : public QObject {
10891092
void saveSessionAsTrainingProgram();
10901093
void strava_connect_clicked();
10911094
void trainProgramSignals();
1095+
void onTrainingProgramSpeedChanged(double speed);
10921096
void refresh_bluetooth_devices_clicked();
10931097
void onStravaGranted();
10941098
void onStravaAuthorizeWithBrowser(const QUrl &url);

0 commit comments

Comments
 (0)