机械臂是一种用于模拟人类手臂运动的机械装置,通常由多个关节和连接部件组成,能够在空间中进行多维度的运动。它被广泛应用于工业自动化、科学研究、医疗领域、航天探测等各个领域,用于执行需要精确、重复或危险的任务。
机械臂的动力学研究机械臂内部各部件之间的相互作用,以及外部施加在机械臂上的力和扭矩对机械臂的影响。动力学分析包括机械臂的运动学、静力学和动力学三个方面,以确保机械臂在执行任务时能够稳定、精准地运动,并且能够承受外部载荷和冲击。其主要控制器为舵机,不同型号的舵机扭矩力不一样,当然价格越贵的舵机扭矩更大,可以支撑起更重的物体。
在这个履带式机器人里,机械臂使用了三个舵机,一个舵机控制底座的旋转,一个舵机控制机械臂上下摆动,一个舵机控制夹子。使用履带式作用主要有
-
稳定性和适应性:履带式机器人通过它们的履带提供更广泛的接触面积,从而增加了在不同地形上的稳定性和适应性。它们可以轻松地通过泥泞、沙地、雪地等复杂的地形,以及越过障碍物和不平整的地面。
-
载重能力:由于履带的设计可以更均匀地分布重量,履带式机器人通常能够承载更大的负载,这使它们在搬运重物或执行其他需要承重能力的任务时非常有用。
而驱动舵机和电机的主要使用PWM,PWM的介绍在我前面发的文章有详细介绍。简单来说就是驱动舵机和电机,然后怎么合理调度这些舵机和电机相互之间配合以实现想要的功能。
当然机械臂的主要作用是完成简单可重复的性的动作,这里我使用的是三个数组来记录舵机的角度,机械臂每到一个位置就记录到数组里面,实现重复动作就是调用这三个数组。
舵机初始化:
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//这里定时器2对应CH2(PA1),定时器3对应CH1(PA6),定时器4对应CH3(PB8)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4,ENABLE);//选择TIM定时器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);//同时开启A和B口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//需要复用推挽输出,因为此程序是CH1输出,是片上外设
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_6|GPIO_Pin_8;//根据GPIO引脚定义,此程序用的是OC2通道,对应的是CH2,由引脚图可知选PA1
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_Init(GPIOB,&GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);//由内部时钟驱动
TIM_InternalClockConfig(TIM3);//由内部时钟驱动
TIM_InternalClockConfig(TIM4);//由内部时钟驱动
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //预分频系数1
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;// //PSC
TIM_TimeBaseInitStructure.TIM_Period=20000-1;// //ARR
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//高级定时器的中的重复计数器的
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//时机单元初始化函数
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//时机单元初始化函数
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//时机单元初始化函数
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//使能中断
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);//使能中断
TIM_Cmd(TIM2,ENABLE);
TIM_Cmd(TIM3,ENABLE);
TIM_Cmd(TIM4,ENABLE);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//避免给一些没用到的参数赋予初始值而导致混乱
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//模式选择,此时选择PWM1模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//极性选择,这里是高极性,不翻转,按原来的高低电平输出
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//使能输出
TIM_OCInitStructure.TIM_Pulse=0; //设计CCR的值
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
TIM_OC1Init(TIM3,&TIM_OCInitStructure);
TIM_OC3Init(TIM4,&TIM_OCInitStructure);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2,Compare);//外部设计CCR的值
}
void PWM_SetCompare3(uint16_t Compare)
{
TIM_SetCompare3(TIM4,Compare);//外部设计CCR的值
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM3,Compare);//外部设计CCR的值
}
main函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "serial.h"
extern uint8_t Serial_RxFlag;
uint8_t KeyNum;
float Angle=0;
uint8_t stop=0;
extern uint8_t Serial_RxPacket[100];
uint8_t Angle1=100;
uint8_t Angle2=0;
uint8_t Angle3=0;
//初始化电机角度
void init_Servo(){
Servo_SetAngle1(160);//2号//最小的是70 最大值为160
Servo_SetAngle2(0);//3号
Servo_SetAngle3(0);//1号
}
//控制一号电机
void ctrl_Servo1_up(){
Angle1= Angle1 + 5;
if(Angle1>=160)
{
Angle1=160;
}
Servo_SetAngle1(Angle1);
}
//控制二号电机
void ctrl_Servo2_up(){
Angle2= Angle2 + 5;
Servo_SetAngle2(Angle2);
}
//控制三号电机
void ctrl_Servo3_up(){
Angle3= Angle3 + 5;
Servo_SetAngle3(Angle3);
}
//控制一号电机
void ctrl_Servo1_done(){
Angle1= Angle1 - 5;
if(Angle1<=70)
{
Angle1=70;
}
Servo_SetAngle1(Angle1);
}
//控制二号电机
void ctrl_Servo2_done(){
Angle2= Angle2 - 5;
Servo_SetAngle2(Angle2);
}
//控制三号电机
void ctrl_Servo3_done(){
Angle3= Angle3 - 5;
Servo_SetAngle3(Angle3);
}
int main(void)
{
// OLED_Init();
Servo_Init();
Serial_Init();
static char s=0;
init_Servo();
static uint8_t num1[100];
static uint8_t num2[100];
static uint8_t num3[100];
while(1)
{
if(Serial_RxFlag==1)
{
OLED_ShowNum(2,2,1,2);
Serial_RxFlag=0;
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == 0); //等待数据发送完成
s=Serial_RxPacket[0];
static uint8_t flag=0;
switch(s)
{
case '1': //记录三个舵机的角度
{
num1[flag]=Angle1;
num2[flag]=Angle2;
num3[flag]=Angle3;
flag++;
;
}break;
case '2':
{
ctrl_Servo1_up();
// OLED_ShowNum(1,1,2,1);
}break;
case '3'://上下
{
ctrl_Servo2_up();
}break;
case '4'://夹子
{
ctrl_Servo3_up();
}break;
case '5':
{
ctrl_Servo1_done();
}break;
case '6':
{
ctrl_Servo2_done();
}break;
case '7':
{
ctrl_Servo3_done();
}break;
case '8':
{
for(uint8_t j=0;j<flag;j++)
{
Servo_SetAngle1(num1[j]);
Servo_SetAngle2(num2[j]);
Servo_SetAngle3(num3[j]);
Delay_s(1);
}
}break;
}
}
}
}
履带机械臂