• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pybricks / pybricks-micropython / 19016791193

02 Nov 2025 06:40PM UTC coverage: 57.167% (-2.6%) from 59.744%
19016791193

Pull #406

github

laurensvalk
bricks/virtualhub: Replace with embedded simulation.

Instead of using the newly introduced simhub alongside the virtualhub, we'll just replace the old one entirely now that it has reached feature parity. We can keep calling it the virtualhub.
Pull Request #406: New virtual hub for more effective debugging

41 of 48 new or added lines in 7 files covered. (85.42%)

414 existing lines in 53 files now uncovered.

4479 of 7835 relevant lines covered (57.17%)

17178392.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.45
/lib/pbio/src/differentiator.c
1
// SPDX-License-Identifier: MIT
2
// Copyright (c) 2022-2023 The Pybricks Authors
3

4
// SPDX-License-Identifier: BSD-3-Clause
5
// Copyright (c) 2022-2023 LEGO System A/S
6

7
#include <stdbool.h>
8
#include <stdint.h>
9
#include <stdlib.h>
10

11
#include <pbio/config.h>
12
#include <pbio/control_settings.h>
13
#include <pbio/differentiator.h>
14
#include <pbio/int_math.h>
15
#include <pbio/util.h>
16

17
/**
18
 * Internal function to get the speed with a variable window size. Window
19
 * size must be validated externally for this function to be used safely.
20
 *
21
 * @param [in]  dif            The differentiator instance.
22
 * @param [in]  window_size    Window size in number of samples (Must be > 0 and <= buffer size!).
23
 * @param [out] speed          Average speed across given time window in mdeg/s.
24
 */
25
static int32_t pbio_differentiator_calc_speed(pbio_differentiator_t *dif, uint8_t window_size) {
53,761✔
26

27
    // Sum differences including start and endpoint.
28
    uint8_t start_index = (dif->index - (window_size - 1) + PBIO_ARRAY_SIZE(dif->history)) % PBIO_ARRAY_SIZE(dif->history);
53,761✔
29
    int32_t total = dif->history[dif->index];
53,761✔
30
    for (uint8_t i = start_index; i != dif->index; i = (i + 1) % PBIO_ARRAY_SIZE(dif->history)) {
1,075,220✔
31
        total += dif->history[i];
1,021,459✔
32
    }
33

34
    // Each sample has units of mdeg, so take average and convert to mdeg/s.
35
    return total * (1000 / PBIO_CONFIG_CONTROL_LOOP_TIME_MS) / window_size;
53,761✔
36
}
37

38
/**
39
 * Updates the angle buffer and calculates the average speed across buffer.
40
 *
41
 * @param [in]  dif            The differentiator instance.
42
 * @param [in]  angle          New angle sample to add to the buffer.
43
 * @return                     Average speed across position buffer.
44
 */
45
int32_t pbio_differentiator_update_and_get_speed(pbio_differentiator_t *dif, const pbio_angle_t *angle) {
53,713✔
46

47
    // Increment index where latest difference will be stored.
48
    dif->index = (dif->index + 1) % PBIO_ARRAY_SIZE(dif->history);
53,713✔
49

50
    // The difference is stored in millidegrees. Even at 6000 deg/s (well
51
    // above the physical limits of the motors we use), this at most
52
    // 6000 * 1000 * 0.005 = 30000, which fits in a 16-bit signed integer.
53
    dif->history[dif->index] = pbio_int_math_clamp(pbio_angle_diff_mdeg(angle, &dif->prev_angle), INT16_MAX);
53,713✔
54
    dif->prev_angle = *angle;
53,713✔
55

56
    // Calculate the speed.
57
    return pbio_differentiator_calc_speed(dif, PBIO_CONFIG_DIFFERENTIATOR_WINDOW_SIZE);
53,713✔
58
}
59

60
/**
61
 * Gets the speed with a variable window size. This can be called by the user
62
 * to get a smoothed speed value.
63
 *
64
 * @param [in]  dif            The differentiator instance.
65
 * @param [in]  window         Window size in milliseconds.
66
 * @param [out] speed          Average speed across given time window.
67
 * @return                     ::PBIO_SUCCESS if successful, ::PBIO_ERROR_INVALID_ARG if window is 0 or bigger than the buffer size.
68
 */
69
pbio_error_t pbio_differentiator_get_speed(pbio_differentiator_t *dif, uint32_t window, int32_t *speed) {
48✔
70

71
    // Round window to nearest sample size.
72
    uint8_t window_size = (window + PBIO_CONFIG_CONTROL_LOOP_TIME_MS / 2) / PBIO_CONFIG_CONTROL_LOOP_TIME_MS;
48✔
73
    if (window_size == 0 || window_size > PBIO_ARRAY_SIZE(dif->history) - 1) {
48✔
UNCOV
74
        return PBIO_ERROR_INVALID_ARG;
×
75
    }
76

77
    // Speed is determined as position delta across the given window.
78
    *speed = pbio_differentiator_calc_speed(dif, window_size);
48✔
79
    return PBIO_SUCCESS;
48✔
80
}
81

82
/**
83
 * Resets the position angle buffer in order to set speed to zero.
84
 *
85
 * @param [in]  dif            The differentiator instance.
86
 * @param [in]  angle          New angle sample to add to the buffer.
87
 */
88
void pbio_differentiator_reset(pbio_differentiator_t *dif, const pbio_angle_t *angle) {
27✔
89
    dif->prev_angle = *angle;
27✔
90
    for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(dif->history); i++) {
1,674✔
91
        dif->history[i] = 0;
1,647✔
92
    }
93
}
27✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc