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

pybricks / pybricks-micropython / 6675885095

28 Oct 2023 08:38AM UTC coverage: 56.053% (+10.0%) from 46.074%
6675885095

push

github

laurensvalk
pybricks.hubs.MoveHub: Use standard hub init.

The Move Hub cannot have true vector axes, but we can still use this API to initialize the hub using numeric indices.

This ensures we can use the custom orientation not just in tilt, but also in acceleration like we do on other hubs.

3616 of 6451 relevant lines covered (56.05%)

20895680.75 hits per line

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

20.47
/pybricks/common/pb_type_control.c
1
// SPDX-License-Identifier: MIT
2
// Copyright (c) 2018-2023 The Pybricks Authors
3

4
#include <pbio/control.h>
5

6
#include "py/mpconfig.h"
7
#include "py/obj.h"
8

9
#include <pybricks/common.h>
10

11
#include <pybricks/util_pb/pb_error.h>
12
#include <pybricks/util_mp/pb_obj_helper.h>
13
#include <pybricks/util_mp/pb_kwarg_helper.h>
14

15
mp_obj_t make_acceleration_return_value(int32_t acceleration, int32_t deceleration) {
×
16
    // For backwards compatibility, return a single integer if acceleration
17
    // and deceleration are equal.
18
    if (acceleration == deceleration) {
×
19
        return mp_obj_new_int(acceleration);
×
20
    }
21
    // Otherwise return a tuple with both values.
22
    mp_obj_t accel[] = {
×
23
        mp_obj_new_int(acceleration),
×
24
        mp_obj_new_int(deceleration),
×
25
    };
26
    return mp_obj_new_tuple(MP_ARRAY_SIZE(accel), accel);
×
27
}
28

29
void unpack_acceleration_value(mp_obj_t accel_in, int32_t *acceleration, int32_t *deceleration) {
4✔
30
    // If no acceleration was given, leave values unchanged.
31
    if (accel_in == mp_const_none) {
4✔
32
        return;
4✔
33
    }
34

35
    // If single value is given for acceleration, use it for deceleration too.
36
    if (mp_obj_is_int(accel_in) || mp_obj_is_float(accel_in)) {
2✔
37
        *acceleration = pb_obj_get_int(accel_in);
2✔
38
        *deceleration = *acceleration;
2✔
39
        return;
2✔
40
    }
41

42
    // Otherwise attempt to unpack acceleration and deceleration from tuple,
43
    // raising if something invalid was given.
44
    mp_obj_t *values;
×
45
    size_t n;
×
46
    mp_obj_get_array(accel_in, &n, &values);
×
47
    if (n != 2) {
×
48
        pb_assert(PBIO_ERROR_INVALID_ARG);
×
49
    }
50
    *acceleration = pb_obj_get_int(values[0]);
×
51
    *deceleration = pb_obj_get_int(values[1]);
×
52
}
53

54
#if PYBRICKS_PY_COMMON_CONTROL
55

56
// pybricks._common.Control class object structure
57
typedef struct _pb_type_Control_obj_t {
58
    mp_obj_base_t base;
59
    pbio_control_t *control;
60
    mp_obj_t scale;
61
    #if PYBRICKS_PY_COMMON_LOGGER
62
    mp_obj_t logger;
63
    #endif
64
} pb_type_Control_obj_t;
65

66
// pybricks._common.Control.__init__/__new__
67
mp_obj_t pb_type_Control_obj_make_new(pbio_control_t *control) {
11✔
68

69
    pb_type_Control_obj_t *self = mp_obj_malloc(pb_type_Control_obj_t, &pb_type_Control);
11✔
70

71
    self->control = control;
11✔
72

73
    #if PYBRICKS_PY_COMMON_LOGGER
74
    // Create an instance of the Logger class
75
    self->logger = common_Logger_obj_make_new(&self->control->log, PBIO_CONTROL_LOGGER_NUM_COLS);
11✔
76
    #endif
77

78
    self->scale = mp_obj_new_int(control->settings.ctl_steps_per_app_step);
11✔
79

80
    return MP_OBJ_FROM_PTR(self);
11✔
81
}
82

