01 机械臂调试


1.简介

基于STM32对于三轴机械臂控制器设计 中对应的控制电路读取肩部和肘部两个 角度编码器 ST-3806-15-RS 数据进行调试。

2.接口电路1

▲ 角度读取的相关电路和PCB

2.单片机软件

单片机软件所在目录:

D:\zhuoqing\window\ARM\IAR\STM32\Application\XQWF\2020\CNTSTM103\Src\main.c

02 基本调试2


1. UART2输入输出

通过UART2发送字符,测试在MAX485的输出波形显示互补的信号。

2.建立ST3806文件

角度编码器 ST-3806-15-RS 拷贝 ST3806的头文件和C文件并建立相应的文件,加入Project。 具体文件内容参见附录。

注意:Control中调用ST3806Init()初始化的时候,需要注意到它的输入参数应该设置为1。

通过下面的过程,可以测量读取两个角度值所需要的缠绵大约在3 ~ 4ms。

    if(++nShowCount >= 500) {nShowCount = 0;int nBegin = HAL_GetTick();unsigned int nNumber1 = ShoulderAngle(); //ST3806ReadNumber(ST3806_CHANNEL_1);unsigned int nNumber2 = ElbowAngle();  //ST3806ReadNumber(ST3806_CHANNEL_2);int nEnd = HAL_GetTick();printf("%d %d %d\r\n", nNumber1, nNumber2, nEnd-nBegin);}

3.读取两个关节的最大值和最小值

从顶部看肩关节和肘关节的角度极值分别为:

(1)肩关节角度极值范围

  • 顺时针: 11157
  • 逆时针: 23376

▲ 顺时针旋转,从左90°旋转刀右90°

(2)肘关节角度极值范围

  • 顺时针: 23913
  • 逆时针: 27646

▲ 顺时针旋转,从左135°旋转刀右135°

4.角度左右补偿

(1)目标

由于传感器一周的分辨率是15bit,角度是以θT=0x8000\theta _T = 0x8000θT​=0x8000为周期重复的。所以机械臂在旋转过程中它的数值可能会从0x8000→0,或者0→0x8000突变。

通过角度增加一个偏置θoffset\theta _{offset}θoffset​,使得修正后的角度,在机械臂旋转范围内,不会出现上述的突变。实际的角度通过如下公式计算:
θnew=(θ+θoffset)%0x8000\theta _{new} = \left( {\theta + \theta _{offset} } \right)\% 0x8000θnew​=(θ+θoffset​)%0x8000

(2)获得偏移量

如何获得最佳的偏移量θoffset\theta _{offset}θoffset​使得输出的角度值范围能够位于0x0 ~ 0x8000的中间位置0x4000呢?

下面给出了角度偏移量θoffset=ΔA\theta _{offset} = \Delta Aθoffset​=ΔA的计算公式。

#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TEST1.PY                     -- by Dr. ZhuoQing 2020-12-21
#
# Note:
#============================================================
from headm import *
from tsmodule.tsstm32       import *
def deltaA(amin, amax):amax = amax if amax >= amin else 0x8000+amaxa0 = (amin + amax) // 2delA = 0x4000-a0 if a0 <= 0x4000 else 0xc000-a0return delA
#------------------------------------------------------------
data = stm32memo(1)
delA = deltaA(data[0], data[-1])
newdata = [(a + delA) % 0x8000 for a in data]
printf('DeltaA:%d'%delA)
printf(data, newdata)
plt.plot(data, label='Origin')
plt.plot(newdata, label='Modifier')
plt.xlabel("Sample")
plt.ylabel("Angle")
plt.grid(True)
plt.tight_layout()
plt.legend(loc='upper right')
plt.show()
#------------------------------------------------------------
#        END OF FILE : TEST1.PY
#============================================================

(3)测试数值

对于肩关节:ΔA=15176\Delta A = 15176ΔA=15176

▲ 肩关节经过修正后的角度变化范围

对于肘关节的数据:ΔA=7433\Delta A = 7433ΔA=7433

▲ 肘关节角度补偿前和补偿后的曲线

03 程序接口


下面分别是在control.h, control.c下的两个接口程序:


//------------------------------------------------------------------------------
#define ARM_SHOULDER_OFFSET     15176
#define ARM_ELBOW_OFFSET        7433unsigned int ShoulderAngle(void);
unsigned int ElbowAngle(void);
//------------------------------------------------------------------------------
unsigned int ShoulderAngle(void) {unsigned int nAngle;nAngle = ST3806ReadNumber(ST3806_CHANNEL_1);return (nAngle + ARM_SHOULDER_OFFSET) & 0x7fff;
}unsigned int ElbowAngle(void) {unsigned int nAngle;nAngle = ST3806ReadNumber(ST3806_CHANNEL_2);return (nAngle + ARM_ELBOW_OFFSET) & 0x7fff;
}

➤※ 附录


1.ST3806角度传感器的读写程序

/*
**==============================================================================
** ST3806.C:             -- by Dr. ZhuoQing, 2020-09-14
**
**==============================================================================
*/#include "stm32f1xx_hal.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "stm32f1xxa.h"//------------------------------------------------------------------------------
#define ST3806_GLOBALS        1              // Define the global variables
#include "ST3806.H"//------------------------------------------------------------------------------//------------------------------------------------------------------------------
void ST3806Init(unsigned char ucAddress) {  // Default ucAddress should be 1OFF(ST3806_DIR1_PIN);OUT(ST3806_DIR1_PIN);OFF(ST3806_DIR2_PIN);OUT(ST3806_DIR2_PIN);g_ucST3806Address = ucAddress;    g_ucST3806Channel = ST3806_CHANNEL_1;
}//------------------------------------------------------------------------------
void UART2ClearBuffer(void) {while(1) {if(!UART2_CANRECE) return;unsigned char ucChar;UART2ReceChar(&ucChar);}}//------------------------------------------------------------------------------
void ST3806SetChannel(unsigned char ucChannel) {g_ucST3806Channel = ucChannel;OFF(ST3806_DIR1_PIN);OFF(ST3806_DIR2_PIN);
}void ST3806DirON(void) {if(g_ucST3806Channel == ST3806_CHANNEL_1) {OFF(ST3806_DIR2_PIN);ON(ST3806_DIR1_PIN);} else {OFF(ST3806_DIR1_PIN);ON(ST3806_DIR2_PIN);        }}void ST3806DirOFF(void) {OFF(ST3806_DIR2_PIN);OFF(ST3806_DIR1_PIN);
}//------------------------------------------------------------------------------
unsigned int ModbusCRC(unsigned char * pByte, int nLength) {unsigned int nCRC;unsigned int i;unsigned char ucByte, j;nCRC = 0xffff;for(i = 0; i < nLength; i ++) {ucByte = *(pByte + i);nCRC ^= (unsigned int)ucByte;for(j = 0; j < 8; j ++) {if((nCRC & 0x1) != 0) {nCRC >>= 1;nCRC ^= 0xA001;} else nCRC >>= 1;}        }return nCRC;
}//------------------------------------------------------------------------------
void ST3806AppendCRC(unsigned char ucLength) {unsigned int nCRC;nCRC = ModbusCRC(g_ucST3806Buffer, ucLength);g_ucST3806Buffer[ucLength + 1] = (unsigned char)(nCRC >> 8);g_ucST3806Buffer[ucLength] = (unsigned char)nCRC;
}//------------------------------------------------------------------------------
void ST3806SendBuffer(unsigned char ucLength) {unsigned char i;ST3806AppendCRC(ucLength);ST3806DirON();for(i = 0; i < ucLength + 2; i ++) {UART2SendChar(g_ucST3806Buffer[i]);}ST3806DirOFF();UART2_CLEAR;}//------------------------------------------------------------------------------
unsigned char ST3806SetBaud115200(void) {unsigned char i, c;g_ucST3806Buffer[0] = g_ucST3806Address;g_ucST3806Buffer[1] = 0x10;g_ucST3806Buffer[2] = 0x0;g_ucST3806Buffer[3] = 0x3;g_ucST3806Buffer[4] = 0x0;g_ucST3806Buffer[5] = 0x1;g_ucST3806Buffer[6] = 0x2;g_ucST3806Buffer[7] = 0x0;g_ucST3806Buffer[8] = 0x5;ST3806SendBuffer(9);for(i = 0; i < 100; i ++) {if(UART2ReceChar(&c) == 0) break;}if(i < 100)g_ucST3806Buffer[0] = c;else return 1;/*        for(i = 1; i < 8; i ++) {if(UART2ReceChar(&c)) return 10+i;g_ucST3806Buffer[i] = c;}
*/   return 0;
}//------------------------------------------------------------------------------
unsigned char ST3806ReadData2Buffer(void) {unsigned char i, c;g_ucST3806Buffer[0] = g_ucST3806Address;g_ucST3806Buffer[1] = 0x3;g_ucST3806Buffer[2] = 0x0;g_ucST3806Buffer[3] = 0x0;g_ucST3806Buffer[4] = 0x0;g_ucST3806Buffer[5] = 0x1;ST3806SendBuffer(6);g_ucST3806Buffer[3] = 0x0;g_ucST3806Buffer[4] = 0x0;g_ucST3806Buffer[5] = 0x0;g_ucST3806Buffer[6] = 0x0;for(i = 0; i < 10; i ++) {if(UART2ReceChar(&c) == 0) break;}if(i < 10)g_ucST3806Buffer[0] = c;else return 1;for(i = 1; i < 7; i ++) {if(UART2ReceChar(&c)) return 1;g_ucST3806Buffer[i] = c;}return 0;}//------------------------------------------------------------------------------
unsigned char ST3806ReadConfig2Buffer(void) {unsigned char i, c;g_ucST3806Buffer[0] = g_ucST3806Address;g_ucST3806Buffer[1] = 0x3;g_ucST3806Buffer[2] = 0x0;g_ucST3806Buffer[3] = 0x0;g_ucST3806Buffer[4] = 0x0;g_ucST3806Buffer[5] = 0x3;ST3806SendBuffer(6);for(i = 0; i < 10; i ++) {if(UART2ReceChar(&c) == 0) break;}if(i < 10)g_ucST3806Buffer[0] = c;else return 1;for(i = 1; i < 11; i ++) {if(UART2ReceChar(&c)) return 1;g_ucST3806Buffer[i] = c;}return 0;
}//------------------------------------------------------------------------------
unsigned int ST3806Buffer2Number(void) {unsigned int nNumber;nNumber = g_ucST3806Buffer[3];nNumber = (nNumber << 8) + g_ucST3806Buffer[4];return nNumber;
}//------------------------------------------------------------------------------
unsigned int ST3806ReadNumber(unsigned char ucChannel) {    ST3806SetChannel(ucChannel);ST3806ReadData2Buffer();return ST3806Buffer2Number();
}//==============================================================================
//                END OF THE FILE : ST3806.C
//------------------------------------------------------------------------------
/*
**==============================================================================
** ST3806.H:            -- by Dr. ZhuoQing, 2020-12-18
**
**  Description:
**
**==============================================================================
*/
#ifndef __ST3806__
#define __ST3806__
//------------------------------------------------------------------------------
#ifdef ST3806_GLOBALS#define ST3806_EXT
#else#define ST3806_EXT extern
#endif // ST3806_GLOBALS
//------------------------------------------------------------------------------
#define ST3806_ADDRESS          1#define ST3806_DIR1_PIN         GPIOB,7
#define ST3806_DIR2_PIN         GPIOB,6//==============================================================================
void ST3806Init(unsigned char ucAddress);         // ucAddress: Default is 1#define ST3806_CHANNEL_1        0
#define ST3806_CHANNEL_2        1ST3806_EXT unsigned char g_ucST3806Channel;
void ST3806SetChannel(unsigned char ucChannel);
void ST3806DirON(void);
void ST3806DirOFF(void);//------------------------------------------------------------------------------
#define ST3806_BUFFER           16ST3806_EXT unsigned char g_ucST3806Buffer[ST3806_BUFFER];
ST3806_EXT unsigned char g_ucST3806Address;unsigned int ModbusCRC(unsigned char * pByte, int nLength);
void ST3806AppendCRC(unsigned char ucLength);//------------------------------------------------------------------------------
void ST3806SendCharBuffer(unsigned char ucLength);unsigned char ST3806ReadData2Buffer(void);
unsigned char ST3806ReadConfig2Buffer(void);unsigned int ST3806Buffer2Number(void);//------------------------------------------------------------------------------
unsigned int ST3806ReadNumber(unsigned char ucChannel); // Return about 2ms(&115200bps)unsigned char ST3806SetBaud115200(void);//------------------------------------------------------------------------------
#define UART2_CLEAR         UART2ClearBuffer()
void UART2ClearBuffer(void);//==============================================================================
//             END OF THE FILE : ST3806.H
//------------------------------------------------------------------------------
#endif // __ST3806__

■ 相关文献链接:

  • 基于STM32对于三轴机械臂控制器设计
  • 角度编码器 ST-3806-15-RS
  • 对于STM32F103三轴机械臂控制器进行基本功能测试-上下运动功能

  1. 接口板上的电路AD工程文件:AD\XQWF\2020\机械臂\CNTINTERFACE.SchDoc ↩︎

  2. 调试工程文件:STM32工程文件:STM32\Application\XQWF\2020\CNTSTM103\ ↩︎

对于STM32F103三轴机械臂控制器进行基本功能测试-关节角度读取相关推荐

  1. 对于STM32F103三轴机械臂控制器进行基本功能测试-上下运动功能

    简 介: 本文针对基于在基于STM32对于三轴机械臂控制器设计 中设计了控制电路板.本文记录对其在机械臂实际部件进行调试的过程. 关键词: STM32F103,机械臂,三轴,上下运动 ➤01 机械臂控 ...

  2. 基于STM32对于三轴机械臂控制器设计

    简 介: 本文使用了STM32对于一款三轴机械臂进行初步驱动,调试他的各个关节的运动情况. 关键词: 机械臂,三轴机械臂,STM32 ➤ 01背景 在 组装肩部带有减速器双轴机械臂组装与调试 的调试基 ...

  3. 对于STM32F103控制的三轴机械臂基本功能测试-关节转动控制

    ➤01 机械臂调试 1.简介 对于 基于STM32对于三轴机械臂控制器设计 的设计已经进行了如下的调试: 对于STM32F103三轴机械臂控制器进行基本功能测试-关节角度读取 对于STM32F103三 ...

  4. 基于STM32F103双轴机械臂完整电路板设计

    ➤01 机械臂设计   在 基于STM32对于三轴机械臂控制器设计 设计了机械臂的控制电路板.采用了双板分开设计方式.并分别进行了如下的测试:   1. 对于STM32F103三轴机械臂控制器进行基本 ...

  5. Rviz玩转三轴机械臂

    前言 最近想加深ROS仿真机械臂的理解,所以笔者参考一些资料与博客,在ROS下搭个简单的三轴机械臂,在Rviz下实现各轴关节转动,如果后续有时间的话,可能会更新下Gazebo下仿真,如果时间不够的话, ...

  6. 六轴机械臂控制器 控制卡 软件 机械臂

    六轴机械臂控制器 控制卡 软件 机械臂27400624681113128教学实训设备

  7. grbl控制3轴机械臂 原理 实现 (四) 之GRBL源码修改驱动三轴机械臂

    往期回顾: 第一篇:grbl控制3轴机械臂 原理 实现 (一) 之2D机械臂模拟及实现 第二篇:grbl控制3轴机械臂 原理 实现 (二) 之3D机械臂模拟及实现 第三篇:grbl控制3轴机械臂 原理 ...

  8. 逆运动学:RRR型 2D 三轴机械臂的IK求解 | 机械臂运动学笔记(二)

    任务: 给定末端的(x,y, \phi),求各轴角度( θ 1 , θ 2 , θ 3 \theta_1 , \theta_2, \theta_3 θ1​,θ2​,θ3​) 先将多个空间几何拆解成平面 ...

  9. 三轴机械臂/三自由度四足单腿DH正逆运动学及matlab验证

    实物模型 DH建立坐标系以及正逆运动学推导 Matlab验证 clear; clc; a1=-9.57*0.001;alpha1=pi/2; a2=-59.2*0.001; a3=-77*0.001; ...

最新文章

  1. 第三部分:Android 应用程序接口指南---第三节:应用程序资源---第四章 本地化...
  2. 5 HBase命令行接口
  3. pytorch中的torch.rand(),torch.randn(),torch.randerm()的关系
  4. 即将改变软件开发的5个Java9新特性
  5. ThreadPoolExecutor 中的workerDone(this); 为什么会时不时的就会在这个地方停下来???
  6. php bloginfo templatedirectory,PHP变量不显示使用bloginfo('template_directory')的图像
  7. 分布式消息系列:详解RocketMQ的简介与演进、架构设计、关键特性与应用场景
  8. 系统性能优化- Session丢失
  9. jsoncpp添加对象、数组与json对象的解析
  10. C++编程读取注册表文件
  11. netsetman使用教程_NetSetMan配置网络参数教程
  12. Mac 文本对比工具(比较两份文件差异)
  13. css svg做动图,如何制作svg动态图
  14. 慌乱的表情,泄露了我的悲伤:伤感心情日志
  15. 广告roi怎么计算公式_什么是广告ROI?ROI计算公式是什么? ROI怎么计算?ROI影响因素有哪些?...
  16. 电子元件-温湿度元件与传感器
  17. 【人因工程】熵值法与CRITIC法求权重
  18. 网络原理——网络层与数据链路层
  19. Mahout in action 中文版-3.推荐器的数据表达
  20. 单元测试、注解、枚举、反射(5)JavaSE

热门文章

  1. 开源 java CMS - FreeCMS2.3会员注册
  2. 解决eclipse project前出现红色感叹号 但没有提示错误出在什么地方build path jar包也没报错...
  3. 解决Oracle启动失败
  4. 【备忘】linux shell 字符串操作(长度,查找,替换,匹配)详解
  5. shell 编程 判断语句参数
  6. 东北面人李---精品作品展
  7. Android intent传序列化对象
  8. Linux下root密码忘记的解决办法
  9. JDBC连接数据库总结
  10. 北京联通限制上传到电信网络服务器