在 两轴机械臂+机械爪整体控制板设计与机械爪控制调试 双轴机械臂的控制中,使用了基于 BH38旋转编码器初步测试 作为两个关节的运动角度测量,但是由于BH38传感器采用了MODBUS协议,所使用的串口波特率(19200)无法改变,致使解读读取的时间大约是10ms(具体读取信号波形参见 BH60绝对位置编码器测试 ),这对于机械臂运动动态调整造成了困难。
在 闭环步进电机平顺控制算法: 42HS48EIS,57HS 对于角度读取的时间延迟采用了补偿的方法,虽然有一定的效果,但是还是没有被彻底解决控制的平顺问题。
下面测试ST-3806-15-RS角度传感器,希望解决以下问题:
红/RD | 黑/BK | 绿/GN | 黄/YE | 白/WH |
---|---|---|---|---|
+5~24V | 0V | 485A+ | 485B- | SET |
▲ 角度编码器 ST-3806-15-RS
对于博文中 基于STC8H1K28的双轴机械臂驱动模块 的模块进行修正。在传感器接口处增加一个管脚(设置SET),形成新的传感器读写模块。
下面对应的电路板设计和软件设计。
▲ #zxhn 01测试电路设计
单片机的软件工程文件采用与基于STC8H1K28的双轴机械臂驱动模块相同的工程文件进行测试。但是由于原来的模块中存在着旧的代码,程序体积过大,所以建立新的测试软件3。
//------------------------------------------------------------------------------
void SetUART2Baud(unsigned long lnBaud) {
unsigned long lnNumber;
unsigned int nNumber;
lnNumber = OSC_FREQUENCY;
lnNumber /= lnBaud * 4;
nNumber = 0xffff - (unsigned int)lnNumber;
T2H = nNumber >> 8;
T2L = nNumber & 0xff;
}
下面是SetUART2Baud(9600)对应的TXD2的波形。
▲ 波特率=9600的波形
else IFARG0("sb115200") {
printf("Set ST3806 baud 115200:\r\n");
ON(ST3806_SET1_PIN);
WaitTime(3000);
OFF(ST3806_SET1_PIN);
WaitTime(1000);
SetUART2Baud(9600);
ucRet = ST3806SetBaud115200();
printf("Set Result: %bd\r\n", ucRet);
SetUART2Baud(115200);
请注意,在前面设置波特率前,设置SET管脚为高电平3秒钟,以保证ST3806被初始化为缺省的9600波特率。
如下是在115200下读写485总线波形。时间长度大约是2.2ms.
▲ 读取数据的485总线波形
ST3806的角度值是在寄存器地址00(0x00),前后两个字节(高端字节在前)表示了一个15bit的角度值。
//------------------------------------------------------------------------------
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();
}
在读取时间上,ST3806返回数据的时刻具有某种随机性。这一点在控制方面需要谨慎。
▲ 读取时间的不确定性
在快速读取的时候,这种结果的返回抖动则更加的明显。结果的抖动时间前后大约1.5ms左右。
▲ 在快速读取的时候,这种结果返回的抖动更加明显
/*
**==============================================================================
** ST3806.C: -- by Dr. ZhuoQing, 2020-09-14
**
**==============================================================================
*/
#include "C51BASIC.H"
#include "STC8H.H"
//------------------------------------------------------------------------------
#define ST3806_GLOBALS 1 // Define the global variables
#include "ST3806.H"
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void ST3806Init(unsigned char ucAddress) {
OFF(ST3806_DIR1_PIN);
PM_PP(ST3806_DIR1_PIN);
OFF(ST3806_DIR2_PIN);
PM_PP(ST3806_DIR2_PIN);
OFF(ST3806_SET1_PIN);
PM_PP(ST3806_SET1_PIN);
OFF(ST3806_SET2_PIN);
PM_PP(ST3806_SET2_PIN);
g_ucST3806Address = ucAddress;
g_ucST3806Channel = ST3806_CHANNEL_1;
}
//------------------------------------------------------------------------------
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 < 9; 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-09-14
**
** 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 1, 2
#define ST3806_DIR2_PIN 1, 3
#define ST3806_SET1_PIN 2, 4
#define ST3806_SET2_PIN 2, 3
//==============================================================================
void ST3806Init(unsigned char ucAddress); // ucAddress: Default is 1
#define ST3806_CHANNEL_1 0
#define ST3860_CHANNEL_2 1
ST3806_EXT unsigned char g_ucST3806Channel;
void ST3806SetChannel(unsigned char ucChannel);
void ST3806DirON(void);
void ST3806DirOFF(void);
//------------------------------------------------------------------------------
#define ST3806_BUFFER 16
ST3806_EXT unsigned char xdata g_ucST3806Buffer[ST3806_BUFFER];
ST3806_EXT unsigned char xdata 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);
//==============================================================================
// END OF THE FILE : ST3806.H
//------------------------------------------------------------------------------
#endif // __ST3806__
■ 相关文献链接:
设计AD工程文件:AD\XQWF\2020\机械臂\CNT2AXESCLAWSTC8H.SchDoc ↩︎
单片机软件工程文件:C51\STC\Project\XQWF\2020\STC8H2AXES\STC8H2AXES.uvproj ↩︎
新建的测试C51工程文件:C51\STC\Project\XQWF\2020\TestST3806\TestST3806.uvproj ↩︎