83
// pybricks._common.Control.limits
84
STATIC mp_obj_t pb_type_Control_limits(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
2✔
85

86
    PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
2✔
87
        pb_type_Control_obj_t, self,
88
        PB_ARG_DEFAULT_NONE(speed),
89
        PB_ARG_DEFAULT_NONE(acceleration),
90
        PB_ARG_DEFAULT_NONE(torque));
2✔
91

92
    // Read current values.
93
    int32_t speed, acceleration, deceleration, torque;
2✔
94
    pbio_control_settings_get_trajectory_limits(&self->control->settings, &speed, &acceleration, &deceleration);
2✔
95
    torque = pbio_control_settings_get_actuation_limit(&self->control->settings);
2✔
96

97
    // If all given values are none, return current values
98
    if (speed_in == mp_const_none && acceleration_in == mp_const_none && torque_in == mp_const_none) {
2✔
99
        mp_obj_t ret[] = {
×
100
            mp_obj_new_int(speed),
×
101
            make_acceleration_return_value(acceleration, deceleration),
×
102
            mp_obj_new_int(torque),
×
103
        };
104
        return mp_obj_new_tuple(MP_ARRAY_SIZE(ret), ret);
×
105
    }
106

107
    // Set user settings if given, else keep using current values.
108
    speed = pb_obj_get_default_abs_int(speed_in, speed);
2✔
109
    torque = pb_obj_get_default_abs_int(torque_in, torque);
2✔
110
    unpack_acceleration_value(acceleration_in, &acceleration, &deceleration);
2✔
111

112
    // Set new values.
113
    pb_assert(pbio_control_settings_set_trajectory_limits(&self->control->settings, speed, acceleration, deceleration));
2✔
114
    pb_assert(pbio_control_settings_set_actuation_limit(&self->control->settings, torque));
1✔
115

116
    return mp_const_none;
1✔
117
}
118
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_Control_limits_obj, 1, pb_type_Control_limits);
119

120
// pybricks._common.Control.pid
121
STATIC mp_obj_t pb_type_Control_pid(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
×
122

123
    PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
×
124
        pb_type_Control_obj_t, self,
125
        PB_ARG_DEFAULT_NONE(kp),
126
        PB_ARG_DEFAULT_NONE(ki),
127
        PB_ARG_DEFAULT_NONE(kd),
128
        PB_ARG_DEFAULT_NONE(integral_deadzone),
129
        PB_ARG_DEFAULT_NONE(integral_rate));
×
130

131
    // Read current values
132
    int32_t kp, ki, kd;
×
133
    int32_t integral_change_max, integral_deadzone;
×
134
    pbio_control_settings_get_pid(&self->control->settings, &kp, &ki, &kd, &integral_deadzone, &integral_change_max);
×
135

136
    // If all given values are none, return current values
137
    if (kp_in == mp_const_none && ki_in == mp_const_none && kd_in == mp_const_none &&
×
138
        integral_rate_in == mp_const_none) {
×
139
        mp_obj_t ret[5];
×
140
        ret[0] = mp_obj_new_int(kp);
×
141
        ret[1] = mp_obj_new_int(ki);
×
142
        ret[2] = mp_obj_new_int(kd);
×
143
        ret[3] = mp_obj_new_int(integral_deadzone);
×
144
        ret[4] = mp_obj_new_int(integral_change_max);
×
145
        return mp_obj_new_tuple(5, ret);
×
146
    }
147

148
    // Set user settings
149
    kp = pb_obj_get_default_abs_int(kp_in, kp);
×
150
    ki = pb_obj_get_default_abs_int(ki_in, ki);
×
151
    kd = pb_obj_get_default_abs_int(kd_in, kd);
×
152
    integral_change_max = pb_obj_get_default_abs_int(integral_rate_in, integral_change_max);
×
153
    integral_deadzone = pb_obj_get_default_abs_int(integral_deadzone_in, integral_deadzone);
×
154

155
    pb_assert(pbio_control_settings_set_pid(&self->control->settings, kp, ki, kd, integral_deadzone, integral_change_max));
×
156

157
    return mp_const_none;
×
158
}
159
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_Control_pid_obj, 1, pb_type_Control_pid);
160

161
// pybricks._common.Control.target_tolerances
162
STATIC mp_obj_t pb_type_Control_target_tolerances(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
×
163

164
    PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
×
165
        pb_type_Control_obj_t, self,
166
        PB_ARG_DEFAULT_NONE(speed),
167
        PB_ARG_DEFAULT_NONE(position));
