diff --git a/apps/tuya.ai/your_otto_robot/app_default.config b/apps/tuya.ai/your_otto_robot/app_default.config index d2af09973..98a85f22e 100755 --- a/apps/tuya.ai/your_otto_robot/app_default.config +++ b/apps/tuya.ai/your_otto_robot/app_default.config @@ -1,6 +1,7 @@ CONFIG_PROJECT_VERSION="1.0.2" -CONFIG_APP_UI_EYES_240_240=y +CONFIG_TUYA_PRODUCT_ID="b05nl7xoijx4fwae" +CONFIG_APP_UI_EYES_160_160=y CONFIG_BOARD_CHOICE_T5AI=y CONFIG_BOARD_CHOICE_T5AI_OTTO=y -CONFIG_T5AI_OTTO_EX_MODULE_ST7789=y +CONFIG_T5AI_OTTO_EX_MODULE_GC9D01=y CONFIG_ENABLE_LIBLVGL=y diff --git a/apps/tuya.ai/your_otto_robot/src/otto/oscillator.c b/apps/tuya.ai/your_otto_robot/src/otto/oscillator.c index 388b63e9f..74b5d7f6b 100644 --- a/apps/tuya.ai/your_otto_robot/src/otto/oscillator.c +++ b/apps/tuya.ai/your_otto_robot/src/otto/oscillator.c @@ -101,7 +101,7 @@ void oscillator_attach(int idx, int pin, bool rev) osc->rev = rev; osc->pwm_channel = (TUYA_PWM_NUM_E)pin; - // 打印初始化信息 + // Print initialization information PR_DEBUG("oscillator_attach: idx=%d, pin=%d, pwm_channel=%d, rev=%s", idx, pin, osc->pwm_channel, rev ? "true" : "false"); @@ -277,13 +277,13 @@ void oscillator_write(int idx, int position) angle = MIN(MAX(angle, 0), 180); - // 计算占空比 + // Calculate duty cycle uint32_t duty = (uint32_t)((0.5 + angle / 180.0 * 2.0) * 10000 / 20); - // 计算占空比百分比 (duty/10000 * 100) + // Calculate duty cycle percentage (duty/10000 * 100) //float duty_percent = (float)duty / 100.0f; - // 合并的占空比打印信息 - 显示百分比 + // Combined duty cycle print information - display percentage // PR_DEBUG("oscillator_write: idx=%d, pin=%d, pwm_channel=%d, pos=%d->angle=%d(trim:%d), duty=%d, duty_percent=%.1f%%", // idx, osc->pin, osc->pwm_channel, position, angle, osc->trim, duty, duty_percent); diff --git a/apps/tuya.ai/your_otto_robot/src/otto/otto_movements.c b/apps/tuya.ai/your_otto_robot/src/otto/otto_movements.c index abc49af6a..9af3aef05 100644 --- a/apps/tuya.ai/your_otto_robot/src/otto/otto_movements.c +++ b/apps/tuya.ai/your_otto_robot/src/otto/otto_movements.c @@ -23,8 +23,8 @@ static unsigned long millis() } /** - * @brief 重置所有振荡器相位到初始状态 - * 解决相位累积导致的不协调问题 + * @brief Reset all oscillator phases to initial state + * Resolves coordination issues caused by phase accumulation */ static void otto_reset_all_oscillators(void) { @@ -246,7 +246,7 @@ void otto_execute(int amplitude[SERVO_COUNT], int offset[SERVO_COUNT], int perio g_otto.is_otto_resting = false; } - // 关键修复:在开始执行前重置所有振荡器相位,确保每次运动都从相同初始状态开始 + // Critical fix: Reset all oscillator phases before starting execution to ensure each movement starts from the same initial state otto_reset_all_oscillators(); int cycles = (int)steps; @@ -269,7 +269,7 @@ void otto_home(bool hands_down) // if (g_otto.is_otto_resting == false) { // Go to rest position only if necessary - // 关键修复:在回到home位置前,先重置所有振荡器相位,确保状态完全重置 + // Critical fix: Reset all oscillator phases before returning to home position to ensure complete state reset otto_reset_all_oscillators(); int homes[SERVO_COUNT]; diff --git a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.c b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.c index 0cc71bb08..1de59cb40 100644 --- a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.c +++ b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.c @@ -18,6 +18,7 @@ #include "tkl_pwm.h" // Tuya PWM definitions #include "tkl_output.h" // Tuya GPIO definitions #include "otto_ninja_app_servo.h" // Pin definitions and function declarations +#include "tal_log.h" // ==================== Tuya Platform Interface Implementation ==================== @@ -169,10 +170,10 @@ void platform_tuya_init(void) #define SERVO_MAX_PULSE 2500 // ==================== Calibration Parameters ==================== -#define LFFWRS 20 // Left foot forward rotation speed -#define RFFWRS 20 // Right foot forward rotation speed -#define LFBWRS 20 // Left foot backward rotation speed -#define RFBWRS 20 // Right foot backward rotation speed +#define LFFWRS 20 // Left foot forward rotation speed (increased to compensate for counterclockwise turn) +#define RFFWRS 12 // Right foot forward rotation speed (further reduced to prevent large right foot span and counterclockwise turn) +#define LFBWRS 5 // Left foot backward rotation speed (increased to reduce left turn in backward) +#define RFBWRS 5 // Right foot backward rotation speed (reduced to decrease clockwise rotation time) #define LA0 60 // Left leg standing position #define RA0 120 // Right leg standing position @@ -200,6 +201,12 @@ static servo_t servos[MAX_SERVO_COUNT]; // Time control variable static uint32_t currentmillis1 = 0; +// Rotate spot state variables +static bool sg_rotate_spot_active = false; // Whether rotate spot is active +static uint16_t sg_right_foot_angle = 90; // Current right foot angle (0-180) +static uint32_t sg_last_foot_update = 0; // Last foot angle update time +static uint32_t sg_angle_accumulator = 0; // Angle accumulator for smooth rotation (0-36000, represents 0.0-360.0 degrees with 0.01 degree precision) + // ==================== Utility Functions ==================== /** @@ -320,6 +327,78 @@ void servo_detach(uint8_t pin) servos[idx].attached = false; } +/** + * Smooth servo angle transition + * Gradually transition from current angle to target angle to avoid sudden changes + * + * @param pin Servo pin + * @param target_angle Target angle (0-180 degrees) + * @param step_delay_ms Delay time per step (milliseconds), controls speed + * @param step_size Angle increment per step, controls smoothness + */ +void servo_write_smooth(uint8_t pin, uint16_t target_angle, uint16_t step_delay_ms, uint16_t step_size) +{ + int idx = get_servo_index(pin); + + // If servo not found, try to attach + if (idx < 0) { + servo_attach(pin, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + idx = get_servo_index(pin); + if (idx < 0) return; // Attach failed, exit + } + + // If servo not attached, auto attach + if (!servos[idx].attached) { + servo_attach(pin, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + } + + // Limit target angle range + if (target_angle > 180) target_angle = 180; + + // Get current angle + uint16_t current_angle = servos[idx].current_angle; + + // If already at target position, return directly + if (current_angle == target_angle) { + return; + } + + // Determine step direction + int16_t direction = (target_angle > current_angle) ? 1 : -1; + int16_t angle_diff = (target_angle > current_angle) ? + (target_angle - current_angle) : + (current_angle - target_angle); + + // Gradual transition + uint16_t steps = (angle_diff + step_size - 1) / step_size; // Round up + if (steps == 0) steps = 1; // At least one step + + for (uint16_t i = 0; i < steps; i++) { + // Calculate target angle for current step + uint16_t step_angle = current_angle + (direction * step_size * (i + 1)); + + // Ensure not exceeding target angle + if (direction > 0) { + if (step_angle > target_angle) step_angle = target_angle; + } else { + if (step_angle < target_angle) step_angle = target_angle; + } + + // Set servo angle + servo_write(pin, step_angle); + + // Delay to ensure servo execution + if (i < steps - 1) { // Last step doesn't need delay + delay_ms(step_delay_ms); + } + } + + // Ensure final target angle is reached + if (servos[idx].current_angle != target_angle) { + servo_write(pin, target_angle); + } +} + // ==================== Initialization Functions ==================== @@ -368,6 +447,15 @@ void servo_detach(uint8_t pin) delay_ms(400); #endif + // Attach leg servos + servo_attach(SERVO_LEFT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + servo_attach(SERVO_RIGHT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + + // Set leg positions + servo_write(SERVO_LEFT_LEG_PIN, LA0); + servo_write(SERVO_RIGHT_LEG_PIN, RA0); + delay_ms(1000); + // Attach feet servos servo_attach(SERVO_LEFT_FOOT_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); servo_attach(SERVO_RIGHT_FOOT_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); @@ -377,15 +465,6 @@ void servo_detach(uint8_t pin) servo_write(SERVO_RIGHT_FOOT_PIN, 90); delay_ms(400); - // Attach leg servos - servo_attach(SERVO_LEFT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - servo_attach(SERVO_RIGHT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - - // Set leg positions - servo_write(SERVO_LEFT_LEG_PIN, LA0); - servo_write(SERVO_RIGHT_LEG_PIN, RA0); - delay_ms(400); - // Detach all servos servo_detach(SERVO_LEFT_FOOT_PIN); servo_detach(SERVO_RIGHT_FOOT_PIN); @@ -402,72 +481,82 @@ void servo_detach(uint8_t pin) /** * Set walk mode + * Use smooth transition function with progressive PWM output, keep PWM running */ void robot_set_walk(void) { + PR_NOTICE("robot_set_walk"); #if ARM_HEAD_ENABLE == 1 - // Arms to middle position + // Step 1: Smooth transition of arms to middle position (90 degrees) + // 2 degrees per step, 15ms delay, ensures smooth transition + // Keep PWM running, don't detach servo_attach(SERVO_LEFT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); servo_attach(SERVO_RIGHT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - servo_write(SERVO_LEFT_ARM_PIN, 90); - servo_write(SERVO_RIGHT_ARM_PIN, 90); - delay_ms(200); - servo_detach(SERVO_LEFT_ARM_PIN); - servo_detach(SERVO_RIGHT_ARM_PIN); + servo_write_smooth(SERVO_LEFT_ARM_PIN, 90, 15, 2); + servo_write_smooth(SERVO_RIGHT_ARM_PIN, 90, 15, 2); + delay_ms(200); // Wait for servo stabilization + // Keep PWM running, don't detach #endif - // Ankles to standing position + // Step 2: Smooth transition of ankles to standing position (LA0, RA0) + // 2 degrees per step, 15ms delay, ensures smooth transition + // Keep PWM running, don't detach servo_attach(SERVO_LEFT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); servo_attach(SERVO_RIGHT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - servo_write(SERVO_LEFT_LEG_PIN, LA0); - servo_write(SERVO_RIGHT_LEG_PIN, RA0); - delay_ms(300); - servo_detach(SERVO_LEFT_LEG_PIN); - servo_detach(SERVO_RIGHT_LEG_PIN); + servo_write_smooth(SERVO_LEFT_LEG_PIN, LA0, 15, 2); + servo_write_smooth(SERVO_RIGHT_LEG_PIN, RA0, 15, 2); + delay_ms(100); // Wait for servo stabilization + // Keep PWM running, don't detach #if ARM_HEAD_ENABLE == 1 - // Arms to final position + // Step 3: Smooth transition of arms to final position (left arm 180 degrees, right arm 0 degrees) + // 2 degrees per step, 15ms delay, ensures smooth transition + // Keep PWM running, don't detach servo_attach(SERVO_LEFT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); servo_attach(SERVO_RIGHT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - servo_write(SERVO_LEFT_ARM_PIN, 180); - servo_write(SERVO_RIGHT_ARM_PIN, 0); - servo_detach(SERVO_LEFT_ARM_PIN); - servo_detach(SERVO_RIGHT_ARM_PIN); + servo_write_smooth(SERVO_LEFT_ARM_PIN, 180, 15, 2); + servo_write_smooth(SERVO_RIGHT_ARM_PIN, 0, 15, 2); + // Keep PWM running, don't detach #endif } /** * Set roll mode + * Use smooth transition function to avoid sudden servo changes and execution issues */ void robot_set_roll(void) { + PR_NOTICE("robot_set_roll"); #if ARM_HEAD_ENABLE == 1 - // Arms to middle position + // Step 1: Smooth transition of arms to middle position (90 degrees) + // 2 degrees per step, 15ms delay, ensures smooth transition + // Keep PWM running, don't detach servo_attach(SERVO_LEFT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); servo_attach(SERVO_RIGHT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - servo_write(SERVO_LEFT_ARM_PIN, 90); - servo_write(SERVO_RIGHT_ARM_PIN, 90); - delay_ms(200); - servo_detach(SERVO_LEFT_ARM_PIN); - servo_detach(SERVO_RIGHT_ARM_PIN); + servo_write_smooth(SERVO_LEFT_ARM_PIN, 90, 15, 2); + servo_write_smooth(SERVO_RIGHT_ARM_PIN, 90, 15, 2); + delay_ms(200); // Wait for servo stabilization + // Keep PWM running, don't detach #endif - // Ankles to roll position + // Step 2: Smooth transition of legs to roll position (LA1=180 degrees, RA1=0 degrees) + // 3 degrees per step, 20ms delay, larger angle change requires more time + // Keep PWM running, don't detach servo_attach(SERVO_LEFT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); servo_attach(SERVO_RIGHT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - servo_write(SERVO_LEFT_LEG_PIN, LA1); - servo_write(SERVO_RIGHT_LEG_PIN, RA1); - delay_ms(300); - servo_detach(SERVO_LEFT_LEG_PIN); - servo_detach(SERVO_RIGHT_LEG_PIN); + servo_write_smooth(SERVO_LEFT_LEG_PIN, LA1, 20, 3); + servo_write_smooth(SERVO_RIGHT_LEG_PIN, RA1, 20, 3); + delay_ms(100); // Wait for servo stabilization + // Keep PWM running, don't detach #if ARM_HEAD_ENABLE == 1 - // Arms to final position + // Step 3: Smooth transition of arms to final position (left arm 180 degrees, right arm 0 degrees) + // 2 degrees per step, 15ms delay, ensures smooth transition + // Keep PWM running, don't detach servo_attach(SERVO_LEFT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); servo_attach(SERVO_RIGHT_ARM_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); - servo_write(SERVO_LEFT_ARM_PIN, 180); - servo_write(SERVO_RIGHT_ARM_PIN, 0); - servo_detach(SERVO_LEFT_ARM_PIN); - servo_detach(SERVO_RIGHT_ARM_PIN); + servo_write_smooth(SERVO_LEFT_ARM_PIN, 180, 15, 2); + servo_write_smooth(SERVO_RIGHT_ARM_PIN, 0, 15, 2); + // Keep PWM running, don't detach #endif } @@ -502,9 +591,11 @@ void servo_detach(uint8_t pin) { if (joystick_y <= 0) return; // Only process forward - // Calculate left/right turn time - int lt = map_value(joystick_x, 100, -100, 200, 700); - int rt = map_value(joystick_x, 100, -100, 700, 200); + // Calculate left/right turn time + // Adjust time distribution to compensate for mechanical asymmetry + // Left foot time is smaller than right foot time + int lt = map_value(joystick_x, 100, -100, 300, 500); // Left foot time: 300-500ms (400ms when straight) + int rt = map_value(joystick_x, 100, -100, 400, 600); // Right foot time: 400-600ms (500ms when straight) // PR_NOTICE("robot_walk_forward: lt=%d, rt=%d", lt, rt); // Calculate time intervals int interval1 = 250; @@ -576,9 +667,11 @@ void servo_detach(uint8_t pin) { if (joystick_y >= 0) return; // Only process backward - // Calculate left/right turn time - int lt = map_value(joystick_x, 100, -100, 200, 700); - int rt = map_value(joystick_x, 100, -100, 700, 200); + // Calculate left/right turn time + // Adjust time distribution to compensate for mechanical asymmetry + // Left foot time is smaller than right foot time + int lt = map_value(joystick_x, 100, -100, 150, 650); // Left foot time: 300-500ms (400ms when straight) + int rt = map_value(joystick_x, 100, -100, 750, 250); // Right foot time: 350-550ms (450ms when straight, reduced) // Calculate time intervals int interval1 = 250; @@ -714,6 +807,154 @@ void servo_detach(uint8_t pin) #endif +/** + * @brief Rotate in place function (walk mode) + * @param direction true=rotate right, false=rotate left (currently unused) + * + * Function description: + * - Ensure in walk mode (not roll mode) + * - Execute the first step of forward walking (Phase 1-2: set to right tilt position, then rotate right foot) + * - Activate continuous rotation, updated in main_loop via robot_rotate_spot_update + */ + void robot_rotate_spot(bool direction){ + PR_NOTICE("robot_rotate_spot: direction=%s, starting rotation", direction ? "right" : "left"); + + // Ensure in walk mode + if (get_mode_counter() != 0) { + PR_NOTICE("robot_rotate_spot: Not in walk mode, switching to walk mode"); + robot_set_walk(); + delay_ms(500); // Wait for mode switch to complete + } + + // Attach leg and foot servos + servo_attach(SERVO_LEFT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + servo_attach(SERVO_RIGHT_LEG_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + servo_attach(SERVO_RIGHT_FOOT_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + servo_attach(SERVO_LEFT_FOOT_PIN, SERVO_MIN_PULSE, SERVO_MAX_PULSE); + + // Phase 1: Set ankles to right tilt position (first step of forward walking) + PR_NOTICE("robot_rotate_spot: Phase 1 - Set ankles to right tilt position (LATR, RATR)"); + servo_write(SERVO_LEFT_LEG_PIN, LATR); + servo_write(SERVO_RIGHT_LEG_PIN, RATR); + delay_ms(250); // Phase 1 duration: 250ms + + // Phase 2: Right foot rotation (first step of forward walking) + PR_NOTICE("robot_rotate_spot: Phase 2 - Right foot rotation (90 - RFFWRS = %d)", 90 - RFFWRS); + uint16_t start_angle = 90 - RFFWRS; // Start angle: right foot angle for first step of forward walking + servo_write(SERVO_RIGHT_FOOT_PIN, start_angle); + delay_ms(500); // Phase 2 duration: 500ms (right foot rotation time for first step of forward walking) + + // Initialize rotation state, start continuous rotation + sg_right_foot_angle = start_angle; // Start angle: right foot angle for first step of forward walking + sg_last_foot_update = get_millis(); + + // Map start angle to accumulator (angle range 60-180 degrees, accumulator range 0-36000) + if (sg_right_foot_angle < 60) { + sg_right_foot_angle = 60; + } + if (sg_right_foot_angle > 180) { + sg_right_foot_angle = 180; + } + if (sg_right_foot_angle <= 120) { + sg_angle_accumulator = (sg_right_foot_angle - 60) * 9000 / 60; + } else { + sg_angle_accumulator = 9000 + (sg_right_foot_angle - 120) * 9000 / 60; + } + + sg_rotate_spot_active = true; // Activate rotation, updated in main_loop via robot_rotate_spot_update + + PR_NOTICE("robot_rotate_spot: Rotation started, will continue in main_loop, start angle=%d", + sg_right_foot_angle); + } + +/** + * @brief Stop rotation in place + */ + void robot_rotate_spot_stop(void){ + PR_NOTICE("robot_rotate_spot_stop: Stopping rotation"); + sg_rotate_spot_active = false; + + // Restore leg position to standing position + servo_write(SERVO_LEFT_LEG_PIN, LA0); + servo_write(SERVO_RIGHT_LEG_PIN, RA0); + servo_write(SERVO_RIGHT_FOOT_PIN, 90); + + // Detach servos + servo_detach(SERVO_LEFT_LEG_PIN); + servo_detach(SERVO_RIGHT_LEG_PIN); + servo_detach(SERVO_RIGHT_FOOT_PIN); + servo_detach(SERVO_LEFT_FOOT_PIN); + } + +/** + * @brief Update rotation state (called in main_loop) + * Continuous rotation, no stuttering, no pauses + */ + void robot_rotate_spot_update(void){ + if (!sg_rotate_spot_active) { + return; // If not in rotation state, return directly + } + + uint32_t current_time = get_millis(); + uint32_t elapsed = current_time - sg_last_foot_update; + + // Update angle every 3ms to achieve smooth continuous rotation + if (elapsed >= 3) { + sg_last_foot_update = current_time; + + // Increase by approximately 15 units every 3ms (equivalent to 0.15 degrees per 3ms, about 50 degrees per second, achieving slow continuous rotation) + uint32_t increment = (elapsed * 15) / 3; + if (increment < 1) increment = 1; + if (increment > 50) increment = 50; + + sg_angle_accumulator += increment; + + // If accumulator exceeds 36000, use modulo operation to return to 0 and continue rotation (achieving continuous loop, no jumps) + if (sg_angle_accumulator >= 36000) { + sg_angle_accumulator = sg_angle_accumulator % 36000; + } + + // Convert accumulator to actual angle: map to 60-180 degree range + // Divide 36000 into 4 segments, each 9000, corresponding to: 60->120->180->120->60 + uint32_t phase = sg_angle_accumulator % 36000; + uint32_t quarter = phase / 9000; // 0, 1, 2, 3 + uint32_t pos_in_quarter = phase % 9000; // 0-8999 + + switch (quarter) { + case 0: + // 0-9000: 60 degrees to 120 degrees (linear increase) + sg_right_foot_angle = 60 + (pos_in_quarter * 60) / 9000; + break; + case 1: + // 9000-18000: 120 degrees to 180 degrees (linear increase) + sg_right_foot_angle = 120 + (pos_in_quarter * 60) / 9000; + break; + case 2: + // 18000-27000: 180 degrees to 120 degrees (linear decrease) + sg_right_foot_angle = 180 - (pos_in_quarter * 60) / 9000; + break; + case 3: + // 27000-36000: 120 degrees to 60 degrees (linear decrease) + sg_right_foot_angle = 120 - (pos_in_quarter * 60) / 9000; + break; + default: + sg_right_foot_angle = 90; + break; + } + + // Ensure angle is within valid range (60-180 degrees) + if (sg_right_foot_angle < 60) { + sg_right_foot_angle = 60; + } + if (sg_right_foot_angle > 180) { + sg_right_foot_angle = 180; + } + + // Update servo angle + servo_write(SERVO_RIGHT_FOOT_PIN, sg_right_foot_angle); + } + } + /** @@ -739,9 +980,17 @@ void main_loop(void) PR_NOTICE("robot_set_roll"); } } + + // Update rotate spot if active (must be called before other motion controls) + robot_rotate_spot_update(); + // Execute different motion control based on mode if (get_mode_counter() == 0) { // Walk mode + // If rotate spot is active, skip other motion controls + if (sg_rotate_spot_active) { + return; // Skip other motion controls when rotating + } if (joystick_x >= -10 && joystick_x <= 10 && joystick_y >= -10 && joystick_y <= 10) { diff --git a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.h b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.h index 01a845850..747032a04 100644 --- a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.h +++ b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_app_servo.h @@ -42,6 +42,7 @@ void platform_tuya_init(void); /** * Initialize servo control system */ + void servo_write_smooth(uint8_t pin, uint16_t target_angle, uint16_t step_delay_ms, uint16_t step_size); void servo_control_init(void); void main_init(void); @@ -58,5 +59,8 @@ void robot_right_arm_down(void); void robot_roll_control(int8_t joystick_x, int8_t joystick_y); void robot_walk_forward(int8_t joystick_x, int8_t joystick_y); void robot_walk_backward(int8_t joystick_x, int8_t joystick_y); +void robot_rotate_spot(bool direction); +void robot_rotate_spot_stop(void); +void robot_rotate_spot_update(void); #endif // OTTO_NINJA_APP_SERVO_H diff --git a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.c b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.c index e506cf824..c3745c213 100644 --- a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.c +++ b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.c @@ -24,10 +24,13 @@ #include "tkl_pwm.h" +#include "tal_sw_timer.h" // Include servo control header files #include "otto_ninja_app_servo.h" #include "otto_ninja_main.h" + #include "tal_thread.h" + #include "tal_log.h" /*********************************************************** @@ -46,10 +49,25 @@ ***********************variable define********************** ***********************************************************/ static THREAD_HANDLE sg_otto_ninja_handle; + static TIMER_ID sg_direction_timer = NULL; /*********************************************************** ***********************function define********************** ***********************************************************/ +/** + * @brief Timer callback function for direction control + * @param timer_id: Timer ID + * @param arg: Timer argument (unused) + * @return none + */ +static void __direction_timer_cb(TIMER_ID timer_id, void *arg) +{ + PR_DEBUG("Direction timer callback triggered after 3 seconds"); + // Timer will be automatically deleted after one-shot execution + sg_direction_timer = NULL; + set_joystick_y(0); + set_joystick_x(0); +} // These values are assumed to be obtained from remote control or sensors /** * @brief Set joystick X-axis value @@ -117,29 +135,40 @@ int get_mode_counter(void){ #define DPID_JOYSTICK_X 103 //joystick_x #define DPID_JOYSTICK_Y 104 //joystick_y +#define DPID_DIRECTION 105 //direction +#define DPID_ROTATE_SPOT 106 //rotate_spot OPERATE_RET otto_ninja_dp_obj_proc(dp_obj_recv_t *dpobj) { uint32_t index = 0; for (index = 0; index < dpobj->dpscnt; index++) { dp_obj_t *dp = dpobj->dps + index; - PR_DEBUG("idx:%d dpid:%d type:%d ts:%u", index, dp->id, dp->type, dp->time_stamp); + PR_DEBUG("Processing dp idx:%d dpid:%d type:%d", index, dp->id, dp->type); + PR_DEBUG("DP[%d]: ID=%d, Type=%d", index, dp->id, dp->type); switch (dp->id) { case SPORT_MODE:{ - set_sport_mode_change(true);//Trigger mode switch - if(dp->value.dp_bool){ - set_mode_counter(1); PR_DEBUG("robot_set_roll"); }else{ - set_mode_counter(0); PR_DEBUG("robot_set_walk"); } - + break; + } + + case DPID_ROTATE_SPOT:{ + if(dp->value.dp_bool){ + robot_rotate_spot(true); + // ai_audio_player_play_alert(AI_AUDIO_ALERT_MERRY_CHRISTMAS); // Commented out - function not available + } + else{ + robot_rotate_spot_stop(); // Stop rotation + set_joystick_y(0); + set_joystick_x(0); + } break; } @@ -160,6 +189,56 @@ OPERATE_RET otto_ninja_dp_obj_proc(dp_obj_recv_t *dpobj) break; } + case DPID_DIRECTION:{ + int8_t direction = dp->value.dp_enum; + if(direction == 0){ + set_joystick_y(100); + set_joystick_x(0); + } + else if(direction == 1){ + set_joystick_y(-100); + set_joystick_x(0); + } + else if(direction == 2){ + set_joystick_y(100); + set_joystick_x(100); + } + else if(direction == 3){ + set_joystick_y(100); + set_joystick_x(-100); + } + else if(direction == 4){ + set_joystick_y(0); + set_joystick_x(0); + } + + PR_DEBUG("direction:%d", direction); + + // Stop existing timer if any + if (sg_direction_timer != NULL) { + tal_sw_timer_stop(sg_direction_timer); + tal_sw_timer_delete(sg_direction_timer); + sg_direction_timer = NULL; + } + + // Create and start 3 second timer + OPERATE_RET ret = tal_sw_timer_create(__direction_timer_cb, NULL, &sg_direction_timer); + if (ret == OPRT_OK && sg_direction_timer != NULL) { + ret = tal_sw_timer_start(sg_direction_timer, 3000, TAL_TIMER_ONCE); + if (ret == OPRT_OK) { + PR_DEBUG("Direction timer started for 3 seconds"); + } else { + PR_ERR("Failed to start direction timer: %d", ret); + tal_sw_timer_delete(sg_direction_timer); + sg_direction_timer = NULL; + } + } else { + PR_ERR("Failed to create direction timer: %d", ret); + } + + break; + } + default: break; @@ -187,19 +266,15 @@ static void __example_otto_ninja_task(void *param) PR_NOTICE("=== OttoNinja Servo Control Task Start ==="); main_init(); - + tal_system_sleep(1000); // Wait 1 second before starting robot_set_walk(); while (1) { - - - main_loop(); - tal_system_sleep(10); // Wait 10ms before restarting - + main_loop(); + tal_system_sleep(10); // Wait 10ms before restarting } PR_NOTICE("OttoNinja task is finished, will delete"); tal_thread_delete(sg_otto_ninja_handle); - return; } /** diff --git a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.h b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.h index 85b7dd004..86e1475c0 100644 --- a/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.h +++ b/apps/tuya.ai/your_otto_robot/src/otto_ninja/otto_ninja_main.h @@ -3,6 +3,7 @@ #include "tuya_cloud_types.h" #include "tuya_iot_dp.h" +#include "dp_schema.h" void set_joystick_x(int8_t value); // Set joystick X-axis value, range -100 to 100, 0 is neutral, negative is left, positive is right int8_t get_joystick_x(void); // Get joystick X-axis value, range -100 to 100, 0 is neutral, negative is left, positive is right diff --git a/boards/T5AI/T5AI_OTTO/t5ai_otto.c b/boards/T5AI/T5AI_OTTO/t5ai_otto.c index cc9670723..479f6c41b 100644 --- a/boards/T5AI/T5AI_OTTO/t5ai_otto.c +++ b/boards/T5AI/T5AI_OTTO/t5ai_otto.c @@ -63,6 +63,10 @@ #define BOARD_LCD_X_OFFSET 0 #define BOARD_LCD_Y_OFFSET 0 +// GC9D01 backlight is active low, override the default HIGH level +#undef BOARD_LCD_BL_ACTIVE_LV +#define BOARD_LCD_BL_ACTIVE_LV TUYA_GPIO_LEVEL_LOW + #endif #define BOARD_LCD_SPI_CS_PIN TUYA_GPIO_NUM_13