HarmonyOS Sports Development: Calculating Outdoor Sports Step Frequency and Stride Length, and Drawing Map Routes
Foreword
In outdoor sports, step frequency (the number of steps per minute) and stride length (the distance of each step) are key indicators for measuring the efficiency and intensity of exercise. Whether you are a running enthusiast or a fitness expert, understanding these data can not only help you optimize your exercise performance but also effectively prevent sports injuries. However, how can we accurately calculate step frequency and stride length in the HarmonyOS system and display the sports trajectory in real time on the map? This article will combine practical development experience to deeply analyze the entire process from sensor data collection to core algorithm implementation and then to map route drawing, helping you master the precise calculation and visual display of outdoor sports data step by step.
I. Step Frequency and Stride Length: Key Indicators of Sports Data
Step frequency and stride length are two core indicators in sports data, which can intuitively reflect the rhythm and efficiency of exercise.
- Step Frequency: The Rhythm of Exercise
Step frequency refers to the number of steps per minute, usually used to measure the speed and rhythm of running or walking. A higher step frequency generally means a faster movement speed, but it may also lead to a decrease in efficiency due to excessive fatigue. The ideal step frequency varies from person to person. Generally speaking, a step frequency of 160-180 steps per minute is more ideal when running. For beginners, maintaining a stable step frequency is more important than pursuing a high step frequency because an excessively high step frequency may lead to physical fatigue and injury.
- Stride Length: The Efficiency of Exercise
Stride length refers to the length of each step, that is, the distance between the two feet. A larger stride length can increase the movement speed, but an excessively large stride length may lead to instability of the body's center of gravity and increase the risk of injury. Therefore, it is very important to reasonably control the stride length to improve the efficiency and safety of exercise. Generally speaking, the size of the stride length should be adjusted according to personal physical conditions and exercise habits. For example, people with a taller stature may have a larger stride length, but an excessively large stride length may cause excessive pressure on the knees and ankles.
II. HarmonyOS Step Counter Sensor: The Core Tool for Data Collection
In the HarmonyOS system, we can use the built-in step counter sensor (Pedometer) to obtain the step data during the exercise process. The step counter sensor can monitor the user's steps in real time and provide accurate step counting statistics. Below are the usage methods and key code analysis of the step counter sensor.
- Initialization of the Step Counter Sensor and Permission Request
Before using the step counter sensor, we need to request the motion permission and initialize the sensor service. Below is the relevant code:
import { sensor } from '@kit.SensorServiceKit';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { common } from '@kit.AbilityKit';
export class StepCounterService {
private static instance: StepCounterService;
private stepCount: number = 0; // Current cumulative step count
private initialStepCount: number = 0; // Initial step count
private isMonitoring: boolean = false; // Whether it is currently listening
private listeners: Array<(data: StepData) => void> = [];
private context: common.UIAbilityContext;
private constructor(context: common.UIAbilityContext) {
this.context = context;
}
public static getInstance(context: common.UIAbilityContext): StepCounterService {
if (!StepCounterService.instance) {
StepCounterService.instance = new StepCounterService(context);
}
return StepCounterService.instance;
}
// Request motion permission
private async requestMotionPermission(): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
try {
const result = await atManager.requestPermissionsFromUser(
this.context,
['ohos.permission.ACTIVITY_MOTION']
);
return result.permissions[0] === 'ohos.permission.ACTIVITY_MOTION' &&
result.authResults[0] === 0;
} catch (err) {
console.error('Permission request failed:', err);
return false;
}
}
}
In the above code, we request the motion permission through abilityAccessCtrl
and implement the initialization logic of the step counter sensor in the StepCounterService
class. Permission request is a key step to ensure the normal operation of the sensor. If the user does not grant the relevant permission, the sensor will not be able to work properly.
- Real-time Monitoring of Step Data
After initializing the sensor, we need to monitor the changes in step data and update the step data in real time. Below is the key code for monitoring step data changes:
public async startStepCounter(): Promise<void> {
if (this.isMonitoring) return;
const hasPermission = await this.requestMotionPermission();
if (!hasPermission) {
throw new Error('Motion sensor permission not granted');
}
try {
sensor.on(sensor.SensorId.PEDOMETER, (data: sensor.PedometerResponse) => {
this.deviceTotalSteps = data.steps;
if (this.initialStepCount === 0) {
this.initialStepCount = data.steps;
}
const deltaSteps = this.deviceTotalSteps - this.initialStepCount;
if (this.isPaused) {
// When paused, only update the device total steps, do not change the business steps
} else {
// Calculate the total steps of all paused intervals
const totalPausedSteps = this.pausedIntervals.reduce((sum, interval) => {
return sum + (interval.end - interval.start);
}, 0);
this.stepCount = deltaSteps - totalPausedSteps;
// Save the current step data
this.lastStepData = {
steps: this.stepCount
};
this.notifyListeners();
}
});
} catch (error) {
const e = error as BusinessError;
console.error(`Step counter subscription failed: Code=${e.code}, Message=${e.message}`);
throw error as Error;
}
}
public pauseStepCounter(): void {
if (!this.isMonitoring || this.isPaused) return;
this.pausedIntervals.push({
start: this.deviceTotalSteps,
end: 0
});
this.isPaused = true;
}
public resumeStepCounter(): void {
if (!this.isMonitoring || !this.isPaused) return;
const lastInterval = this.pausedIntervals[this.pausedIntervals.length - 1];
lastInterval.end = this.deviceTotalSteps;
this.isPaused = false;
}
// Stop listening
public stopStepCounter(): void {
if (!this.isMonitoring) return;
this.stepCount = 0;
this.initialStepCount = 0;
this.isPaused = false;
this.pausedIntervals = []; // Clear all paused records
try {
sensor.off(sensor.SensorId.PEDOMETER);
this.isMonitoring = false;
} catch (error) {
const e = error as BusinessError;
console.error(`Step counter unsubscribe failed: Code=${e.code}, Message=${e.message}`);
}
}
In the above code, we monitor the data changes of the step counter sensor through the sensor.on
method and calculate the current steps in real time. At the same time, we also handle the logic of pausing and resuming listening to ensure the accuracy of step counting. This is very useful for pauses during the exercise process (such as waiting for traffic lights), which can avoid step counting errors caused by pauses.
III. Calculation Logic of Step Frequency and Stride Length
With the step data, we can calculate step frequency and stride length. Below is the core logic for calculating step frequency and stride length.
- Calculation of Step Frequency
The formula for calculating step frequency is:
[
\text{Step Frequency}=\frac{\text{Step Difference}}{\text{Time Difference}}\times 60
]
In the actual code, we calculate the step frequency through two consecutive trajectory points (containing time and step information). Below is the relevant code:
if (this.previousPoint && this.previousPoint.steps > 0) {
const timeDiff = (point.timestamp - this.previousPoint.timestamp) / 1000; // Convert to seconds
const stepDiff = point.steps - this.previousPoint.steps;
if (timeDiff > 0 && stepDiff > 0) {
// Calculate step frequency (steps per minute)
const instantCadence = (stepDiff / timeDiff) * 60;
// Use moving average to smooth step frequency data
point.cadence = this.currentPoint.cadence * 0.7 + instantCadence * 0.3;
} else {
// If the time difference or step difference is 0, keep the data of the previous point
point.cadence = this.currentPoint.cadence;
}
} else {
// The first point, initialize to 0
point.cadence = 0;
}
In the above code, we calculate the instantaneous step frequency through the time difference and step difference of two trajectory points, and use the moving average to smooth the step frequency data to avoid excessive data fluctuations. The use of moving average can effectively reduce the step frequency data fluctuations caused by sensor errors or irregular user movements.
- Calculation of Stride Length
The formula for calculating stride length is:
[
\text{Stride Length}=\frac{\text{Distance Difference}}{\text{Step Difference}}
]
In the actual code, we calculate the stride length through two consecutive trajectory points (containing distance and step information). Below is the relevant code:
if (this.previousPoint && this.previousPoint.steps > 0) {
const distance = this.calculateDistance(this.previousPoint, point) * 1000; // Convert to meters
const stepDiff = point.steps - this.previousPoint.steps;
if (stepDiff > 0) {
// Calculate stride length (meters per step)
const instantStride = distance / stepDiff;
// Use moving average to smooth stride length data
point.stride = this.currentPoint.stride * 0.7 + instantStride * 0.3;
} else {
// If the step difference is 0, keep the data of the previous point
point.stride = this.currentPoint.stride;
}
} else {
// The first point, initialize to 0
point.stride = 0;
}
In the above code, we calculate the instantaneous stride length through the distance difference and step difference of two trajectory points, and use the moving average to smooth the stride length data. The calculation of stride length depends on the distance between trajectory points, so it is necessary to ensure the accuracy and density of trajectory points.
IV. Real-time Data Update and Display
During the outdoor sports process, we need to update the step frequency and stride length data in real time and display them to the user. This can not only help the user understand their current sports status in real time but also provide them with a basis for adjusting their sports rhythm and intensity. Below is the key code for data update and display:
- Data Update Logic
During the sports process, we calculate the step frequency and stride length in real time by monitoring the step counter sensor and trajectory point data, and store these data in the current trajectory point object. Below is the core code for data update:
// Update the trajectory point
this.currentPoint = point;
// Notify listeners
this.notifyListeners();
// Return the current total distance
return this.totalDistance;
In the above code, the notifyListeners
method is used to notify all registered listeners and pass the latest step frequency and stride length data to them. These listeners can be UI components or other services that require real-time data.
- Data Display
To display the step frequency and stride length data to the user, we need to update these data in real time on the application's interface. Below is a simple example code showing how to display step frequency and stride length in the UI:
// Assume there is a UI component to display step frequency and stride length
updateUI(point: RunPoint) {
this.cadenceDisplayElement.textContent = `Step Frequency: ${point.cadence.toFixed(2)} steps/minute`;
this.strideDisplayElement.textContent = `Stride Length: ${point.stride.toFixed(2)} meters/step`;
}
In the above code, cadenceDisplayElement
and strideDisplayElement
are HTML elements used to display step frequency and stride length. By calling the toFixed
method, we can format the values of step frequency and stride length to two decimal places, making the data more intuitive and readable.
V. Map Route Drawing: Real-time Trajectory Display
In addition to the calculation of step frequency and stride length, real-time drawing of sports trajectories is also an important feature of outdoor sports applications. Displaying the user's sports path on the map can help the user better understand their sports trajectory and also increase the fun of sports. Below is the core code for map route drawing:
- Initializing the Map
Before drawing the trajectory, we need to initialize the map. Here we take Baidu Map as an example:
import { MapController, Polyline, SysEnum } from '@ohos.maps';
// Initialize the map controller
this.mapController = new MapController(this.mapView);
// Set the map center point
this.mapController.setMapCenter({
latitude: this.startLatitude,
longitude: this.startLongitude,
});
In the above code, MapController
is the class used to control the map, and the setMapCenter
method is used to set the map center point. We usually use the user's starting position as the map center point.
- Drawing the Trajectory Line
During the sports process, we need to draw the trajectory line according to the user's real-time location. Below is the core code for drawing the trajectory line:
// Create a trajectory point array
this.trackPoints = [];
// Each time a new trajectory point is obtained, add it to the trajectory point array
this.trackPoints.push({
latitude: point.latitude,
longitude: point.longitude,
});
// Create a trajectory line
this.polyline = new Polyline({
points: this.trackPoints,
strokeColor: '#f0f', // Trajectory line color
strokeWidth: 20, // Trajectory line width
lineJoin: SysEnum.LineJoinType.ROUND, // Trajectory line connection method
lineCap: SysEnum.LineCapType.ROUND, // Trajectory line end point style
isThined: true, // Whether to simplify the trajectory line
});
// Add the trajectory line to the map
this.mapController.addOverlay(this.polyline);
In the above code, Polyline
is the class used to draw the trajectory line, and the points
property is an array containing the coordinates of the trajectory points. Each time a new trajectory point is obtained, we add this point to the trackPoints
array and recreate the trajectory line object. By calling the addOverlay
method, we can add the trajectory line to the map.
- Dynamically Updating the Trajectory
To achieve dynamic updating of the trajectory, we need to redraw the trajectory line each time a new trajectory point is obtained. Below is the core code for dynamically updating the trajectory:
// Update the trajectory point array
this.trackPoints.push({
latitude: point.latitude,
longitude: point.longitude,
});
this.mapController!.removeOverlay(this.polyline);
this.polyline.setPoints(this.trackPoints);
this.mapController!.addOverlay(this.polyline);
In the above code, the removeOverlay
method is used to clear the trajectory line's point array, the setPoints
method is used to update the trajectory line's point array, and the addOverlay
method is used to redraw the trajectory line. In this way, we can achieve real-time updating of the trajectory, allowing users to see their sports trajectory during the sports process.
VI. Summary
Through the HarmonyOS step counter sensor and map service, we have achieved accurate calculation of step frequency and stride length in outdoor sports, as well as real-time drawing of sports trajectories.
Top comments (0)