基于stm32的光点运动轨迹控制

2024-03-03 21:30

本文主要是介绍基于stm32的光点运动轨迹控制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

步进电机画圆、直线。使用的简单的模拟脉冲方式快速实现的步进电机运动控制,如有不足的地方欢迎补充。

任务分析

1.任务
制作一个激光笔点二维控制装置,示意如图所示。在50cm*50cm靶纸上,用激光笔投射一光点,激光笔距离靶纸1米。要求能按指定的误差范围将光点定位在靶纸上任意一点,并在限定的条件下将光点按指定轨迹运动。
在这里插入图片描述
2.设备方案
主控采用stm32f411retx。控制装置为二自由度旋转式云台。使用42步进电机以及TB6600电机驱动器进行32细分。
3.基本原理
直线运动插补与圆弧运动插补采用的逐点比较法,这里只要注意一点就是激光笔是在云台上进行控制,控制x轴与y轴的电机转动时,需根据实际定位的坐标换算成电机当前相对初始状态要转动的角度。这里让激光笔初始垂直照射到原点位置,如下图。
在这里插入图片描述
tan(angle_x) = x / o p x / op x/op
tan(angle_y) = y / ( x 2 + o p 2 ) y / \sqrt(x^2+op^2) y/( x2+op2)
使用math.h里的atan可以算出angle值
angle_x = a t a n ( x / o p ) ∗ 180 / P I atan(x / op) * 180 / PI atan(x/op)180/PI;
angle_y = a t a n ( y / ( x 2 + o p 2 ) ) ∗ 180 / P I atan(y / \sqrt(x^2+op^2)) * 180 / PI atan(y/( x2+op2))180/PI

4.关键代码

