@@ -105,7 +105,7 @@ static PT_THREAD(test_drivebase_basics(struct pt *pt)) {
105105 turn_acceleration ,
106106 turn_deceleration ), = = , PBIO_ERROR_INVALID_ARG );
107107
108- // Try to set invalid settings.
108+ // Try to set valid settings.
109109 tt_uint_op (pbio_drivebase_set_drive_settings (db ,
110110 200 ,
111111 drive_acceleration * 2 ,
@@ -183,7 +183,92 @@ static PT_THREAD(test_drivebase_basics(struct pt *pt)) {
183183 PT_END (pt );
184184}
185185
186+ /**
187+ * Creates a drivebase pair where one of the motors (C) is physically stalled at
188+ * about +/- 150 degrees. Motor F can spin freely.
189+ */
190+ static PT_THREAD (test_drivebase_stalling (struct pt * pt )) {
191+
192+ static struct timer timer ;
193+
194+ static pbio_servo_t * srv_free ;
195+ static pbio_servo_t * srv_blocked ;
196+ static pbdrv_legodev_dev_t * legodev_left ;
197+ static pbdrv_legodev_dev_t * legodev_right ;
198+ static pbio_drivebase_t * db ;
199+
200+ static int32_t drive_distance ;
201+ static int32_t drive_speed ;
202+ static int32_t turn_angle_start ;
203+ static int32_t turn_rate ;
204+
205+ static bool stalled ;
206+ static uint32_t stall_duration ;
207+
208+ // Start motor driver simulation process.
209+ pbdrv_motor_driver_init_manual ();
210+
211+ PT_BEGIN (pt );
212+
213+ // Wait for motor simulation process to be ready.
214+ while (pbdrv_init_busy ()) {
215+ PT_YIELD (pt );
216+ }
217+
218+ // Start motor control process manually.
219+ pbio_motor_process_start ();
220+
221+ // Initialize the servos.
222+
223+ pbdrv_legodev_type_id_t id = PBDRV_LEGODEV_TYPE_ID_ANY_ENCODED_MOTOR ;
224+ tt_uint_op (pbdrv_legodev_get_device (PBIO_PORT_ID_F , & id , & legodev_left ), = = , PBIO_SUCCESS );
225+ tt_uint_op (pbio_servo_get_servo (legodev_left , & srv_free ), = = , PBIO_SUCCESS );
226+ tt_uint_op (pbio_servo_setup (srv_free , id , PBIO_DIRECTION_COUNTERCLOCKWISE , 1000 , true, 0 ), = = , PBIO_SUCCESS );
227+ id = PBDRV_LEGODEV_TYPE_ID_ANY_ENCODED_MOTOR ;
228+ tt_uint_op (pbdrv_legodev_get_device (PBIO_PORT_ID_C , & id , & legodev_right ), = = , PBIO_SUCCESS );
229+ tt_uint_op (pbio_servo_get_servo (legodev_right , & srv_blocked ), = = , PBIO_SUCCESS );
230+ tt_uint_op (pbio_servo_setup (srv_blocked , id , PBIO_DIRECTION_CLOCKWISE , 1000 , true, 0 ), = = , PBIO_SUCCESS );
231+
232+ // Set up the drivebase.
233+ tt_uint_op (pbio_drivebase_get_drivebase (& db , srv_free , srv_blocked , 56000 , 112000 ), = = , PBIO_SUCCESS );
234+ tt_uint_op (pbio_drivebase_get_state_user (db , & drive_distance , & drive_speed , & turn_angle_start , & turn_rate ), = = , PBIO_SUCCESS );
235+ tt_uint_op (pbio_drivebase_is_stalled (db , & stalled , & stall_duration ), = = , PBIO_SUCCESS );
236+ tt_want (!stalled );
237+
238+ // Try to drive straight. Should get stalled.
239+ tt_uint_op (pbio_drivebase_drive_straight (db , 1000 , PBIO_CONTROL_ON_COMPLETION_COAST_SMART ), = = , PBIO_SUCCESS );
240+ pbio_test_sleep_until (pbio_drivebase_is_stalled (db , & stalled , & stall_duration ) == PBIO_SUCCESS && stalled );
241+
242+ // Stop. Now we should not be stalled any more.
243+ tt_uint_op (pbio_drivebase_stop (db , PBIO_CONTROL_ON_COMPLETION_COAST ), = = , PBIO_SUCCESS );
244+ tt_uint_op (pbio_drivebase_is_stalled (db , & stalled , & stall_duration ), = = , PBIO_SUCCESS );
245+ tt_want (!stalled );
246+
247+ // Run the individual servos back to the start position.
248+ tt_uint_op (pbio_servo_run_target (srv_free , 500 , 0 , PBIO_CONTROL_ON_COMPLETION_COAST ), = = , PBIO_SUCCESS );
249+ tt_uint_op (pbio_servo_run_target (srv_blocked , 500 , 0 , PBIO_CONTROL_ON_COMPLETION_COAST ), = = , PBIO_SUCCESS );
250+ pbio_test_sleep_until (pbio_control_is_done (& srv_free -> control ) && pbio_control_is_done (& srv_blocked -> control ));
251+
252+ // Stall the individual servos.
253+ tt_uint_op (pbio_servo_run_target (srv_free , 500 , 360 , PBIO_CONTROL_ON_COMPLETION_COAST ), = = , PBIO_SUCCESS );
254+ tt_uint_op (pbio_servo_run_target (srv_blocked , 500 , 360 , PBIO_CONTROL_ON_COMPLETION_COAST ), = = , PBIO_SUCCESS );
255+ pbio_test_sleep_ms (& timer , 2000 );
256+
257+ // The blocked motor should be stalled, the free motor not stalled, and the drivebase stalled.
258+ tt_uint_op (pbio_servo_is_stalled (srv_blocked , & stalled , & stall_duration ), = = , PBIO_SUCCESS );
259+ tt_want (stalled );
260+ tt_uint_op (pbio_servo_is_stalled (srv_free , & stalled , & stall_duration ), = = , PBIO_SUCCESS );
261+ tt_want (!stalled );
262+ tt_uint_op (pbio_drivebase_is_stalled (db , & stalled , & stall_duration ), = = , PBIO_SUCCESS );
263+ tt_want (stalled );
264+
265+ end :
266+
267+ PT_END (pt );
268+ }
269+
186270struct testcase_t pbio_drivebase_tests [] = {
187271 PBIO_PT_THREAD_TEST (test_drivebase_basics ),
272+ PBIO_PT_THREAD_TEST (test_drivebase_stalling ),
188273 END_OF_TESTCASES
189274};
0 commit comments