//cosf 余弦 正弦 2M_PI / _cellCount 每一个的角度

本文介绍了一种使用余弦和正弦函数来确定元素在圆形路径上位置的方法。通过计算每个元素相对于圆心的角度,可以实现均匀分布的圆形布局效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    //cosf 余弦 正弦 2M_PI / _cellCount 每一个的角度

    attributes.center = CGPointMake(_center.x + _radius * cosf(2 * path.item * M_PI / _cellCount),

                                    _center.y + _radius * sinf(2 * path.item * M_PI / _cellCount));

    return attributes;

STM32舵机画圆//#include "stm32f10x.h" //#include "Servo.h" //#include "Key.h" //#include <math.h> //#include "LED.h" //// 核心参数配置(平衡时间与精度) //#define TOTAL_TIME_MS 10000 // 总时间限制:30秒 //#define CIRCLE_STEPS 240 // 步数(提高至120,轨迹更平滑,降低折线误差) //#define CIRCLE_RADIUS 10.0f // 基础半径(根据实际物理尺寸调整,建议先实测) //#define CUSTOM_ORIGIN_X 166.0f // 原点X(初始位置) //#define CUSTOM_ORIGIN_Y 90.0f // 原点Y(初始位置) //// 精度优化参数 //#define X_SCALE_FACTOR 1.15f // X方向缩放(需实测校准:用尺子量X/Y实际移动距离,比例=Y实际/X实际) //#define Y_SCALE_FACTOR 1.65f // Y方向缩放(示例值,需根据实测调整至X/Y移动距离相等) //#define X_DIRECTION 1.0f // X轴方向(1=正方向,-1=反方向) //#define Y_DIRECTION 1.0f // Y轴方向(同上) //// 舵机角度安全范围(防止超程卡顿导致误差) //#define X_MIN_ANGLE 90.0f // X轴最小角度(根据舵机实际范围设置) //#define X_MAX_ANGLE 200.0f // X轴最大角度 //#define Y_MIN_ANGLE 60.0f // Y轴最小角度 //#define Y_MAX_ANGLE 120.0f // Y轴最大角度 //// 定义PI常量(高精度) //#ifndef M_PI //#define M_PI 3.1415926535897932384626433832795 //#endif //// 限幅函数(防止舵机超程,避免机械误差) //float limit_angle(float angle, float min, float max) { // if (angle < min) return min; // if (angle > max) return max; // return angle; //} //// 高精度画圆逻辑 //void Draw_Circle(void) { // // 计算每步延时(确保总时间≤30秒) // uint16_t step_delay = TOTAL_TIME_MS / CIRCLE_STEPS; // // for(int i = 0; i <= CIRCLE_STEPS; i++) { // // 高精度弧度计算(降低角度离散误差) // float rad = 2 * M_PI * i / CIRCLE_STEPS; // // // 计算理论坐标(考虑缩放和方向) // float x = CUSTOM_ORIGIN_X + X_DIRECTION * CIRCLE_RADIUS * X_SCALE_FACTOR * cos(rad); // float y = CUSTOM_ORIGIN_Y + Y_DIRECTION * CIRCLE_RADIUS * Y_SCALE_FACTOR * sin(rad); // // // 限幅处理(避免机械卡顿导致的轨迹偏移) // x = limit_angle(x, X_MIN_ANGLE, X_MAX_ANGLE); // y = limit_angle(y, Y_MIN_ANGLE, Y_MAX_ANGLE); // // // 高精度角度设置(假设Servo_SetAngle支持浮点精度) // Servo_SetAngle(SERVO_X_CHANNEL, x); // Servo_SetAngle(SERVO_Y_CHANNEL, y); // // // 精确延时(确保每步到位,降低动态误差) // Delay_ms(step_delay); // } //} //int main(void) { // SystemInit(); // Servo_Init(); // 初始化舵机(确保校准至高精度模式) // Key_Init(); // LED_Init(); // 补充LED初始化(原代码可能遗漏) // // // 初始位置校准(减少起始误差) // Servo_SetAngle(SERVO_X_CHANNEL, CUSTOM_ORIGIN_X); // Servo_SetAngle(SERVO_Y_CHANNEL, CUSTOM_ORIGIN_Y); // Delay_ms(2000); // 延长初始化等待时间,确保舵机到位 // // uint8_t keyNum = 0; // // while(1) { // LED2_OFF(); // keyNum = Key_GetNum(); // // if(keyNum == 1) { // 按键1触发画圆 // // // Draw_Circle(); // // // 画完回中心(二次校准) // Servo_SetAngle(SERVO_X_CHANNEL, CUSTOM_ORIGIN_X); // Servo_SetAngle(SERVO_Y_CHANNEL, CUSTOM_ORIGIN_Y); // Delay_ms(2000); // LED2_OFF(); // } // // // 低功耗待机(减少系统抖动影响) // Delay_ms(10); // } //} 我要精度高一点
07-16
#include "stm32f10x.h" // 定义SVPWM参数 #define PWM_PERIOD 4800 // 72MHz/15kHz = 4800 float V_dc = 0; // 直流母线电压 float duty_cycle[3]; // 三相占空比 // TIM1 PWM初始化 void TIM1_PWM_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, ENABLE); // GPIO配置 (PA8/PA9/PA10为PWM输出) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 定时器基础配置 TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD - 1; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // PWM通道配置 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 互补输出 TIM_OCInitStructure.TIM_Pulse = 0; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC2Init(TIM1, &TIM_OCInitStructure); TIM_OC3Init(TIM1, &TIM_OCInitStructure); // 死区时间配置 (防止上下管直通) TIM_BDTRInitTypeDef TIM_BDTRInitStructure; TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; TIM_BDTRInitStructure.TIM_DeadTime = 72; // 1us死区时间 (72MHz/72=1MHz) TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); // 启动定时器 TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); } // SVPWM算法实现 void SVPWM_Calc(float V_alpha, float V_beta) { // 1. 计算参考电压角度和幅值 float theta = atan2f(V_beta, V_alpha); float V_ref = sqrtf(V_alpha*V_alpha + V_beta*V_beta); // 2. 限制最大输出电压 if(V_ref > V_dc * 0.577f) V_ref = V_dc * 0.577f; // 最大线电压幅值 // 3. 计算三相占空比 duty_cycle[0] = 0.5f + (V_ref/V_dc) * sinf(theta); duty_cycle[1] = 0.5f + (V_ref/V_dc) * sinf(theta - 2*M_PI/3); duty_cycle[2] = 0.5f + (V_ref/V_dc) * sinf(theta + 2*M_PI/3); // 4. 更新PWM寄存器 TIM1->CCR1 = (uint16_t)(duty_cycle[0] * PWM_PERIOD); TIM1->CCR2 = (uint16_t)(duty_cycle[1] * PWM_PERIOD); TIM1->CCR3 = (uint16_t)(duty_cycle[2] * PWM_PERIOD); } // ADC初始化(直流母线电压采样) void ADC_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置ADC输入引脚 (PA0) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // ADC配置 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); // 配置通道0 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 启动ADC ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1, ENABLE); } // 主函数 int main(void) { SystemInit(); // 系统时钟初始化 TIM1_PWM_Init(); // PWM初始化 ADC_Init(); // ADC初始化 float V_alpha = 0, V_beta = 0; // 参考电压矢量 float freq = 50.0f; // 输出频率50Hz while(1) { // 1. 读取直流母线电压 (12位ADC值) V_dc = ADC_GetConversionValue(ADC1) * 3.3f / 4096.0f * 10.0f; // 假设分压比1:10 // 2. 生成旋转参考矢量 (开环控制) static float angle = 0; angle += 2 * M_PI * freq * 0.0001f; // 控制周期100us if(angle > 2*M_PI) angle -= 2*M_PI; V_alpha = V_dc * 0.4f * cosf(angle); // 40%调制比 V_beta = V_dc * 0.4f * sinf(angle); // 3. 计算SVPWM SVPWM_Calc(V_alpha, V_beta); // 4. 延时控制周期 Delay_us(100); // 10kHz控制频率 } } 这段代码啥意思
07-26
#include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_tim.h" #include "stm32f10x_usart.h" #include "math.h" #include <stdio.h> #include <stdlib.h> #include "delay.h" // 定义&pi;常量 #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // 步进电机参数 #define STEPS_PER_REV 200 // 步距角1.8° (360/1.8=200步/圈) #define MICROSTEPS 16 // D36A驱动器细分设置 #define FULL_STEPS (STEPS_PER_REV * MICROSTEPS) // 每圈总步数 // 云台几何参数 #define BASE_DISTANCE 500.0f // 基准距离50cm (单位mm) #define TARGET_RADIUS 60.0f // 画圆半径6cm // 引脚定义 // 水平电机控制 #define HORIZ_DIR_GPIO GPIOB #define HORIZ_DIR_PIN GPIO_Pin_12 #define HORIZ_STEP_GPIO GPIOB #define HORIZ_STEP_PIN GPIO_Pin_13 #define HORIZ_EN_GPIO GPIOB #define HORIZ_EN_PIN GPIO_Pin_14 // 垂直电机控制 #define VERT_DIR_GPIO GPIOB #define VERT_DIR_PIN GPIO_Pin_15 #define VERT_STEP_GPIO GPIOA #define VERT_STEP_PIN GPIO_Pin_8 #define VERT_EN_GPIO GPIOA #define VERT_EN_PIN GPIO_Pin_1 // 激光控制 #define LASER_GPIO GPIOA #define LASER_PIN GPIO_Pin_0 // 摄像头数据 volatile int targetX = 0; // 靶心X坐标 (像素) volatile int targetY = 0; // 靶心Y坐标 (像素) volatile float distance = 0.0f; // 当前云台到靶面距离 // 电机当前位置 (步数) - volatile声明 volatile int32_t horizPos = 0; volatile int32_t vertPos = 0; // 延时函数 void Delay(uint32_t nCount) { for(; nCount != 0; nCount--); } // 初始化GPIO void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); // 水平电机控制引脚 GPIO_InitStructure.GPIO_Pin = HORIZ_DIR_PIN | HORIZ_STEP_PIN | HORIZ_EN_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // 垂直电机控制引脚 GPIO_InitStructure.GPIO_Pin = VERT_STEP_PIN | VERT_EN_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 垂直电机方向引脚 (PB15) GPIO_InitStructure.GPIO_Pin = VERT_DIR_PIN; GPIO_Init(GPIOB, &GPIO_InitStructure); // 激光控制引脚 GPIO_InitStructure.GPIO_Pin = LASER_PIN; GPIO_Init(LASER_GPIO, &GPIO_InitStructure); // 使能电机 GPIO_SetBits(HORIZ_EN_GPIO, HORIZ_EN_PIN); GPIO_SetBits(VERT_EN_GPIO, VERT_EN_PIN); // 关闭激光 GPIO_ResetBits(LASER_GPIO, LASER_PIN); } // 初始化定时器 void TIM_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 使能定时器时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4, ENABLE); // 水平电机定时器配置 TIM_TimeBaseStructure.TIM_Period = 1000; TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 垂直电机定时器配置 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); } // 初始化串口 void USART_Configuration(void) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // USART1 TX (PA9) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // USART1 RX (PA10) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // USART配置 USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); // 使能串口中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART1_IRQn); USART_Cmd(USART1, ENABLE); } // 移动步进电机 (修正volatile指针问题) void moveStepper(TIM_TypeDef* TIMx, GPIO_TypeDef* dirGPIO, uint16_t dirPin, volatile int32_t* currentPos, int32_t targetSteps, uint16_t speed) { // 设置方向 if (targetSteps > *currentPos) { GPIO_SetBits(dirGPIO, dirPin); } else { GPIO_ResetBits(dirGPIO, dirPin); } // 计算需要移动的步数 int32_t steps = abs(targetSteps - *currentPos); // 生成脉冲 for (int i = 0; i < steps; i++) { GPIO_SetBits((TIMx == TIM3) ? HORIZ_STEP_GPIO : VERT_STEP_GPIO, (TIMx == TIM3) ? HORIZ_STEP_PIN : VERT_STEP_PIN); Delay(10); // 脉冲宽度 GPIO_ResetBits((TIMx == TIM3) ? HORIZ_STEP_GPIO : VERT_STEP_GPIO, (TIMx == TIM3) ? HORIZ_STEP_PIN : VERT_STEP_PIN); // 速度控制延时 Delay(speed); } // 更新位置 *currentPos = targetSteps; } // 计算靶心坐标对应的电机步数 void calculateTargetPosition(float targetX, float targetY, float dist, int32_t* horizSteps, int32_t* vertSteps) { // 角度计算 (弧度) float horizAngle = atan2f(targetX, dist); float vertAngle = atan2f(targetY, dist); // 转换为步数 *horizSteps = (int32_t)(horizAngle * (180.0f / M_PI) * FULL_STEPS / 360.0f); *vertSteps = (int32_t)(vertAngle * (180.0f / M_PI) * FULL_STEPS / 360.0f); } // 瞄准靶心 void aimAtTarget(void) { int32_t targetHorizSteps, targetVertSteps; // 计算靶心位置对应的步数 calculateTargetPosition(targetX, targetY, distance, &targetHorizSteps, &targetVertSteps); // 移动云台 (修正volatile指针传递) moveStepper(TIM3, HORIZ_DIR_GPIO, HORIZ_DIR_PIN, &horizPos, targetHorizSteps, 500); moveStepper(TIM4, VERT_DIR_GPIO, VERT_DIR_PIN, &vertPos, targetVertSteps, 500); // 开启激光 GPIO_SetBits(LASER_GPIO, LASER_PIN); } // 动态画圆函数 void drawCircle(float radius, uint32_t duration) { const uint32_t steps = 100; for (uint32_t i = 0; i <= steps; i++) { float angle = 2 * M_PI * i / steps; float targetX = radius * cosf(angle); float targetY = radius * sinf(angle); int32_t horizSteps, vertSteps; calculateTargetPosition(targetX, targetY, distance, &horizSteps, &vertSteps); moveStepper(TIM3, HORIZ_DIR_GPIO, HORIZ_DIR_PIN, &horizPos, horizSteps, 200); moveStepper(TIM4, VERT_DIR_GPIO, VERT_DIR_PIN, &vertPos, vertSteps, 200); Delay(duration / steps); } } //// 主函数 //int main(void) { // // 系统初始化 // SystemInit(); // GPIO_Configuration(); // TIM_Configuration(); // USART_Configuration(); // // while (1) { // aimAtTarget(); // delay(2000000); // drawCircle(TARGET_RADIUS, 20000); // } //} //// 串口中断处理 //void USART1_IRQHandler(void) { // if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { // static char buffer[32]; // static uint8_t index = 0; // // char ch = USART_ReceiveData(USART1); // if (ch == '\n') { // buffer[index] = '\0'; // if (sscanf(buffer, "%d,%d,%f", &targetX, &targetY, &distance) != 3) { // targetX = targetY = 0; // distance = BASE_DISTANCE; // } // index = 0; // } else if (index < sizeof(buffer) - 1) { // buffer[index++] = ch; // } else { // index = 0; // } // USART_ClearITPendingBit(USART1, USART_IT_RXNE); // } //} 把该代码写成一个.c文件和一个.h文件,方便外部调用
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值