目录
最近在搞机械臂机械视觉的项目,想着写篇博客来记录一下自己的成长和记录自己踩过的一些坑,方便以后复习,也希望自己的博客可以帮助到更多人读者。本人能力有限,过程如有不对,希望大家不吝指教。
一、总线舵机简介
图一:总线舵机
总线舵机是一种集成了电机、减速齿轮组、控制电路和通信接口的智能执行器。它的主要功能是接收来自控制器的指令(常见的是接受单片机串口传输的指令),并通过精确控制电机的转动来实现特定角度的输出。常在应用机械人和机械臂上,大家如果去淘宝上买那种组装好的机械臂大多都是由总线舵机组成的。
二、总线舵机工作原理
总线舵机通过特定的通信总线(如 CAN 总线、串口通信等)与控制器进行通信。控制器可以发送指令给舵机,包括设定目标角度、速度、运行时间等参数。因为舵机内部带有一块主控芯片, 内部已经完成 PWM 的控制。我们只需一条命令即可实现舵机的控制。(这里只简单述如何控制,不深究原理)。下图是众灵科技的总线舵机命令:
图二:总线舵机常见控制指令
总线舵机通过读取上位机或者单片机传输的指令来完成对应的任务。例如:单片机给他传输#000P1500T1000! (最常用)
# 和 !是固定的英文格式。# 和 !可以看做串口通信的帧头和帧尾,有这些总线舵机才可以正常设别你的指令,000代表ID(范围0-254),必须为 3位,不足补0。比如3号舵机为“003”而不能为“3”。1500代表PWM脉冲宽度调制(P)(范围500-2500), 必须为4位,不足补0。比如PWM为800,则必须为“P0800”。1000代表TIME时间(T)(范围0-9999,代表完成这个动作的时间,越短越快),同样必须为 4位,不足补0,单位ms。比如TIME为500,则必须为“T0500。
该指令可以叠加同时控制多个舵机。多个指令同时使用时(2个或2个以上叠加)需要在整条指令前后加“{}”,比如:{G0000#000P1602T1000!#001P2500T0000!#002P1500T1000!}
三、总线舵机接线
图3 :总线舵机接线端口
图4:舵机控制板
通过上图不难看出,总线舵机只有3 条线(信号线,正负极)。因为总线舵机通过半双工协议进行数据表的发送和接受(半双工是指不能同时接收发送),所以我们得通过舵机控制板才能正确的给舵机发送和接受数据,舵机控制板里会有对应的信号转换电路,用于将串口通信的全双工信号转换为半双工信号。
三、上位机调试
通过商家给的上位机,我们可以更直观的控制舵机旋转以及读取舵机现在的状态。
在使用上位机前,要正确的给总线舵机和舵机控制板以及电脑接线。(电池电压要确认在规定范围内,电压太小无法驱动机械臂,太大emmmm会炸)
图5:舵机控板与电脑接线
上位机正常界面
图6:上位机正常界面
如果出现下面那种字体缩在一起的情况,右击属性,点击兼容性更改dpi为系统执行。更改后就可正常显示。
图7:上位机不正常界面
图8:解决方法
上位机基本使用教程
1.配置舵机id号
首先给总线舵机配置自己的编号,上位机可以给255个总线舵机配置自己的id号,用于后面通信,首先点击配置,选择总线配置,然后确认自己usb线的串口号和波特率(默认115200)
图9:未连接界面
连接上后,连接设备会变成绿色
图10:正确连接界面
点击“写” 修改设备 ID 号, 比如 000 改为 001 是将设备原本的 ID 000 改为 001,
在不知道 ID 的情况下就写 255 改成 XXX, 当前设备 ID 号就被修改成了 XXX, 255 是广播 ID,
所有总线设备都会响应这个指令; “ 读” 和“ 写” 类似, 点击时, 会发送一个读 ID 指令,
一般用来检测 ID 是否修改成功或者查看当前设备 ID
读写id号的时候最好只连接一个总线舵机,不要串联
图11:舵机写数据
图12:舵机读数据
2.读取舵机角度
点击高级的“高级配置”,点击全部释力(让舵机释放扭力,不释放掰不动)ps:我是已经点击过了才会出现全部恢复
图13:读取总线舵机角度
然后调整舵机的角度,点击依次回读,就会返回你舵机的角度(不过是pwm数值的形式,不掰舵机默认1500度),舵机的pwm值会在(500-2500)之间,500对应0度,2500对应实际的270 度
图14:读总线舵机角度
由此可得旋转一度,pwm会增加(2500-500)/270=7.0407.....这样就可以通过对比前后2次pwm值的差值,来计算出舵机旋转的角度。
四、stm32读取舵机角度
1、接线图
stm32与舵机控制板和舵机接线(一定要接对,不对舵机不会动的)
图15:舵机控制板与stm32接线
2、实现代码
经过上面的解释,大家应该也都知道了,发送对应的命令,总线舵机就会执行对应的命令,那么怎么在stm'32里面实现呢,直接上代码(我这里是stm32f4)
首先配置串口
usatrt2.c
#include "sys.h"
#include "usart.h"
extern u8 Start;
//
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos 使用
#endif
#if 1 //如果使能了接收
//串口2中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART2_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART2_RX_STA=0; //接收状态标记
//初始化IO 串口2
//bound:波特率
void uart2_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); //使能GPIOD时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
//串口2对应引脚复用映射
GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_USART2); //GPIOD5复用为USART2
GPIO_PinAFConfig(GPIOD,GPIO_PinSource6,GPIO_AF_USART2); //GPIOD6复用为USART2
//USART2端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6; //GPIOD5与GPIOD6,5TX,6RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOD,&GPIO_InitStructure); //初始化PD5,PD6
//USART2 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART2, &USART_InitStructure); //初始化串口2
USART_Cmd(USART2, ENABLE); //使能串口2
//USART_ClearFlag(USART2, USART_FLAG_TC);
#if 1
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart2 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//串口2中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
#endif
}
void usart2_send_str(u8 *Data)
{
while(*Data) {
USART_SendData(USART2, *Data++);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
}
return;
}
void USART2_IRQHandler(void) //串口3中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART2, USART_IT_RXNE)!= RESET) //接收中断()
{
USART_ClearITPendingBit(USART6, USART_IT_RXNE);
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
#endif
usart2.h
#ifndef __USART2_H
#define __USART2_H
#include "stdio.h"
#include "stm32f4xx_conf.h"
#include "sys.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//串口1初始化
//正点原子@ALIENTEK
//技术论坛:www.openedv.csom
//修改日期:2011/6/14
//版本:V1.4
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
//********************************************************************************
//V1.3修改说明
//支持适应不同频率下的串口波特率设置.
//加入了对printf的支持
//增加了串口接收命令功能.
//修正了printf第一个字符丢失的bug
//V1.4修改说明
//1,修改串口初始化IO的bug
//2,修改了USART_RX_STA,使得串口最大接收字节数为2的14次方
//3,增加了USART_REC_LEN,用于定义串口最大允许接收的字节数(不大于2的14次方)
//4,修改了EN_USART1_RX的使能方式
//
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define EN_USART2_RX 1 //使能(1)/禁止(0)串口1接收
extern u8 USART2_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART2_RX_STA; //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart2_init(u32 bound);
void usart2_send_str(u8 *Data);
#endif
给舵机发送读取角度字符串,函数,依次传入参数,在自己主函数里面调用即可
void set_servo(int index, int pwm, int time)//依次传不同的舵机要转到的角度和时间进去
{
jxb_control[index].aim = pwm;
jxb_control[index].time = time;
jxb_control[index].inc = (jxb_control[index].aim - jxb_control[index].cur) / (jxb_control[index].time/20.000);
sprintf((char *)cmd_return, "#%03dP%04dT%04d!\r\n", index, pwm, time); //合并字符串
usart2_send_str(cmd_return); //自定义usart2的发送字符串函数,在usart2.c里面
}
标签:USART,舵机,总线,----,玩转,串口,GPIO,USART2
From: https://blog.csdn.net/Fhfgbyv/article/details/142531679