Skip to content

Commit 63de1b5

Browse files
committed
pybricks.robotics.DriveBase: Implement arc method.
See pybricks/support#1157
1 parent 4f1041a commit 63de1b5

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
slots on the Prime Hub and Inventor Hub.
2323
- Added ability to set distance and angle in `DriveBase.reset()`. If the
2424
DriveBase is using the gyro, it will be set to the same angle. ([support#1617]).
25+
- Added `DriveBase.arc` method with more intuitive parameters to drive along
26+
an arc, to eventually replace `DriveBase.curve` ([support#1157]).
2527

2628
### Changed
2729

@@ -59,6 +61,7 @@
5961
[pybricks-micropython#254]: https://github.com/pybricks/pybricks-micropython/pull/254
6062
[pybricks-micropython#261]: https://github.com/pybricks/pybricks-micropython/pull/261
6163
[support#1105]: https://github.com/pybricks/support/issues/1105
64+
[support#1157]: https://github.com/pybricks/support/issues/1157
6265
[support#1429]: https://github.com/pybricks/support/issues/1429
6366
[support#1460]: https://github.com/pybricks/support/issues/1460
6467
[support#1615]: https://github.com/pybricks/support/issues/1615

lib/pbio/include/pbio/drivebase.h

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pbio_error_t pbio_drivebase_is_stalled(pbio_drivebase_t *db, bool *stalled, uint
6363

6464
pbio_error_t pbio_drivebase_drive_straight(pbio_drivebase_t *db, int32_t distance, pbio_control_on_completion_t on_completion);
6565
pbio_error_t pbio_drivebase_drive_curve(pbio_drivebase_t *db, int32_t radius, int32_t angle, pbio_control_on_completion_t on_completion);
66+
pbio_error_t pbio_drivebase_drive_arc_angle(pbio_drivebase_t *db, int32_t radius, int32_t angle, pbio_control_on_completion_t on_completion);
67+
pbio_error_t pbio_drivebase_drive_arc_distance(pbio_drivebase_t *db, int32_t radius, int32_t distance, pbio_control_on_completion_t on_completion);
6668

6769
// Infinite driving:
6870

lib/pbio/src/drivebase.c

+71
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,9 @@ pbio_error_t pbio_drivebase_drive_straight(pbio_drivebase_t *db, int32_t distanc
616616
/**
617617
* Starts the drivebase controllers to run by an arc of given radius and angle.
618618
*
619+
* curve() was originally used as a generalization of turn(), but is now
620+
* deprecated in favor of the arc methods, which have more practical arguments.
621+
*
619622
* This will use the default speed.
620623
*
621624
* @param [in] db The drivebase instance.
@@ -636,6 +639,74 @@ pbio_error_t pbio_drivebase_drive_curve(pbio_drivebase_t *db, int32_t radius, in
636639
return pbio_drivebase_drive_relative(db, arc_length, 0, arc_angle, 0, on_completion);
637640
}
638641

642+
/**
643+
* Starts the drivebase controllers to run by an arc of given radius and angle.
644+
*
645+
* With a positive radius, the robot drives along a circle to its right.
646+
* With a negative radius, the robot drives along a circle to its left.
647+
*
648+
* A positive angle means driving forward along the circle, negative is reverse.
649+
*
650+
* This will use the default speed.
651+
*
652+
* @param [in] db The drivebase instance.
653+
* @param [in] radius Radius of the arc in mm.
654+
* @param [in] angle The angle to drive along the circle in degrees.
655+
* @param [in] on_completion What to do when reaching the target.
656+
* @return Error code.
657+
*/
658+
pbio_error_t pbio_drivebase_drive_arc_angle(pbio_drivebase_t *db, int32_t radius, int32_t angle, pbio_control_on_completion_t on_completion) {
659+
660+
if (pbio_int_math_abs(radius) < 10) {
661+
return PBIO_ERROR_INVALID_ARG;
662+
}
663+
664+
// Arc length is radius * angle, with the user angle parameter governing
665+
// the drive direction as positive forward.
666+
int32_t drive_distance = (10 * angle * pbio_int_math_abs(radius)) / 573;
667+
668+
// The user angle is positive for going forward, no matter the radius sign.
669+
// The internal functions expect positive to mean clockwise for the robot.
670+
int32_t direction = (radius > 0) == (angle > 0) ? 1 : -1;
671+
int32_t drive_angle = pbio_int_math_abs(angle) * direction;
672+
673+
// Execute the common drive command at default speed (by passing 0 speed).
674+
return pbio_drivebase_drive_relative(db, drive_distance, 0, drive_angle, 0, on_completion);
675+
}
676+
677+
/**
678+
* Starts the drivebase controllers to run by an arc of given radius and arc length.
679+
*
680+
* With a positive radius, the robot drives along a circle to its right.
681+
* With a negative radius, the robot drives along a circle to its left.
682+
*
683+
* A positive distance means driving forward along the circle, negative is reverse.
684+
*
685+
* This will use the default speed.
686+
*
687+
* @param [in] db The drivebase instance.
688+
* @param [in] radius Radius of the arc in mm.
689+
* @param [in] distance The distance to drive (arc length) in mm.
690+
* @param [in] on_completion What to do when reaching the target.
691+
* @return Error code.
692+
*/
693+
pbio_error_t pbio_drivebase_drive_arc_distance(pbio_drivebase_t *db, int32_t radius, int32_t distance, pbio_control_on_completion_t on_completion) {
694+
695+
if (pbio_int_math_abs(radius) < 10) {
696+
return PBIO_ERROR_INVALID_ARG;
697+
}
698+
699+
// The internal functions expect positive to mean clockwise for the robot
700+
// with respect to the ground, not in relation to any particular circle.
701+
int32_t angle = pbio_int_math_abs(distance) * 573 / pbio_int_math_abs(radius) / 10;
702+
if ((radius < 0) != (distance < 0)) {
703+
angle *= -1;
704+
}
705+
706+
// Execute the common drive command at default speed (by passing 0 speed).
707+
return pbio_drivebase_drive_relative(db, distance, 0, angle, 0, on_completion);
708+
}
709+
639710
/**
640711
* Starts the drivebase controllers to run for a given duration.
641712
*

pybricks/robotics/pb_type_drivebase.c

+34
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,39 @@ static mp_obj_t pb_type_DriveBase_curve(size_t n_args, const mp_obj_t *pos_args,
184184
}
185185
static MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_DriveBase_curve_obj, 1, pb_type_DriveBase_curve);
186186

187+
// pybricks.robotics.DriveBase.arc
188+
static mp_obj_t pb_type_DriveBase_arc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
189+
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
190+
pb_type_DriveBase_obj_t, self,
191+
PB_ARG_REQUIRED(radius),
192+
PB_ARG_DEFAULT_NONE(distance),
193+
PB_ARG_DEFAULT_NONE(angle),
194+
PB_ARG_DEFAULT_OBJ(then, pb_Stop_HOLD_obj),
195+
PB_ARG_DEFAULT_TRUE(wait));
196+
197+
// Parse user arguments.
198+
mp_int_t radius = pb_obj_get_int(radius_in);
199+
if ((distance_in == mp_const_none) == (angle_in == mp_const_none)) {
200+
mp_raise_ValueError(MP_ERROR_TEXT("Please specify distance or angle but not both."));
201+
}
202+
203+
pbio_control_on_completion_t then = pb_type_enum_get_value(then_in, &pb_enum_type_Stop);
204+
205+
if (distance_in != mp_const_none) {
206+
pb_assert(pbio_drivebase_drive_arc_distance(self->db, radius, pb_obj_get_int(distance_in), then));
207+
} else {
208+
pb_assert(pbio_drivebase_drive_arc_angle(self->db, radius, pb_obj_get_int(angle_in), then));
209+
}
210+
211+
// Old way to do parallel movement is to start and not wait on anything.
212+
if (!mp_obj_is_true(wait_in)) {
213+
return mp_const_none;
214+
}
215+
// Handle completion by awaiting or blocking.
216+
return await_or_wait(self);
217+
}
218+
static MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_DriveBase_arc_obj, 1, pb_type_DriveBase_arc);
219+
187220
// pybricks.robotics.DriveBase.drive
188221
static mp_obj_t pb_type_DriveBase_drive(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
189222
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
@@ -359,6 +392,7 @@ static const pb_attr_dict_entry_t pb_type_DriveBase_attr_dict[] = {
359392

360393
// dir(pybricks.robotics.DriveBase)
361394
static const mp_rom_map_elem_t pb_type_DriveBase_locals_dict_table[] = {
395+
{ MP_ROM_QSTR(MP_QSTR_arc), MP_ROM_PTR(&pb_type_DriveBase_arc_obj) },
362396
{ MP_ROM_QSTR(MP_QSTR_curve), MP_ROM_PTR(&pb_type_DriveBase_curve_obj) },
363397
{ MP_ROM_QSTR(MP_QSTR_straight), MP_ROM_PTR(&pb_type_DriveBase_straight_obj) },
364398
{ MP_ROM_QSTR(MP_QSTR_turn), MP_ROM_PTR(&pb_type_DriveBase_turn_obj) },

0 commit comments

Comments
 (0)