From b1d04badfbec5ba765e8f927940f580579ebe510 Mon Sep 17 00:00:00 2001 From: fastium Date: Wed, 23 Oct 2024 10:59:38 +0200 Subject: [PATCH 1/7] ADD sensor device classes --- common/constants.hpp | 54 ++++++++++++++++++++++++++++++++++++++++ common/sensor_device.cpp | 21 ++++++++++++++++ common/sensor_device.hpp | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 common/constants.hpp create mode 100644 common/sensor_device.cpp create mode 100644 common/sensor_device.hpp diff --git a/common/constants.hpp b/common/constants.hpp new file mode 100644 index 0000000..8774f8f --- /dev/null +++ b/common/constants.hpp @@ -0,0 +1,54 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file constants.hpp + * @author Serge Ayer + * + * @brief Constants definition used for implementing the bike system + * + * @date 2023-08-20 + * @version 1.0.0 + ***************************************************************************/ + +#pragma once + +#include + +#include "mbed.h" + +namespace bike_computer { + +// gear related constants +static constexpr uint8_t kMinGear = 1; +static constexpr uint8_t kMaxGear = 9; +// smallest gear (= 1) corresponds to a gear size of 20 +// when the gear increases, the gear size descreases +static constexpr uint8_t kMaxGearSize = 20; +static constexpr uint8_t kMinGearSize = kMaxGearSize - kMaxGear; + +// pedal related constants +// When compiling and linking with gcc, we get a link error when using static +// constexpr. The error is related to template instantiation. + +// definition of pedal rotation initial time (corresponds to 80 turn / min) +static constexpr std::chrono::milliseconds kInitialPedalRotationTime = 750ms; +// definition of pedal minimal rotation time (corresponds to 160 turn / min) +static constexpr std::chrono::milliseconds kMinPedalRotationTime = 375ms; +// definition of pedal maximal rotation time (corresponds to 10 turn / min) +static constexpr std::chrono::milliseconds kMaxPedalRotationTime = 1500ms; +// definition of pedal rotation time change upon acceleration/deceleration +static constexpr std::chrono::milliseconds kDeltaPedalRotationTime = 25ms; + +} // namespace bike_computer \ No newline at end of file diff --git a/common/sensor_device.cpp b/common/sensor_device.cpp new file mode 100644 index 0000000..4aa7ef2 --- /dev/null +++ b/common/sensor_device.cpp @@ -0,0 +1,21 @@ +#include "sensor_device.hpp" + +namespace bike_computer { + +SensorDevice::SensorDevice() : _hdc1000(I2C_SDA, I2C_SCL, STMOD_11) +{} + +bool SensorDevice::init() { + return this->_hdc1000.probe(); +} + +float SensorDevice::readTemperature(void) { + return this->_hdc1000.getTemperature(); +} + +float SensorDevice::readHumidity(void) { + return this->_hdc1000.getHumidity(); +} + +} // bike_computer + diff --git a/common/sensor_device.hpp b/common/sensor_device.hpp new file mode 100644 index 0000000..d6ead2c --- /dev/null +++ b/common/sensor_device.hpp @@ -0,0 +1,49 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file sensor_device.hpp + * @author Serge Ayer + * + * @brief SensorDevice header file (static scheduling) + * + * @date 2023-08-20 + * @version 1.0.0 + ***************************************************************************/ + +#pragma once + +#include "hdc1000.hpp" +#include "mbed.h" + +namespace bike_computer { + +class SensorDevice { + public: + // constructor + SensorDevice(); + + // method for initializing the device + bool init(); + + // methods used for + float readTemperature(void); + float readHumidity(void); + + private: + // data members + advembsof::HDC1000 _hdc1000; +}; + +} // namespace bike_computer \ No newline at end of file From b9fda1aefe5185f2ca56cc4e025c70a029f18775 Mon Sep 17 00:00:00 2001 From: fastium Date: Tue, 29 Oct 2024 16:13:20 +0100 Subject: [PATCH 2/7] ADD Tests for the sensor --- .github/workflows/build-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 56b70af..3db23d2 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -19,7 +19,8 @@ jobs: tests-simple-test-ptr-test, tests-simple-unique-ptr, tests-simple-test-raw-ptr, - advdembsof_library-tests-sensors-hdc1000 + advdembsof_library-tests-sensors-hdc1000, + tests-bike-computer-sensor-device ] From 0d4e603a647ab171a7e8524a8918351f557d00b6 Mon Sep 17 00:00:00 2001 From: fastium Date: Tue, 29 Oct 2024 16:15:32 +0100 Subject: [PATCH 3/7] ADD speedometer and gear class --- common/speedometer.cpp | 125 ++++++++++++++++++++++++++++++ common/speedometer.hpp | 91 ++++++++++++++++++++++ static_scheduling/gear_device.cpp | 83 ++++++++++++++++++++ static_scheduling/gear_device.hpp | 50 ++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 common/speedometer.cpp create mode 100644 common/speedometer.hpp create mode 100644 static_scheduling/gear_device.cpp create mode 100644 static_scheduling/gear_device.hpp diff --git a/common/speedometer.cpp b/common/speedometer.cpp new file mode 100644 index 0000000..a30ecaa --- /dev/null +++ b/common/speedometer.cpp @@ -0,0 +1,125 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file speedometer_device.cpp + * @author Serge Ayer + * + * @brief WheelCounterDevice implementation (static scheduling) + * + * @date 2023-08-20 + * @version 1.0.0 + ***************************************************************************/ + +#include "speedometer.hpp" + +#include +#include + +// from disco_h747i/wrappers +#include "joystick.hpp" +#include "mbed_trace.h" + +#if MBED_CONF_MBED_TRACE_ENABLE +#define TRACE_GROUP "Speedometer" +#endif // MBED_CONF_MBED_TRACE_ENABLE + +namespace bike_computer { + +Speedometer::Speedometer(Timer& timer) : _timer(timer) { + // update _lastTime + _lastTime = _timer.elapsed_time(); +} + +void Speedometer::setCurrentRotationTime( + const std::chrono::milliseconds& currentRotationTime) { + if (_pedalRotationTime != currentRotationTime) { + // compute distance before changing the rotation time + computeDistance(); + + // change pedal rotation time + _pedalRotationTime = currentRotationTime; + + // compute speed with the new pedal rotation time + computeSpeed(); + } +} + +void Speedometer::setGearSize(uint8_t gearSize) { + if (_gearSize != gearSize) { + // compute distance before chaning the gear size + computeDistance(); + + // change gear size + _gearSize = gearSize; + + // compute speed with the new gear size + computeSpeed(); + } +} + +float Speedometer::getCurrentSpeed() const { return _currentSpeed; } + +float Speedometer::getDistance() { + // make sure to update the distance traveled + computeDistance(); + return _totalDistance; +} + +void Speedometer::reset() { + // TODO : done + this->_totalDistanceMutex.lock(); + this->_totalDistance = 0.0f; + this->_totalDistanceMutex.unlock(); +} + +#if defined(MBED_TEST_MODE) +uint8_t Speedometer::getGearSize() const { return _gearSize; } + +float Speedometer::getWheelCircumference() const { return kWheelCircumference; } + +float Speedometer::getTraySize() const { return kTraySize; } + +std::chrono::milliseconds Speedometer::getCurrentPedalRotationTime() const { + return _pedalRotationTime; +} + +#endif // defined(MBED_TEST_MODE) + +void Speedometer::computeSpeed() { + // For computing the speed given a rear gear (braquet), one must divide the size of + // the tray (plateau) by the size of the rear gear (pignon arrière), and then multiply + // the result by the circumference of the wheel. Example: tray = 50, rear gear = 15. + // Distance run with one pedal turn (wheel circumference = 2.10 m) = 50/15 * 2.1 m + // = 6.99m If you ride at 80 pedal turns / min, you run a distance of 6.99 * 80 / min + // ~= 560 m / min = 33.6 km/h + + // TODO + + +} + +void Speedometer::computeDistance() { + // For computing the speed given a rear gear (braquet), one must divide the size of + // the tray (plateau) by the size of the rear gear (pignon arrière), and then multiply + // the result by the circumference of the wheel. Example: tray = 50, rear gear = 15. + // Distance run with one pedal turn (wheel circumference = 2.10 m) = 50/15 * 2.1 m + // = 6.99m If you ride at 80 pedal turns / min, you run a distance of 6.99 * 80 / min + // ~= 560 m / min = 33.6 km/h. We then multiply the speed by the time for getting the + // distance traveled. + + // TODO +} + +} // namespace bike_computer \ No newline at end of file diff --git a/common/speedometer.hpp b/common/speedometer.hpp new file mode 100644 index 0000000..bbc1e6b --- /dev/null +++ b/common/speedometer.hpp @@ -0,0 +1,91 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file speedometer_device.hpp + * @author Serge Ayer + * + * @brief WheelCounterDevice header file (static scheduling) + * + * @date 2023-08-20 + * @version 1.0.0 + ***************************************************************************/ + +#pragma once + +#include "constants.hpp" +#include "mbed.h" + +namespace bike_computer { + +class Speedometer { + public: + explicit Speedometer(Timer& timer); // NOLINT(runtime/references) + + // method used for setting the current pedal rotation time + void setCurrentRotationTime(const std::chrono::milliseconds& currentRotationTime); + + // method used for setting/getting the current gear + void setGearSize(uint8_t gearSize); + + // method called for getting the current speed (expressed in km / h) + float getCurrentSpeed() const; + + // method called for getting the current traveled distance (expressed in km) + float getDistance(); + + // method called for resetting the traveled distance + void reset(); + + // methods used for tests only +#if defined(MBED_TEST_MODE) + uint8_t getGearSize() const; + float getWheelCircumference() const; + float getTraySize() const; + std::chrono::milliseconds getCurrentPedalRotationTime() const; + void setOnResetCallback(mbed::Callback cb); +#endif // defined(MBED_TEST_MODE) + + private: + // private methods + void computeSpeed(); + void computeDistance(); + + // definition of task period time + static constexpr std::chrono::milliseconds kTaskPeriod = 400ms; + // definition of task execution time + static constexpr std::chrono::microseconds kTaskRunTime = 200000us; + + // constants related to speed computation + static constexpr float kWheelCircumference = 2.1f; + static constexpr uint8_t kTraySize = 50; + std::chrono::microseconds _lastTime = std::chrono::microseconds::zero(); + std::chrono::milliseconds _pedalRotationTime = kInitialPedalRotationTime; + + // data members + Timer& _timer; + LowPowerTicker _ticker; + float _currentSpeed = 0.0f; + Mutex _totalDistanceMutex; + float _totalDistance = 0.0f; + uint8_t _gearSize = 1; + + Thread _thread; + +#if defined(MBED_TEST_MODE) + mbed::Callback _cb; +#endif +}; + +} // namespace bike_computer \ No newline at end of file diff --git a/static_scheduling/gear_device.cpp b/static_scheduling/gear_device.cpp new file mode 100644 index 0000000..e120ce2 --- /dev/null +++ b/static_scheduling/gear_device.cpp @@ -0,0 +1,83 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file gear_device.cpp + * @author Serge Ayer + * + * @brief Gear Device implementation (static scheduling) + * + * @date 2023-08-20 + * @version 1.0.0 + ***************************************************************************/ + +#include "gear_device.hpp" + +// from disco_h747i/wrappers +#include + +#include "joystick.hpp" +#include "mbed_trace.h" + +#if MBED_CONF_MBED_TRACE_ENABLE +#define TRACE_GROUP "GearDevice" +#endif // MBED_CONF_MBED_TRACE_ENABLE + +namespace static_scheduling { + +// definition of task execution time +static constexpr std::chrono::microseconds kTaskRunTime = 100000us; + +GearDevice::GearDevice(Timer& timer) : _timer(timer) {} + +uint8_t GearDevice::getCurrentGear() { + std::chrono::microseconds initialTime = _timer.elapsed_time(); + std::chrono::microseconds elapsedTime = std::chrono::microseconds::zero(); + // we bound the change to one increment/decrement per call + bool hasChanged = false; + while (elapsedTime < kTaskRunTime) { + if (!hasChanged) { + disco::Joystick::State joystickState = + disco::Joystick::getInstance().getState(); + switch (joystickState) { + case disco::Joystick::State::UpPressed: + if (_currentGear < bike_computer::kMaxGear) { + _currentGear++; + } + hasChanged = true; + break; + + case disco::Joystick::State::DownPressed: + if (_currentGear > bike_computer::kMinGear) { + _currentGear--; + } + hasChanged = true; + break; + + default: + break; + } + } + elapsedTime = _timer.elapsed_time() - initialTime; + } + return _currentGear; +} + +uint8_t GearDevice::getCurrentGearSize() const { + // simulate task computation by waiting for the required task run time + // wait_us(kTaskRunTime.count()); + return bike_computer::kMaxGearSize - _currentGear; +} + +} // namespace static_scheduling \ No newline at end of file diff --git a/static_scheduling/gear_device.hpp b/static_scheduling/gear_device.hpp new file mode 100644 index 0000000..d44d6f7 --- /dev/null +++ b/static_scheduling/gear_device.hpp @@ -0,0 +1,50 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file gear_device.hpp + * @author Serge Ayer + * + * @brief Gear Device header file (static scheduling) + * + * @date 2023-08-20 + * @version 1.0.0 + ***************************************************************************/ + +#pragma once + +#include "constants.hpp" +#include "mbed.h" + +namespace static_scheduling { + +class GearDevice { + public: + explicit GearDevice(Timer& timer); // NOLINT(runtime/references) + + // make the class non copyable + GearDevice(GearDevice&) = delete; + GearDevice& operator=(GearDevice&) = delete; + + // method called for updating the bike system + uint8_t getCurrentGear(); + uint8_t getCurrentGearSize() const; + + private: + // data members + uint8_t _currentGear = bike_computer::kMinGear; + Timer& _timer; +}; + +} // namespace static_scheduling \ No newline at end of file From db2d5308bc14cd5ea7e40cb0d1cd071d5f46ea32 Mon Sep 17 00:00:00 2001 From: fastium Date: Tue, 29 Oct 2024 16:16:30 +0100 Subject: [PATCH 4/7] ADD tests for speedometer and sensor-device --- TESTS/bike-computer/sensor-device/main.cpp | 69 ++++ TESTS/bike-computer/speedometer/main.cpp | 354 +++++++++++++++++++++ 2 files changed, 423 insertions(+) create mode 100644 TESTS/bike-computer/sensor-device/main.cpp create mode 100644 TESTS/bike-computer/speedometer/main.cpp diff --git a/TESTS/bike-computer/sensor-device/main.cpp b/TESTS/bike-computer/sensor-device/main.cpp new file mode 100644 index 0000000..9792526 --- /dev/null +++ b/TESTS/bike-computer/sensor-device/main.cpp @@ -0,0 +1,69 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file main.cpp + * @author Serge Ayer + * + * @brief Bike computer test suite: sensor device + * + * @date 2023-08-26 + * @version 0.1.0 + ***************************************************************************/ + +#include "greentea-client/test_env.h" +#include "hdc1000.hpp" +#include "mbed.h" +#include "sensor_device.hpp" +#include "unity/unity.h" +#include "utest/utest.h" + +using namespace utest::v1; + +// test_hdc1000 test handler function +static control_t test_sensor_device(const size_t call_count) { + // create the SensorDevice instance + bike_computer::SensorDevice sensorDevice; + + bool rc = sensorDevice.init(); + TEST_ASSERT_TRUE(rc); + + float temperature = sensorDevice.readTemperature(); + static constexpr float kTemperatureRange = 20.0f; + static constexpr float kMeanTemperature = 15.0f; + TEST_ASSERT_FLOAT_WITHIN(kTemperatureRange, kMeanTemperature, temperature); + + float humidity = sensorDevice.readHumidity(); + static constexpr float kHumidityRange = 40.0f; + static constexpr float kMeanHumidity = 50.0f; + TEST_ASSERT_FLOAT_WITHIN(kHumidityRange, kMeanHumidity, humidity); + + // execute the test only once and move to the next one, without waiting + return CaseNext; +} + +static utest::v1::status_t greentea_setup(const size_t number_of_cases) { + // Here, we specify the timeout (60s) and the host test (a built-in host test or the + // name of our Python file) + GREENTEA_SETUP(60, "default_auto"); + + return greentea_test_setup_handler(number_of_cases); +} + +// List of test cases in this file +static Case cases[] = {Case("test sensor device", test_sensor_device)}; + +static Specification specification(greentea_setup, cases); + +int main() { return !Harness::run(specification); } \ No newline at end of file diff --git a/TESTS/bike-computer/speedometer/main.cpp b/TESTS/bike-computer/speedometer/main.cpp new file mode 100644 index 0000000..26a2906 --- /dev/null +++ b/TESTS/bike-computer/speedometer/main.cpp @@ -0,0 +1,354 @@ +// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/**************************************************************************** + * @file main.cpp + * @author Serge Ayer + * + * @brief Bike computer test suite: speedometer device + * + * @date 2023-08-26 + * @version 0.1.0 + ***************************************************************************/ + +#include + +#include "common/constants.hpp" +#include "common/speedometer.hpp" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "static_scheduling/gear_device.hpp" +#include "unity/unity.h" +#include "utest/utest.h" + +using namespace utest::v1; + +// allow for 0.1 km/h difference +static constexpr float kAllowedSpeedDelta = 0.1f; +// allow for 1m difference +static constexpr float kAllowedDistanceDelta = 1.0f / 1000.0; + +// function called by test handler functions for verifying the current speed +void check_current_speed(const std::chrono::milliseconds& pedalRotationTime, + uint8_t traySize, + uint8_t gearSize, + float wheelCircumference, + float currentSpeed) { + // compute the number of pedal rotation per hour + uint32_t milliSecondsPerHour = 1000 * 3600; + float pedalRotationsPerHour = static_cast(milliSecondsPerHour) / + static_cast(pedalRotationTime.count()); + + // compute the expected speed in km / h + // first compute the distance in meter for each pedal turn + float trayGearRatio = static_cast(traySize) / static_cast(gearSize); + float distancePerPedalTurn = trayGearRatio * wheelCircumference; + float expectedSpeed = (distancePerPedalTurn / 1000.0f) * pedalRotationsPerHour; + + printf(" Expected speed is %f, current speed is %f\n", expectedSpeed, currentSpeed); + TEST_ASSERT_FLOAT_WITHIN(kAllowedSpeedDelta, expectedSpeed, currentSpeed); +} + +// compute the traveled distance for a time interval +float compute_distance(const std::chrono::milliseconds& pedalRotationTime, + uint8_t traySize, + uint8_t gearSize, + float wheelCircumference, + const std::chrono::milliseconds& travelTime) { + // compute the number of pedal rotation during travel time + // both times are expressed in ms + float pedalRotations = static_cast(travelTime.count()) / + static_cast(pedalRotationTime.count()); + + // compute the distance in meter for each pedal turn + float trayGearRatio = static_cast(traySize) / static_cast(gearSize); + float distancePerPedalTurn = trayGearRatio * wheelCircumference; + + // distancePerPedalTurn is expressed in m, divide per 1000 for a distance in km + return (distancePerPedalTurn * pedalRotations) / 1000.0; +} + +// function called by test handler functions for verifying the distance traveled +void check_distance(const std::chrono::milliseconds& pedalRotationTime, + uint8_t traySize, + uint8_t gearSize, + float wheelCircumference, + const std::chrono::milliseconds& travelTime, + float distance) { + // distancePerPedalTurn is expressed in m, divide per 1000 for a distance in km + float expectedDistance = compute_distance( + pedalRotationTime, traySize, gearSize, wheelCircumference, travelTime); + printf(" Expected distance is %f, current distance is %f\n", + expectedDistance, + distance); + TEST_ASSERT_FLOAT_WITHIN(kAllowedDistanceDelta, expectedDistance, distance); +} + +// test the speedometer by modifying the gear +static control_t test_gear_size(const size_t call_count) { + // create a timer + Timer timer; + // start the timer + timer.start(); + + // create a speedometer instance + bike_computer::Speedometer speedometer(timer); + + // get speedometer constant values (for this test) + const auto traySize = speedometer.getTraySize(); + const auto wheelCircumference = speedometer.getWheelCircumference(); + const auto pedalRotationTime = speedometer.getCurrentPedalRotationTime(); + + for (uint8_t gearSize = bike_computer::kMinGearSize; + gearSize <= bike_computer::kMaxGearSize; + gearSize++) { + // set the gear + printf("Testing gear size %d\n", gearSize); + speedometer.setGearSize(gearSize); + + // get the current speed + auto currentSpeed = speedometer.getCurrentSpeed(); + + // check the speed against the expected one + check_current_speed( + pedalRotationTime, traySize, gearSize, wheelCircumference, currentSpeed); + } + + // execute the test only once and move to the next one, without waiting + return CaseNext; +} + +// test the speedometer by modifying the pedal rotation speed +static control_t test_rotation_speed(const size_t call_count) { + // create a timer + Timer timer; + // start the timer + timer.start(); + + // create a speedometer instance + bike_computer::Speedometer speedometer(timer); + + // set the gear size + speedometer.setGearSize(bike_computer::kMaxGearSize); + + // get speedometer constant values + const auto traySize = speedometer.getTraySize(); + const auto wheelCircumference = speedometer.getWheelCircumference(); + const auto gearSize = speedometer.getGearSize(); + + // first test increasing rotation speed (decreasing rotation time) + auto pedalRotationTime = speedometer.getCurrentPedalRotationTime(); + while (pedalRotationTime > bike_computer::kMinPedalRotationTime) { + // decrease the pedal rotation time + pedalRotationTime -= bike_computer::kDeltaPedalRotationTime; + speedometer.setCurrentRotationTime(pedalRotationTime); + + // get the current speed + const auto currentSpeed = speedometer.getCurrentSpeed(); + + // check the speed against the expected one + check_current_speed( + pedalRotationTime, traySize, gearSize, wheelCircumference, currentSpeed); + } + + // second test decreasing rotation speed (increasing rotation time) + pedalRotationTime = speedometer.getCurrentPedalRotationTime(); + while (pedalRotationTime < bike_computer::kMaxPedalRotationTime) { + // increase the pedal rotation time + pedalRotationTime += bike_computer::kDeltaPedalRotationTime; + speedometer.setCurrentRotationTime(pedalRotationTime); + + // get the current speed + const auto currentSpeed = speedometer.getCurrentSpeed(); + + // check the speed against the expected one + check_current_speed( + pedalRotationTime, traySize, gearSize, wheelCircumference, currentSpeed); + } + + // execute the test only once and move to the next one, without waiting + return CaseNext; +} + +// test the speedometer by modifying the pedal rotation speed +static control_t test_distance(const size_t call_count) { + // create a timer + Timer timer; + + // create a speedometer instance + bike_computer::Speedometer speedometer(timer); + + // set the gear size + speedometer.setGearSize(bike_computer::kMaxGearSize); + + // get speedometer constant values + const auto traySize = speedometer.getTraySize(); + const auto wheelCircumference = speedometer.getWheelCircumference(); + auto gearSize = speedometer.getGearSize(); + auto pedalRotationTime = speedometer.getCurrentPedalRotationTime(); + + // test different travel times + const std::chrono::milliseconds travelTimes[] = {500ms, 1000ms, 5s, 10s}; + const uint8_t nbrOfTravelTimes = sizeof(travelTimes) / sizeof(travelTimes[0]); + + // start the timer (for simulating bike start) + timer.start(); + + // first check travel distance without changing gear and rotation speed + std::chrono::milliseconds totalTravelTime = std::chrono::milliseconds::zero(); + for (uint8_t index = 0; index < nbrOfTravelTimes; index++) { + // run for the travel time and get the distance + ThisThread::sleep_for(travelTimes[index]); + + // get the distance traveled + const auto distance = speedometer.getDistance(); + + // accumulate travel time + totalTravelTime += travelTimes[index]; + + // check the distance vs the expected one + check_distance(pedalRotationTime, + traySize, + gearSize, + wheelCircumference, + totalTravelTime, + distance); + } + + // now change gear at each time interval + auto expectedDistance = speedometer.getDistance(); + for (uint8_t index = 0; index < nbrOfTravelTimes; index++) { + // update the gear size + gearSize++; + speedometer.setGearSize(gearSize); + + // run for the travel time and get the distance + ThisThread::sleep_for(travelTimes[index]); + + // compute the expected distance for this time segment + float distance = compute_distance(pedalRotationTime, + traySize, + gearSize, + wheelCircumference, + travelTimes[index]); + expectedDistance += distance; + + // get the distance traveled + const auto traveledDistance = speedometer.getDistance(); + + printf(" Expected distance is %f, current distance is %f\n", + expectedDistance, + traveledDistance); + TEST_ASSERT_FLOAT_WITHIN( + kAllowedDistanceDelta, expectedDistance, traveledDistance); + } + // now change rotation speed at each time interval + expectedDistance = speedometer.getDistance(); + for (uint8_t index = 0; index < nbrOfTravelTimes; index++) { + // update the rotation speed + pedalRotationTime += bike_computer::kDeltaPedalRotationTime; + speedometer.setCurrentRotationTime(pedalRotationTime); + + // run for the travel time and get the distance + ThisThread::sleep_for(travelTimes[index]); + + // compute the expected distance for this time segment + float distance = compute_distance(pedalRotationTime, + traySize, + gearSize, + wheelCircumference, + travelTimes[index]); + expectedDistance += distance; + + // get the distance traveled + const auto traveledDistance = speedometer.getDistance(); + + printf(" Expected distance is %f, current distance is %f\n", + expectedDistance, + traveledDistance); + TEST_ASSERT_FLOAT_WITHIN( + kAllowedDistanceDelta, expectedDistance, traveledDistance); + } + + // execute the test only once and move to the next one, without waiting + return CaseNext; +} + +// test the speedometer by modifying the pedal rotation speed +static control_t test_reset(const size_t call_count) { + // create a timer instance + Timer timer; + + // create a speedometer instance + bike_computer::Speedometer speedometer(timer); + + // set the gear size + speedometer.setGearSize(bike_computer::kMinGearSize); + + // get speedometer constant values + const auto traySize = speedometer.getTraySize(); + const auto wheelCircumference = speedometer.getWheelCircumference(); + const auto gearSize = speedometer.getGearSize(); + const auto pedalRotationTime = speedometer.getCurrentPedalRotationTime(); + + // start the timer (for simulating bike start) + timer.start(); + + // travel for 1 second + const auto travelTime = 1000ms; + ThisThread::sleep_for(travelTime); + + // check the expected distaance traveled + const auto expectedDistance = compute_distance( + pedalRotationTime, traySize, gearSize, wheelCircumference, travelTime); + + // get the distance traveled + auto traveledDistance = speedometer.getDistance(); + + printf(" Expected distance is %f, current distance is %f\n", + expectedDistance, + traveledDistance); + TEST_ASSERT_FLOAT_WITHIN(kAllowedDistanceDelta, expectedDistance, traveledDistance); + + // reset the speedometer + speedometer.reset(); + + // traveled distance should now be zero + traveledDistance = speedometer.getDistance(); + + printf(" Expected distance is %f, current distance is %f\n", 0.0f, traveledDistance); + TEST_ASSERT_FLOAT_WITHIN(kAllowedDistanceDelta, 0.0f, traveledDistance); + + // execute the test only once and move to the next one, without waiting + return CaseNext; +} + +static utest::v1::status_t greentea_setup(const size_t number_of_cases) { + // Here, we specify the timeout (60s) and the host test (a built-in host test or the + // name of our Python file) + GREENTEA_SETUP(180, "default_auto"); + + return greentea_test_setup_handler(number_of_cases); +} + +// List of test cases in this file +static Case cases[] = { + Case("test speedometer gear size change", test_gear_size), + Case("test speedometer rotation speed change", test_rotation_speed), + Case("test speedometer distance", test_distance), + Case("test speedometer reset", test_reset)}; + +static Specification specification(greentea_setup, cases); + +int main() { return !Harness::run(specification); } \ No newline at end of file From 0d18073562267ee0f13bfe9a3658698858e77855 Mon Sep 17 00:00:00 2001 From: fastium Date: Tue, 29 Oct 2024 17:10:58 +0100 Subject: [PATCH 5/7] ADD (WIP) speedometer implementation --- common/speedometer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/speedometer.cpp b/common/speedometer.cpp index a30ecaa..7f1b4c1 100644 --- a/common/speedometer.cpp +++ b/common/speedometer.cpp @@ -24,6 +24,8 @@ #include "speedometer.hpp" +#include "static_scheduling/gear_device.hpp" + #include #include @@ -106,8 +108,9 @@ void Speedometer::computeSpeed() { // ~= 560 m / min = 33.6 km/h // TODO - - + //Distance run with one pedal turn = tray size / rear gear size * circumference of the wheel + std::chrono::seconds pedal_rotation_time = std::chrono::duration_cast(this->_pedalRotationTime).count(); + this->_currentSpeed = static_cast(kTraySize) / this->_gearSize * this->kWheelCircumference * ; } void Speedometer::computeDistance() { @@ -120,6 +123,7 @@ void Speedometer::computeDistance() { // distance traveled. // TODO + } } // namespace bike_computer \ No newline at end of file From ac8e030089c557acbdbe0d10d53662ca8950b24e Mon Sep 17 00:00:00 2001 From: fastium Date: Tue, 5 Nov 2024 15:30:12 +0100 Subject: [PATCH 6/7] ADD speedometer implementation --- common/speedometer.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/common/speedometer.cpp b/common/speedometer.cpp index 7f1b4c1..19ba566 100644 --- a/common/speedometer.cpp +++ b/common/speedometer.cpp @@ -107,10 +107,13 @@ void Speedometer::computeSpeed() { // = 6.99m If you ride at 80 pedal turns / min, you run a distance of 6.99 * 80 / min // ~= 560 m / min = 33.6 km/h - // TODO + // TODO : done //Distance run with one pedal turn = tray size / rear gear size * circumference of the wheel - std::chrono::seconds pedal_rotation_time = std::chrono::duration_cast(this->_pedalRotationTime).count(); - this->_currentSpeed = static_cast(kTraySize) / this->_gearSize * this->kWheelCircumference * ; + float ms_in_hour = static_cast(3600 * 1000); + float pedal_rotation_per_hour = ms_in_hour / static_cast(_pedalRotationTime.count()); + float gear_ratio = static_cast(kTraySize) / static_cast(this->_gearSize); + float wheel_dist_km = static_cast(this->kWheelCircumference) / 1000.0; + this->_currentSpeed = gear_ratio * wheel_dist_km * pedal_rotation_per_hour; } void Speedometer::computeDistance() { @@ -122,8 +125,14 @@ void Speedometer::computeDistance() { // ~= 560 m / min = 33.6 km/h. We then multiply the speed by the time for getting the // distance traveled. - // TODO - + // TODO : done + Speedometer::computeSpeed(); + // compute distance + float last_time_in_hour = static_cast(std::chrono::duration_cast(this->_lastTime).count()); + float traveled_dist = this->_currentSpeed * last_time_in_hour; + this->_totalDistanceMutex.lock(); + this->_totalDistance += traveled_dist; + this->_totalDistanceMutex.unlock(); } } // namespace bike_computer \ No newline at end of file From dc99ac08b5cd6609087f791336cd7f3175e6f59c Mon Sep 17 00:00:00 2001 From: fastium Date: Tue, 5 Nov 2024 16:21:51 +0100 Subject: [PATCH 7/7] ADD speedometer tests in CI for github --- .github/workflows/build-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 3db23d2..e2c92a3 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -20,7 +20,8 @@ jobs: tests-simple-unique-ptr, tests-simple-test-raw-ptr, advdembsof_library-tests-sensors-hdc1000, - tests-bike-computer-sensor-device + tests-bike-computer-sensor-device, + tests-bike-computer-speedometer ]