×
168

169
    // Read current values
170
    int32_t speed, position;
×
171
    pbio_control_settings_get_target_tolerances(&self->control->settings, &speed, &position);
×
172

173
    // If all given values are none, return current values
174
    if (speed_in == mp_const_none && position_in == mp_const_none) {
×
175
        mp_obj_t ret[2];
×
176
        ret[0] = mp_obj_new_int(speed);
×
177
        ret[1] = mp_obj_new_int(position);
×
178
        return mp_obj_new_tuple(2, ret);
×
179
    }
180

181
    // Set user settings
182
    speed = pb_obj_get_default_abs_int(speed_in, speed);
×
183
    position = pb_obj_get_default_abs_int(position_in, position);
×
184

185
    pb_assert(pbio_control_settings_set_target_tolerances(&self->control->settings, speed, position));
×
186

187
    return mp_const_none;
×
188
}
189
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_Control_target_tolerances_obj, 1, pb_type_Control_target_tolerances);
190

191
// pybricks._common.Control.stall_tolerances
192
STATIC mp_obj_t pb_type_Control_stall_tolerances(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
×
193

194
    PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
×
195
        pb_type_Control_obj_t, self,
196
        PB_ARG_DEFAULT_NONE(speed),
197
        PB_ARG_DEFAULT_NONE(time));
×
198

199
    // Read current values
200
    int32_t speed;
×
201
    uint32_t time;
×
202
    pbio_control_settings_get_stall_tolerances(&self->control->settings, &speed, &time);
×
203

204
    // If all given values are none, return current values
205
    if (speed_in == mp_const_none && time_in == mp_const_none) {
×
206
        mp_obj_t ret[2];
×
207
        ret[0] = mp_obj_new_int(speed);
×
208
        ret[1] = mp_obj_new_int_from_uint(time);
×
209
        return mp_obj_new_tuple(2, ret);
×
210
    }
211

212
    // Set user settings
213
    speed = pb_obj_get_default_abs_int(speed_in, speed);
×
214
    time = pb_obj_get_default_abs_int(time_in, time);
×
215

216
    pb_assert(pbio_control_settings_set_stall_tolerances(&self->control->settings, speed, time));
×
217

218
    return mp_const_none;
×
219
}
220
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_Control_stall_tolerances_obj, 1, pb_type_Control_stall_tolerances);
221

222
// pybricks._common.Control.trajectory
223
STATIC mp_obj_t pb_type_Control_trajectory(mp_obj_t self_in) {
×
224
    pb_type_Control_obj_t *self = MP_OBJ_TO_PTR(self_in);
×
225
    pbio_trajectory_t *trj = &self->control->trajectory;
×
226

227
    mp_obj_t parms[13];
×
228

229
    if (pbio_control_is_active(self->control)) {
×
230
        parms[0] = mp_obj_new_int(0);
×
231
        parms[1] = mp_obj_new_int(trj->t1 / 10);
×
232
        parms[2] = mp_obj_new_int(trj->t2 / 10);
×
233
        parms[3] = mp_obj_new_int(trj->t3 / 10);
×
234
        parms[4] = mp_obj_new_int(0);
×
235
        parms[5] = mp_obj_new_int(trj->th1 / 1000);
×
236
        parms[6] = mp_obj_new_int(trj->th2 / 1000);
×
237
        parms[7] = mp_obj_new_int(trj->th3 / 1000);
×
238
        parms[8] = mp_obj_new_int(trj->w0 / 10);
×
239
        parms[9] = mp_obj_new_int(trj->w1 / 10);
×
240
        parms[10] = mp_obj_new_int(trj->w3 / 10);
×
241
        parms[11] = mp_obj_new_int(trj->a0);
×
242
        parms[12] = mp_obj_new_int(trj->a2);
×
243
        return mp_obj_new_tuple(13, parms);
×
244
    }
245
    return mp_const_none;
246
}
247
MP_DEFINE_CONST_FUN_OBJ_1(pb_type_Control_trajectory_obj, pb_type_Control_trajectory);
248

