|
很早就想做磁懸浮只是覺得有點難就一直沒有做,自學51單片機,又學了stm32后也一直沒有做過單片機項目,直到做設計的時候才想起用單片機做個磁懸浮玩玩。選用stm32也只是手頭上剛好有一塊,通過對網上的資料學習后以為對磁懸浮有點了解,做起來應該不是很難,沒想到上手操作的時候還是有很多的坑。
其大概原理就是用四個線圈對浮子在前后左右的位置進行調整,浮子的位置用線性霍爾元件進行檢測,轉換為電壓后由單片機進行ADC采集
磁懸浮圖片原理.png (45.04 KB, 下載次數: 159)
下載附件
2021-1-30 15:18 上傳
單片機將采集的位置數據分別進行x,y軸的pid算法處理,輸出pwm控制電磁線圈的磁力從而控制浮子的位置。
本項目的重點就是霍爾傳感器的信號放大以及ad采集,pid算法,pwm輸出還有就是磁鐵的放置位置。
磁懸浮電路.png (55.35 KB, 下載次數: 169)
下載附件
2021-1-30 15:18 上傳
線性霍爾元件用的a3144,輸出只有幾百mv需要用運放將其放大,運放接5v話其最大輸出有4v左右,需要用兩個電阻將其限制在3.3v以下保護單片機,也可以用兩個二極管組成鉗位電路進行限制。(一定要用線性霍爾元件,并且要接運放將霍爾元件的輸出放大,對運放的輸出限制以免燒壞stm32單片機。
將霍爾元件,運放,以及鉗位電阻連接后,需要調節電位器使輸出電壓穩定在1.7v附近
pid算法網上有很多這里就不解釋了,貼幾個連接https://blog.csdn.net/qq_25352981/article/details/81007075 https://blog.csdn.net/sdkdlwk/article/details/107759435
以下運用的是位置pid算法,pid參數調整時可以x,y軸一起調整,先調整kp也就是比例系數,再調整kd微分系數。
- #define Max_Cycle 290//限制幅度
- #define Min_Cycle -290
- typedef struct//結構體
- {
- int targetValue;//設定值
- int Error;//誤差
- int prevError;//上次誤差
- int Integral;//誤差積分
- float Kp;//比例系數
- float Ki;//沒用
- float Kd;//微分系數
- }PID;
- int Calc_PID(PID *pid,int Pos)//位置PID
- {
- int output;
- int Differential;//微分變量
-
- pid->Error = (pid->targetValue - Pos); // 誤差有正負
-
- pid->Integral += pid->Error; // 誤差累計
-
- Differential = pid->Error - pid->prevError; // 微分部分本次誤差減去上次誤差
-
- output = (pid->Kp * pid->Error + pid->Integral * pid->Ki + pid->Kd * Differential);//通過比例 積分 微分參數算出輸出控制量 可省略積分部分
-
- pid->prevError = pid->Error; // 本次誤差賦值為上次
-
- if(output>Max_Cycle) // 超過上限則輸出恒定值
- output = Max_Cycle;
-
- if(output<Min_Cycle)
- output = Min_Cycle;
-
- return output;
- }
- void Init_PID_Parameter(void)
- {
- xPID.targetValue = 2300; //
- yPID.targetValue = 2300;
- xPID.Error = 0;
- yPID.Error = 0;
- xPID.prevError=0;
- yPID.prevError=0;
-
- xPID.Ki = 0.0f;
- yPID.Ki = 0.0f;
-
- xPID.Kp = 0.3f;
- yPID.Kp = 0.3f;
-
- xPID.Kd = 0.60f;
- yPID.Kd = 0.60f;
- }
復制代碼
pwm主要就是控制電磁線圈的的磁力大小,從而控制浮子位置。將pid算法的輸出作為pwm的輸入,控制4路pwm的通斷- void TIM3_GPIO_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- /* 設置TIM3CLK 為 72MHZ */
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
- /* GPIOA and GPIOB clock enable */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE );
- /*GPIOA Configuration: TIM3 channel 1 and 2 as alternate function push-pull */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復用推挽輸出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- /*GPIOB Configuration: TIM3 channel 3 and 4 as alternate function push-pull */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- }
- void TIM3_Mode_Config(void)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- /* PWM信號電平跳變值 */
- /* u16 CCR1_Val ;
- u16 CCR2_Val ;
- CCR1_Val=CCR1_value;
- CCR2_Val=CCR2_value;
- */
- //周期為12K 72M/ARR+1/PSC+1
- /* Time base configuration */
- TIM_TimeBaseStructure.TIM_Period =299; //當定時器從0計數到299,即為300次,為一個定時周期
- TIM_TimeBaseStructure.TIM_Prescaler = 11; //設置預分頻:不預分頻,即為72MHz
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ; //設置時鐘分頻系數:不分頻(這里用不到)
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
- /* PWM1 Mode configuration: Channel1 */
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置為PWM模式1
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //當定時器計數值小于CCR1_Val時為高電平
- TIM_OCInitStructure.TIM_Pulse = 10; //設置跳變值,當計數器計數到這個值時,電平發生跳變 可不設置
- TIM_OC1Init(TIM3, &TIM_OCInitStructure); //使能通道1
- TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
- /* PWM1 Mode configuration: Channel2 */
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
- TIM_OCInitStructure.TIM_Pulse = 10; //設置通道2的電平跳變值,輸出另外一個占空比的PWM
- TIM_OC2Init(TIM3, &TIM_OCInitStructure); //使能通道2
- TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
-
- /*TIM3的通道3*/
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
- TIM_OCInitStructure.TIM_Pulse = 10; //設置通道2的電平跳變值,輸出另外一個占空比的PWM
- TIM_OC3Init(TIM3, &TIM_OCInitStructure); //使能通道2
- TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
-
- /*TIM 通道 4*/
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
- TIM_OCInitStructure.TIM_Pulse = 10; //設置通道2的電平跳變值,輸出另外一個占空比的PWM
- TIM_OC4Init(TIM3, &TIM_OCInitStructure); //使能通道2
- TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
- /* TIM3 enable counter */
- TIM_Cmd(TIM3, ENABLE); //使能定時器3
- }
- /**
- * 初始化
- */
- void TIM3_PWM_Init(void)
- {
- TIM3_GPIO_Config();
- TIM3_Mode_Config();
- }</div><div>//pwm輸出處理函數</div><div>
- void TIM3_OutSequence1zhuoyou(int Shuzhi){
- if(Shuzhi>0){
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,Shuzhi);
-
- }
- else {
- TIM_SetCompare1(TIM3,Shuzhi*(-1));
- TIM_SetCompare2(TIM3,0);
-
- }
- }
- void TIM3_OutSequence1shangxia(int Shuzhi){
- if(Shuzhi>0){
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,Shuzhi);
-
- }
- else {
- TIM_SetCompare3(TIM3,Shuzhi*(-1));
- TIM_SetCompare4(TIM3,0);
- }
- }
復制代碼 l298n接受單片機的pwm輸出,再輸出電壓到電磁線圈。
當所有電路連接好后,將強力磁鐵放在四個線圈的中間,再左右前后移動如感覺有斥力將浮子限制在中間則線路連接正確,否則要調整電路連接。
大磁鐵(為浮子提供主要支持力)的位置放置很重要,將浮子放在大磁鐵中間上方要感覺是有排斥力才行。大磁鐵最好放在板子也就是電磁線圈的下方,否者電磁線圈的控制力不足以控制浮子的姿態。或者加大輸入電磁線圈的電壓也行。
正面
板子203.jpg (3.83 MB, 下載次數: 160)
下載附件
2021-1-30 15:58 上傳
背面
板子背面.jpg (3.35 MB, 下載次數: 137)
下載附件
2021-1-30 15:59 上傳
IMG_20210105_222252.jpg (2.82 MB, 下載次數: 155)
下載附件
2021-1-30 15:49 上傳
最終效果
VID_20210129_144633[00-00-00--00-00-04].gif (3.3 MB, 下載次數: 140)
下載附件
2021-1-30 16:05 上傳
材料
stm32c8t6
lm358n運放
a3144線性霍爾元件
l298n
2個電位器10k
兩個100k電阻
四個4.7k電阻
兩個15k電阻
四個19*12電磁線圈
100*60*15環形磁鐵
20*3銣磁鐵
4個m3的螺絲
51hei.png (5.92 KB, 下載次數: 150)
下載附件
2021-1-30 16:56 上傳
Proteus仿真與程序資料51hei下載地址:
磁懸浮stm32.7z
(231.26 KB, 下載次數: 258)
2021-1-30 16:59 上傳
點擊文件名下載附件
代碼及其電路 下載積分: 黑幣 -5
|
評分
-
查看全部評分
|