|
16 | 16 | #include <tinytest_macros.h> |
17 | 17 |
|
18 | 18 | #include <pbdrv/motor_driver.h> |
| 19 | +#include <pbio/angle.h> |
19 | 20 | #include <pbio/control.h> |
20 | 21 | #include <pbio/error.h> |
21 | 22 | #include <pbio/logger.h> |
@@ -138,8 +139,67 @@ static PT_THREAD(test_servo_stall(struct pt *pt)) { |
138 | 139 | PT_END(pt); |
139 | 140 | } |
140 | 141 |
|
| 142 | +static PT_THREAD(test_servo_gearing(struct pt *pt)) { |
| 143 | + |
| 144 | + static struct timer timer; |
| 145 | + static pbio_servo_t *srv_basic; |
| 146 | + static pbio_servo_t *srv_geared; |
| 147 | + static int32_t angle; |
| 148 | + static int32_t speed; |
| 149 | + static const int32_t geared_target = 90; |
| 150 | + |
| 151 | + // Start motor driver simulation process. |
| 152 | + pbdrv_motor_driver_init_manual(); |
| 153 | + |
| 154 | + PT_BEGIN(pt); |
| 155 | + |
| 156 | + // Wait for motor simulation process to be ready. |
| 157 | + while (pbdrv_init_busy()) { |
| 158 | + PT_YIELD(pt); |
| 159 | + } |
| 160 | + |
| 161 | + // Start motor control process manually. |
| 162 | + pbio_motor_process_start(); |
| 163 | + |
| 164 | + // Initialize a servo without gears (1000 mdeg rotation per 1 deg output) |
| 165 | + tt_uint_op(pbio_servo_get_servo(PBIO_PORT_ID_E, &srv_basic), ==, PBIO_SUCCESS); |
| 166 | + tt_uint_op(pbio_servo_setup(srv_basic, PBIO_DIRECTION_CLOCKWISE, 1000, true, 0), ==, PBIO_SUCCESS); |
| 167 | + tt_uint_op(pbio_servo_reset_angle(srv_basic, 0, false), ==, PBIO_SUCCESS); |
| 168 | + |
| 169 | + // Initialize a servo with 12:36 gears (3000 mdeg rotation per 1 deg output) |
| 170 | + tt_uint_op(pbio_servo_get_servo(PBIO_PORT_ID_F, &srv_geared), ==, PBIO_SUCCESS); |
| 171 | + tt_uint_op(pbio_servo_setup(srv_geared, PBIO_DIRECTION_CLOCKWISE, 3000, true, 0), ==, PBIO_SUCCESS); |
| 172 | + tt_uint_op(pbio_servo_reset_angle(srv_geared, 0, false), ==, PBIO_SUCCESS); |
| 173 | + |
| 174 | + // Rotate both motors to +90 degrees. |
| 175 | + tt_uint_op(pbio_servo_run_target(srv_basic, 200, geared_target, PBIO_CONTROL_ON_COMPLETION_HOLD), ==, PBIO_SUCCESS); |
| 176 | + tt_uint_op(pbio_servo_run_target(srv_geared, 200, geared_target, PBIO_CONTROL_ON_COMPLETION_HOLD), ==, PBIO_SUCCESS); |
| 177 | + srv_geared->control.settings.position_tolerance = 2000; |
| 178 | + pbio_test_sleep_until(pbio_control_is_done(&srv_basic->control) && pbio_control_is_done(&srv_geared->control)); |
| 179 | + |
| 180 | + // For both, the user angle should match target. |
| 181 | + tt_uint_op(pbio_servo_get_state_user(srv_basic, &angle, &speed), ==, PBIO_SUCCESS); |
| 182 | + tt_want(pbio_test_int_is_close(angle, geared_target, 5)); |
| 183 | + tt_uint_op(pbio_servo_get_state_user(srv_geared, &angle, &speed), ==, PBIO_SUCCESS); |
| 184 | + tt_want(pbio_test_int_is_close(angle, geared_target, 5)); |
| 185 | + |
| 186 | + // Internally, the geared motor should have traveled trice as much. |
| 187 | + pbio_control_state_t state; |
| 188 | + pbio_angle_t angle_zero = (pbio_angle_t) {.rotations = 0, .millidegrees = 0}; |
| 189 | + tt_uint_op(pbio_servo_get_state_control(srv_basic, &state), ==, PBIO_SUCCESS); |
| 190 | + tt_want(pbio_test_int_is_close(pbio_angle_diff_mdeg(&state.position, &angle_zero), geared_target * 1000, 5000)); |
| 191 | + tt_uint_op(pbio_servo_get_state_control(srv_geared, &state), ==, PBIO_SUCCESS); |
| 192 | + tt_want(pbio_test_int_is_close(pbio_angle_diff_mdeg(&state.position, &angle_zero), geared_target * 3 * 1000, 5000)); |
| 193 | + pbio_test_sleep_ms(&timer, 2000); |
| 194 | + |
| 195 | +end: |
| 196 | + |
| 197 | + PT_END(pt); |
| 198 | +} |
| 199 | + |
141 | 200 | struct testcase_t pbio_servo_tests[] = { |
142 | 201 | PBIO_PT_THREAD_TEST(test_servo_basics), |
143 | 202 | PBIO_PT_THREAD_TEST(test_servo_stall), |
| 203 | + PBIO_PT_THREAD_TEST(test_servo_gearing), |
144 | 204 | END_OF_TESTCASES |
145 | 205 | }; |
0 commit comments