找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4012|回复: 2
打印 上一主题 下一主题
收起左侧

单片机控制舵机机械手视频与源码

[复制链接]
跳转到指定楼层
楼主
ID:401931 发表于 2018-9-24 22:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


小弟自己业余爱好,闲时做了一个舵机控制装置摆弄一下,利用三角函数还算是可以用摇杆随意控制方向。有待改进,请多包涵,应大家需求我也可以贴出代码!谢谢!

//设置接收dma接口的模拟数据(自动接收)
__IO uint16_t ADC_ConvertedValue[2];

首先设置pwm三个舵机接口

stm32源码:
  1. void TIM3_PWM_Init(u16 arr,u16 psc)
  2. {
  3.   GPIO_InitTypeDef GPIO_InitStructure;
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  5.         TIM_OCInitTypeDef  TIM_OCInitStructure;
  6.       
  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//
  8.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
  9.       
  10.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; //TIM_CH1
  11.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.         GPIO_Init(GPIOA, &GPIO_InitStructure);

  14.       
  15.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         80K
  16.         TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
  17.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
  18.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
  19.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位


  20.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
  21.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  22.         TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
  23.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
  24.         TIM_OC2Init(TIM2, &TIM_OCInitStructure);
  25.         TIM_OC3Init(TIM2, &TIM_OCInitStructure);
  26.         TIM_OC4Init(TIM2, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

  27.   //TIM_CtrlPWMOutputs(TIM1,ENABLE);        //MOE 主输出使能      

  28.         TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //CH3预装载使能      
  29.         TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);  //CH3预装载使能      
  30.         TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);  //CH3预装载使能         
  31.       
  32.         TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIMx在ARR上的预装载寄存器
  33.       
  34.         TIM_Cmd(TIM2, ENABLE);  //使能TIM1
  35. }


  36. float Right_Angle_Hypotenuse(float H,float X)//求直角斜边的距离
  37. {
  38.         return sqrt(pow(H,2)+pow(X,2));
  39. }

  40. float Right_Angle(float H,float X)//求直角三角形的角度
  41. {
  42.         return atan(X/H)*180/PI;
  43. }

  44. /*三角形ABC角度分别为A,B,C,边分别为AB=c,BC=a,CA=b;
  45.   如果你想知道A的度数,参数依次为bca,
  46.         如果你想知道B的度数,参数依次为acb,
  47.         如果你想知道C的度数,参数依次为abc,
  48. */
  49. float Angle(float a,float b,float c)//求任意三角形的每个角的角度
  50. {
  51.         float angle;
  52.         angle=acos((pow(a,2)+pow(b,2)-pow(c,2))/(2*a*b));
  53.         angle=angle*180/PI;
  54.         if(angle<0)angle=180-fabs(angle);
  55.         return angle;
  56. }

  57. void YaoGan_XYD_init(void)
  58. {
  59.         GPIO_InitTypeDef HS_Gpio;
  60.         ADC_InitTypeDef  HS_ADC;
  61.         DMA_InitTypeDef  HS_DMA;
  62.       
  63.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启IO口A时钟
  64.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  65.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  66.       
  67.         DMA_DeInit(DMA1_Channel1);
  68.         HS_DMA.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//((u32)0x40012400+0x4c);
  69.         HS_DMA.DMA_MemoryBaseAddr=(u32)&ADC_ConvertedValue;
  70.         HS_DMA.DMA_DIR=DMA_DIR_PeripheralSRC;
  71.         HS_DMA.DMA_BufferSize=2;
  72.         HS_DMA.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  73.         HS_DMA.DMA_MemoryInc=DMA_MemoryInc_Enable;
  74.         HS_DMA.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  
  75.         HS_DMA.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  76.         HS_DMA.DMA_Mode = DMA_Mode_Circular;  
  77.         HS_DMA.DMA_Priority = DMA_Priority_High;
  78.         HS_DMA.DMA_M2M = DMA_M2M_Disable;  
  79.         DMA_Init(DMA1_Channel1, &HS_DMA);
  80.         DMA_Cmd(DMA1_Channel1, ENABLE);
  81.       
  82.       
  83.         HS_Gpio.GPIO_Pin=GPIO_Pin_10; //开10号Io口
  84.         HS_Gpio.GPIO_Mode=GPIO_Mode_IPU;   //上拉输入
  85.         HS_Gpio.GPIO_Speed=GPIO_Speed_50MHz;
  86.         GPIO_Init(GPIOB,&HS_Gpio);  //初始化IO口
  87.       
  88.         HS_Gpio.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1; //开启0,1号Io口
  89.         HS_Gpio.GPIO_Mode=GPIO_Mode_AIN;   //
  90.         HS_Gpio.GPIO_Speed=GPIO_Speed_50MHz;
  91.         GPIO_Init(GPIOB,&HS_Gpio);  //初始化IO口
  92.       
  93.         HS_ADC.ADC_Mode = ADC_Mode_Independent;
  94.         HS_ADC.ADC_ScanConvMode = ENABLE;//多通道循环扫描
  95.         HS_ADC.ADC_ContinuousConvMode = ENABLE;
  96.         HS_ADC.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  97.         HS_ADC.ADC_DataAlign = ADC_DataAlign_Right;
  98.         HS_ADC.ADC_NbrOfChannel = 2;
  99.         ADC_Init(ADC1,&HS_ADC);
  100. //        RCC_ADCCLKConfig(RCC_PCLK2_Div8);//这句意思是把系统时间分为八分之一
  101.         ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_1Cycles5);
  102.   ADC_RegularChannelConfig(ADC1,ADC_Channel_9,2,ADC_SampleTime_1Cycles5);
  103.         ADC_DMACmd(ADC1, ENABLE);
  104.         ADC_Cmd(ADC1,ENABLE);//ADC1使能
  105.         ADC_ResetCalibration(ADC1);//复位
  106.         while(ADC_GetResetCalibrationStatus(ADC1));//判断复位是否完成
  107.         ADC_StartCalibration(ADC1);
  108.         while(ADC_GetCalibrationStatus(ADC1));
  109.         ADC_SoftwareStartConvCmd(ADC1,ENABLE);//执行转换功能
  110. }

  111. u8 Key(void)//返回按键值
  112. {
  113.   return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10);
  114. }


  115. u16 ADC1_DMA1_2(u8 x)//
  116. {
  117.         return ADC_ConvertedValue[x];
  118. }

  119. u16 AngleMinMax(u16 angle)
  120. {
  121.         if(angle<ANGLEMIN){angle=ANGLEMIN;}
  122.         else if(angle>ANGLEMAX){angle=ANGLEMAX;}
  123.         return angle;
  124. }

  125. //主程序
  126. #include "stm32f10x.h"
  127. #include "init.h"

  128. u16  LD_L1Angle;//臀部舵机的角度 左边
  129. u16  LD_L2Angle;//膝盖舵机的角度 左边
  130. u16  LD_L3Angle;//脚踝舵机的角度 左边

  131. float LD_H;//机器人从臀部舵机到脚踝舵机的垂直高度
  132. float LD_L1H;//机器人从臀部舵机到膝盖舵机的距离 左边
  133. float LD_L2H;//机器人从膝盖舵机到脚踝舵机的距离 左边
  134. float LD_LH;//机器人臀部到脚踝的距离 左边
  135. float LD_LX;//机器人前后移动的距离,变量

  136. u16 YaoGanX;
  137. u16 YaoGanY;
  138. #define YGMIN 1750
  139. #define YGMAX 2250

  140. void init()
  141. {
  142.         LD_H=80;//mm
  143.         LD_L1H=77;
  144.         LD_L2H=80;
  145.         LD_LX=0.0;      
  146.       
  147. }

  148. int main(void)
  149. {
  150.         init();
  151.         TIM3_PWM_Init(200,3600);//不分频。PWM频率=72000/(899+1)=80Khz
  152.         time_ms(10);
  153.         YaoGan_XYD_init();
  154.         time_ms(10);
  155.         while (1)
  156.         {
  157.                 YaoGanX=ADC1_DMA1_2(1);
  158.                 YaoGanY=ADC1_DMA1_2(0);

  159.                 if(Key()==0)
  160.                 {
  161.                         time_ms(10);
  162.                         if(Key()==0)
  163.                         {
  164.                                 LD_H=80;//mm
  165.                                 LD_LX=0.0;      
  166.                         }
  167.                 }
  168.                 if(YaoGanX<YGMIN)
  169.                 {
  170.                         LD_LX+=fabs(YaoGanX-YGMIN)/2000.0;
  171.                 }else if(YaoGanX>YGMAX)
  172.                 {
  173.                         LD_LX-=fabs(YaoGanX-YGMAX)/2000.0;
  174.                 }
  175.                 if(YaoGanY<YGMIN)
  176.                 {
  177.                         LD_H-=fabs(YaoGanY-YGMIN)/2000.0;
  178.                 }else if(YaoGanY>YGMAX)
  179.                 {
  180.                         LD_H+=fabs(YaoGanY-YGMAX)/2000.0;
  181.                 }
  182.                 if(LD_H<25){LD_H=25;}if(LD_H>120){LD_H=120;}
  183.                 if(LD_LX<-90){LD_LX=-90;}if(LD_LX>90){LD_LX=90;}
  184.                 Left_leg_Movement();
  185.                
  186.                 TIM_SetCompare2(TIM2,LD_L1Angle);
  187.                 TIM_SetCompare3(TIM2,LD_L2Angle);
  188.                 TIM_SetCompare4(TIM2,LD_L3Angle);
  189.                 time_ms(10);
  190.         }
  191.                
  192. }

  193. float Left_leg_Movement(void)//左腿运动
  194. {
  195.         float CAB,ABC,BCA,CAD,ACD;//设置角度参数
  196.         //下面开始计算所有要用的角度
  197.         LD_LH=Right_Angle_Hypotenuse(LD_H,fabs(LD_LX));//计算斜边
  198.         CAB=Angle(LD_L1H,LD_LH,LD_L2H);
  199.         ABC=Angle(LD_L1H,LD_L2H,LD_LH);
  200.         BCA=Angle(LD_LH,LD_L2H,LD_L1H);
  201.         CAD=Right_Angle(LD_H,fabs(LD_LX));
  202.         ACD=Right_Angle(fabs(LD_LX),LD_H);
  203.       
  204.         if(LD_LX<0)
  205.         {
  206.                 LD_L1Angle=(u16)((90-CAD-CAB)+80)/4;
  207.                 LD_L3Angle=(u16)((BCA+ACD)-30)/4;
  208.         }
  209.         if(LD_LX==0)
  210.         {
  211.                 LD_L1Angle=(u16)((90-CAB)+80)/4;
  212.                 LD_L3Angle=(u16)((BCA+90)-30)/4;
  213.         }
  214.         if(LD_LX>0)
  215.         {
  216.                 LD_L1Angle=(u16)((90-(CAB-CAD)+80))/4;
  217.                 LD_L3Angle=(u16)((180-ACD+BCA)-30)/4;
  218.         }
  219.         LD_L2Angle=(u16)((180-ABC)+45)/4;
  220.       
  221.       
  222.         LD_L1Angle=AngleMinMax(LD_L1Angle);
  223.         LD_L2Angle=AngleMinMax(LD_L2Angle);
  224.         LD_L3Angle=AngleMinMax(LD_L3Angle);
  225.         return 1;
  226. }
  227. 舵机1是最上面的接PA1;
  228. 舵机2是最上面的接PA2;
  229. 舵机3是最上面的接PA3;

  230. 摇杆的X方向为PB0;
  231. 摇杆的Y方向为PB1;