#define Step_one 1 //单步步进值
static float now_x_step = 0, now_y_step = 0;  //记忆当前步数/** x* CCW对应x轴正方向*/
void stepper_x_run(int tim,float step,float subdivide,uint8_t dir)
{int i;if(step < 0.5)return;if(dir == CW)MOTOR_X_DIR(CW);else if(dir == CCW)MOTOR_X_DIR(CCW);osDelay(2);for(i = 0; i < step; i++){if(dir == CW)now_x_step--;else if(dir == CCW)now_x_step++;MOTOR_X_PUL(HIGH);osDelay(tim / 2);MOTOR_X_PUL(LOW);osDelay(tim / 2);}
}
/** y* CW对应y轴正方向*/
void stepper_y_run(int tim, float step, float subdivide, uint8_t dir)
{int i;if(step < 0.5)return;if(dir == CW)MOTOR_Y_DIR(CW);else if(dir == CCW)MOTOR_Y_DIR(CCW);osDelay(2);for(i = 0; i < step; i++){if(dir == CW)now_y_step++;else if(dir == CCW)now_y_step--;MOTOR_Y_PUL(HIGH);osDelay(tim / 2);MOTOR_Y_PUL(LOW);osDelay(tim / 2);}
}
/**
*定点函数
*/
void turn_coordinate(float x, float y)
{float angle_x, angle_y;float step_x, step_y;float dx, dy;float sqx;arm_sqrt_f32(1050 * 1050 + x * x, &sqx);angle_x = atan(x / 1050) * 180 / PI;angle_y = atan(y / sqx) * 180 / PI;step_x = angle_x / 0.05625;//计算对应步数,与0相差step_y = angle_y / 0.05625;dx = step_x - now_x_step;dy = step_y - now_y_step;if(dx > 0)stepper_x_run(2, dx, 32, CCW);else if(dx < 0)stepper_x_run(2, -dx, 32, CW);if(dy > 0)stepper_y_run(2, dy, 32, CW);else if(dy < 0)stepper_y_run(2, -dy, 32, CCW);
}
/** @brief:直线运动插补* @parameter:起点坐标(X0, Y0),终点坐标(Xe, Ye)* @return: 无* */
void drawline(float X0, float Y0, float Xe, float Ye)
{float NXY;              //总步数float Fm = 0;           //偏差float Xm = X0, Ym = Y0; //当前坐标uint8_t XOY;            //象限Xe = Xe - X0;Ye = Ye - Y0;NXY = (fabsf(Xe) + fabsf(Ye)) / Step_one;if(Xe > 0 && Ye >= 0) XOY = 1;else if(Xe <= 0 && Ye > 0) XOY = 2;else if(Xe < 0 && Ye <= 0) XOY = 3;else if(Xe >= 0 && Ye < 0) XOY = 4;while(NXY > 0){switch (XOY){case 1: (Fm >= 0) ? (Xm += Step_one) : (Ym += Step_one); break;case 2: (Fm <  0) ? (Xm -= Step_one) : (Ym += Step_one); break;case 3: (Fm >= 0) ? (Xm -= Step_one) : (Ym -= Step_one); break;case 4: (Fm <  0) ? (Xm += Step_one) : (Ym -= Step_one); break;default: break;}NXY -= 1;Fm = (Ym - Y0) * Xe - (Xm - X0) * Ye;turn_coordinate(Xm, Ym);osDelay(2);}
}
/** @brief:圆运动插补* @parameter:圆心坐标(x0, y0),半径 R, 方向 SorN 1 顺时针 2 逆时针* @return: 无* */
void drawcircle(float x0, float y0, float R, uint8_t SorN)
{float X0, Y0, Xe, Ye;float step = 0;float Fm = 0;float Xm, Ym;uint8_t XOY;X0 = x0; Y0 = y0 + R;  //开始点Xe = x0; Ye = y0 + R;  //结束点Xm = X0; Ym = Y0;while (pow((Xm - Xe), 2) + pow((Ym - Ye), 2) > Step_one * Step_one / 2 || (step == 0)){if ((Xm - x0) > 0 && (Ym - y0) >= 0) XOY = 1;else if ((Xm - x0) <= 0 && (Ym - y0) > 0) XOY = 2;else if ((Xm - x0) < 0 && (Ym - y0) <= 0) XOY = 3;else if ((Xm - x0) >= 0 && (Ym - y0) < 0) XOY = 4;switch (XOY){case 1:if(SorN == 1)(Fm >= 0) ? (Ym -= Step_one) : (Xm += Step_one);else(Fm <= 0) ? (Ym += Step_one) : (Xm -= Step_one);break;case 2:if(SorN == 1)(Fm >= 0) ? (Xm += Step_one) : (Ym += Step_one);else(Fm >  0) ? (Ym -= Step_one) : (Xm -= Step_one);break;case 3:if(SorN == 1)(Fm >= 0) ? (Ym += Step_one) : (Xm -= Step_one);else(Fm >  0) ? (Xm += Step_one) : (Ym -= Step_one);break;case 4:if(SorN == 1)(Fm >= 0) ? (Xm -= Step_one) : (Ym -= Step_one);else(Fm >  0) ? (Ym += Step_one) : (Xm += Step_one);default: break;}step = step + 1;Fm = pow((Xm - x0), 2) + pow((Ym - y0), 2) - pow(R, 2);turn_coordinate(Xm, Ym);osDelay(2);}
}

结论与现象

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
右边有一点点多出来是因为板子右边往后弯了些。思路大概为:写好一个定点函数,根据所给坐标更新步进电机的当前对应角度。然后在直线与圆弧插补里面不断调用定点函数来进行插补。如果使用PWM脉冲中断去控制电机步进。开环控制改为闭环控制,如带编码器的伺服电机,精度也许会更高。

附下工程:https://github.com/YAOSIYANAD/Light_spot_motion_control

这篇关于基于stm32的光点运动轨迹控制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/770964

相关文章

Python实现局域网远程控制电脑

《Python实现局域网远程控制电脑》这篇文章主要为大家详细介绍了如何利用Python编写一个工具,可以实现远程控制局域网电脑关机,重启,注销等功能,感兴趣的小伙伴可以参考一下... 目录1.简介2. 运行效果3. 1.0版本相关源码服务端server.py客户端client.py4. 2.0版本相关源码1

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

轨迹规划-B样条

B样条究竟是干啥的?白话就是给出一堆点,用样条的方式,给这些点连接起来,并保证丝滑的。 同时B样条分为准均匀和非均匀,以下为准均匀为例。 参考链接1:https://zhuanlan.zhihu.com/p/50626506https://zhuanlan.zhihu.com/p/50626506 参考链接2: https://zhuanlan.zhihu.com/p/536470972h

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但

Unity3D 运动之Move函数和translate

CharacterController.Move 移动 function Move (motion : Vector3) : CollisionFlags Description描述 A more complex move function taking absolute movement deltas. 一个更加复杂的运动函数,每次都绝对运动。 Attempts to