249
// DELETEME: This method should not be used in V3.2 or later. It may be removed
250
// in a future version
251
// pybricks._common.Control.done
252
STATIC mp_obj_t pb_type_Control_done(mp_obj_t self_in) {
×
253
    pb_type_Control_obj_t *self = MP_OBJ_TO_PTR(self_in);
×
254
    return mp_obj_new_bool(pbio_control_is_done(self->control));
×
255
}
256
MP_DEFINE_CONST_FUN_OBJ_1(pb_type_Control_done_obj, pb_type_Control_done);
257

258
// DELETEME: This method should not be used in V3.2 or later. It may be removed
259
// in a future version
260
// pybricks._common.Control.load
261
STATIC mp_obj_t pb_type_Control_load(mp_obj_t self_in) {
×
262
    pb_type_Control_obj_t *self = MP_OBJ_TO_PTR(self_in);
×
263

264
    if (!pbio_control_is_active(self->control)) {
×
265
        return mp_obj_new_int(0);
×
266
    }
267

268
    // Read currently applied PID feedback torque and return as mNm.
269
    return mp_obj_new_int(self->control->pid_average / 1000);
×
270
}
271
MP_DEFINE_CONST_FUN_OBJ_1(pb_type_Control_load_obj, pb_type_Control_load);
272

273
// DELETEME: This method should not be used in V3.2 or later. It may be removed
274
// in a future version
275
// pybricks._common.Control.stalled
276
STATIC mp_obj_t pb_type_Control_stalled(mp_obj_t self_in) {
×
277
    pb_type_Control_obj_t *self = MP_OBJ_TO_PTR(self_in);
×
278
    uint32_t stall_duration;
×
279
    return mp_obj_new_bool(pbio_control_is_stalled(self->control, &stall_duration));
×
280
}
281
MP_DEFINE_CONST_FUN_OBJ_1(pb_type_Control_stalled_obj, pb_type_Control_stalled);
282

283
STATIC const pb_attr_dict_entry_t pb_type_Control_attr_dict[] = {
284
    PB_DEFINE_CONST_ATTR_RO(MP_QSTR_scale, pb_type_Control_obj_t, scale),
285
    #if PYBRICKS_PY_COMMON_LOGGER
286
    PB_DEFINE_CONST_ATTR_RO(MP_QSTR_log, pb_type_Control_obj_t, logger),
287
    #endif // PYBRICKS_PY_COMMON_LOGGER
288
    PB_ATTR_DICT_SENTINEL
289
};
290

291
// dir(pybricks.common.Control)
292
STATIC const mp_rom_map_elem_t pb_type_Control_locals_dict_table[] = {
293
    { MP_ROM_QSTR(MP_QSTR_limits), MP_ROM_PTR(&pb_type_Control_limits_obj) },
294
    { MP_ROM_QSTR(MP_QSTR_pid), MP_ROM_PTR(&pb_type_Control_pid_obj) },
295
    { MP_ROM_QSTR(MP_QSTR_target_tolerances), MP_ROM_PTR(&pb_type_Control_target_tolerances_obj) },
296
    { MP_ROM_QSTR(MP_QSTR_stall_tolerances), MP_ROM_PTR(&pb_type_Control_stall_tolerances_obj) },
297
    { MP_ROM_QSTR(MP_QSTR_trajectory), MP_ROM_PTR(&pb_type_Control_trajectory_obj) },
298
    { MP_ROM_QSTR(MP_QSTR_done), MP_ROM_PTR(&pb_type_Control_done_obj) },
299
    { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&pb_type_Control_load_obj) },
300
    { MP_ROM_QSTR(MP_QSTR_stalled), MP_ROM_PTR(&pb_type_Control_stalled_obj) },
301
};
302
STATIC MP_DEFINE_CONST_DICT(pb_type_Control_locals_dict, pb_type_Control_locals_dict_table);
303

304
// type(pybricks.common.Control)
305
MP_DEFINE_CONST_OBJ_TYPE(pb_type_Control,
306
    MP_QSTR_Control,
307
    MP_TYPE_FLAG_NONE,
308
    attr, pb_attribute_handler,
309
    protocol, pb_type_Control_attr_dict,
310
    locals_dict, &pb_type_Control_locals_dict);
311

312
#endif // PYBRICKS_PY_COMMON_CONTROL
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