复制代码


51单片机源码:
//机器人琳达的行动代码编写
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #include <math.h>
  4. #include <float.h>
  5. #define FOSC 11059200L //11.0592M Hz
  6. #define TIME_US 100 //设定定时时间
  7. #define uchar unsigned char
  8. #define uint unsigned int

  9. P0M0=0xff;
  10. P0M1=0x00;//强推
  11. uchar serval[2];
  12. uint pwm[]={1382,1382,1382};
  13. uchar pwm_flag=0;
  14. uint  ms0_5con=461;//0.5
  15. uint  ms2_5con=2304;//2.5
  16. sbit D1=P0^7;//舵机1
  17. sbit D2=P0^0;//舵机2
  18. sbit D3=P0^1;//舵机3
  19. sbit led=P1^0;
  20. sbit led1=P1^1;
  21. //机器人叫 琳达  简称LD
  22. uint count;//舵机变量
  23. #define  PI  3.141593  // 设定圆周率

  24. float LD_H;//机器人从臀部舵机到脚踝舵机的垂直高度
  25. float LD_LX;//机器人前后移动的距离,变量
  26. float LD_L1H;//机器人从臀部舵机到膝盖舵机的距离 左边
  27. float LD_L2H;//机器人从膝盖舵机到脚踝舵机的距离 左边
  28. uint  LD_L1Angle;//臀部舵机的角度 左边
  29. uint  LD_L2Angle;//膝盖舵机的角度 左边
  30. uint  LD_L3Angle;//脚踝舵机的角度 左边
  31. float LD_LH;//机器人臀部到脚踝的距离 左边
  32. float in;
  33. uint y=0;
  34. void init()
  35. {
  36. /*
  37. TMOD=0x01; //设定定时器0的工作方式为1
  38. TH0=(65536-(FOSC/12*TIME_US)/1000000)/256;
  39. TL0=(65536-(FOSC/12*TIME_US)/1000000)%256;
  40. ET0=1; //开启定时器0中断
  41. TR0=1; //开启定时器
  42. EA=1;  //打开总中断
  43. */
  44. TMOD|=0x20;
  45. TH1=0xfd;
  46. TL1=0xfd;
  47. TR1=1;
  48. REN=1;
  49. SM0=0;
  50. SM1=1;
  51. EA=1;
  52. ES=1;

  53. TMOD|=0x01;
  54. TH0=-ms2_5con>>8;
  55. TL0=-ms2_5con;
  56. EA=1;
  57. ET0=1;
  58. TR0=1;


  59. LD_H=120;//mm
  60. LD_L1H=77;
  61. LD_L2H=80;
  62. in=-1.0;
  63. LD_LX=0.0;
  64. }
  65. void time(unsigned int ms)
  66. {
  67. uint i,j;
  68. for(i=0;i<ms;i++)
  69. #if FOSC == 11059200L
  70.   for(j=0;j<114;j++);
  71. #elif FOSC == 12000000L
  72.    for(j=0;j<123;j++);
  73. #elif FOSC == 24000000L
  74.   for(j=0;j<249;j++);
  75. #else
  76.   for(j=0;j<114;j++);
  77. #endif
  78. }

  79. void main()
  80. {
  81. uint x=0;
  82. init();
  83. while(1)
  84. {
  85.   switch(x)
  86.   {
  87.   case 0:
  88.    LD_LX+=in;
  89.    if(LD_LX<-80.0){x=1;}
  90.    if(LD_LX>50.0){x=1;}
  91.    led=0;
  92.    led1=1;
  93.    break;
  94.   case 1:
  95.    LD_H+=in;
  96.    if(LD_H<90.0){in=1.0;x=0;}
  97.    if(LD_H>120.0){in=-1.0;x=0;}
  98.    led=1;
  99.    led1=0;
  100.    break;
  101.   }
  102.   Left_Leg_Movement();
  103.   
  104. }
  105. }
  106. float Right_Angle_Hypotenuse(float H,float X)//求直角斜边的距离
  107. {
  108. return sqrt(pow(H,2)+pow(X,2));
  109. }
  110. float Right_Angle(float H,float X)//求直角三角形的角度
  111. {
  112. return atan(X/H)*180/PI;
  113. }
  114. /*三角形ABC角度分别为A,B,C,边分别为AB=c,BC=a,CA=b;
  115.   如果你想知道A的度数,参数依次为bca,
  116. 如果你想知道B的度数,参数依次为acb,
  117. 如果你想知道C的度数,参数依次为abc,
  118. */
  119. float Angle(float a,float b,float c)//求任意三角形的每个角的角度
  120. {
  121. float angle;
  122. angle=acos((pow(a,2)+pow(b,2)-pow(c,2))/(2*a*b));
  123. angle=angle*180/PI;
  124. if(angle<0)angle=180-abs(angle);
  125. return angle;
  126. }

  127. void Left_leg_Movement()//左腿运动
  128. {
  129. float CAB,ABC,BCA,CAD,ACD;//设置角度参数
  130. //下面开始计算所有要用的角度
  131. LD_LH=Right_Angle_Hypotenuse(LD_H,abs(LD_LX));//计算斜边
  132. CAB=Angle(LD_L1H,LD_LH,LD_L2H);
  133. ABC=Angle(LD_L1H,LD_L2H,LD_LH);
  134. BCA=Angle(LD_LH,LD_L2H,LD_L1H);
  135. CAD=Right_Angle(LD_H,abs(LD_LX));
  136. ACD=Right_Angle(abs(LD_LX),LD_H);

  137. if(LD_LX<=0)
  138. {
  139.   LD_L1Angle=(int)(180-CAD-CAB)/7;
  140.   LD_L3Angle=(int)(BCA+ACD)/7-6;
  141. }
  142. if(LD_LX>0)
  143. {
  144.   LD_L1Angle=(int)(180+CAD-CAB)/7;
  145.   LD_L3Angle=(int)(180-ACD+BCA)/7-6;
  146. }
  147. LD_L2Angle=(int)(180-ABC)/7;

  148.   
  149. }

  150. void Timer0Int() interrupt 1
  151. {
  152. /*
  153. TH0=(65536-(FOSC/12*TIME_US)/1000000)/256;
  154. TL0=(65536-(FOSC/12*TIME_US)/1000000)%256;
  155. */

  156. count++;
  157. if(count > 200)
  158. {
  159.   count=0;
  160. }
  161. if(LD_L1Angle<7)LD_L1Angle=7;if(LD_L1Angle>20)LD_L1Angle=20;
  162. if(LD_L2Angle<7)LD_L2Angle=7;if(LD_L2Angle>20)LD_L2Angle=20;
  163. if(LD_L3Angle<7)LD_L3Angle=7;if(LD_L3Angle>20)LD_L3Angle=20;

  164. /*

  165. if(count<LD_L1Angle){D1=1;}else{D1=0;}
  166. if(count<LD_L2Angle){D2=1;}else{D2=0;}
  167. if(count<LD_L3Angle){D3=1;}else{D3=0;}

  168. */
  169. switch(pwm_flag)
  170. {
  171. case 1:
  172.   D1=1;
  173.   TH0=-pwm[0]>>8;
  174.   TL0=-pwm[0];
  175.   break;
  176. case 2:
  177.   D1=0;
  178.   TH0=-(ms2_5con-pwm[0])>>8;
  179.   TL0=-(ms2_5con-pwm[0]);
  180.   pwm_flag=0;
  181.   break;
  182. case 3:
  183.   TH0=0xff;
  184.   TL0=0x80;
  185.   pwm_flag=0;
  186.   break;
  187. }
  188. pwm_flag++;


  189. switch(y)
  190.   {
  191.   case 0:
  192.    pwm[0]+=10;
  193.    if(pwm[0]>2000)
  194.    {
  195.     y=1;
  196.    }
  197.    break;
  198.   case 1:
  199.    pwm[0]-=10;
  200.    if(pwm[0]<500)
  201.    {
  202.     y=0;
  203.    }
  204.    break;
  205.   }
  206. }
  207. void ser() interrupt 4
  208. {

  209.   
  210.   
  211. }
复制代码








分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:277392 发表于 2018-11-1 20:34 | 只看该作者
很强啊老哥,可以交流一下
回复

使用道具 举报

板凳
ID:419977 发表于 2018-11-3 01:08 | 只看该作者
可以啊,帮顶
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表