角度编码器 ST-3806-15-RS

两轴机械臂+机械爪整体控制板设计与机械爪控制调试 双轴机械臂的控制中,使用了基于 BH38旋转编码器初步测试 作为两个关节的运动角度测量,但是由于BH38传感器采用了MODBUS协议,所使用的串口波特率(19200)无法改变,致使解读读取的时间大约是10ms(具体读取信号波形参见 BH60绝对位置编码器测试 ),这对于机械臂运动动态调整造成了困难。

闭环步进电机平顺控制算法: 42HS48EIS,57HS 对于角度读取的时间延迟采用了补偿的方法,虽然有一定的效果,但是还是没有被彻底解决控制的平顺问题。

下面测试ST-3806-15-RS角度传感器,希望解决以下问题:

  • 能够将角度读取的时间缩短到1ms左右;
  • 角度的分辨率提高到15bit。

 

■ 编码器ST-3806-15-RS


  • 编码器的基本资料参加: ST-3806系列单圈编码器 说明书
  • 对于编码器的测试参见: ST-3806系列单圈编码器 测试说明

1.基本信息

  • 型号:ST-3806-15-RS
  • 工作电压:DC5-24V
  • 接口定义:
红/RD 黑/BK 绿/GN 黄/YE 白/WH
+5~24V 0V 485A+ 485B- SET
  • 出品公司:上海默马科技有限公司

角度编码器 ST-3806-15-RS_第1张图片

▲ 角度编码器 ST-3806-15-RS

 

01测试电路板设计


对于博文中 基于STC8H1K28的双轴机械臂驱动模块 的模块进行修正。在传感器接口处增加一个管脚(设置SET),形成新的传感器读写模块。

下面对应的电路板设计和软件设计。

1. SCH和PCB1

角度编码器 ST-3806-15-RS_第2张图片

角度编码器 ST-3806-15-RS_第3张图片

▲ #zxhn 01测试电路设计

 

2.软件工程文件2

单片机的软件工程文件采用与基于STC8H1K28的双轴机械臂驱动模块相同的工程文件进行测试。但是由于原来的模块中存在着旧的代码,程序体积过大,所以建立新的测试软件3

 

02软件初步调试


1.设置UART2波特率

//------------------------------------------------------------------------------
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的波形。

角度编码器 ST-3806-15-RS_第4张图片

▲ 波特率=9600的波形

2.ST3806子函数

(1) 设置ST3806波特率

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.

角度编码器 ST-3806-15-RS_第5张图片

▲ 读取数据的485总线波形

(2) 读取ST3806角度

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返回数据的时刻具有某种随机性。这一点在控制方面需要谨慎。

角度编码器 ST-3806-15-RS_第6张图片

▲ 读取时间的不确定性

在快速读取的时候,这种结果的返回抖动则更加的明显。结果的抖动时间前后大约1.5ms左右。

角度编码器 ST-3806-15-RS_第7张图片

▲ 在快速读取的时候,这种结果返回的抖动更加明显

 

03C51代码


/*
**==============================================================================
** 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__

 

※ 附录


 
■ 相关文献链接:

  • 两轴机械臂+机械爪整体控制板设计与机械爪控制调试
  • BH38旋转编码器初步测试
  • BH60绝对位置编码器测试
  • 闭环步进电机平顺控制算法: 42HS48EIS,57HS
  • ST-3806系列单圈编码器 说明书
  • ST-3806系列单圈编码器 测试说明
  • 基于STC8H1K28的双轴机械臂驱动模块:步进电机42HS348E,BH32角度传感器

  1. 设计AD工程文件:AD\XQWF\2020\机械臂\CNT2AXESCLAWSTC8H.SchDoc ↩︎

  2. 单片机软件工程文件:C51\STC\Project\XQWF\2020\STC8H2AXES\STC8H2AXES.uvproj ↩︎

  3. 新建的测试C51工程文件:C51\STC\Project\XQWF\2020\TestST3806\TestST3806.uvproj ↩︎

你可能感兴趣的:(电子模块实验,测量模块,合作项目)