机械臂运动控制,通讯的解包->运动控制->数据封包上报过程

一、协议

数据格式为小端模式,浮点数格式为IEEE754,需与上位机的PC端一致,如window系统,其它系统需要自行测试,用于传输16位、32位、float数据格式,避免只传输字节数据带来转换的繁琐及精度丢失。

二、下位机数据接收线程

csharp 复制代码
/** 
*  通讯主线程. 
* . 
* @param[in]   parameter:线程参数.
* @param[out]  无.  
* @retval  无.
* @par 标识符 
*      保留 
* @par 其它 
*      无 
* @par 修改日志 
*      kun于2022-07-25创建 
*/
void comm_thread_entry(void *parameter)
{
    uint8_t ch;
    
    serial = rt_device_find("uart2");
    if (!serial)
    {
        LOG_E("find comm uart1 failed!\n");
        return;
    }
    else{
        struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;  /* 初始化配置参数 */
        /* step2:修改串口配置参数 */
        config.baud_rate = BAUD_RATE_115200;        //修改波特率为 9600
        config.data_bits = DATA_BITS_8;           //数据位 8
        config.stop_bits = STOP_BITS_1;           //停止位 1
        config.bufsz     = RECV_BUF_LEN;            //修改缓冲区 buff size 为 128
        config.parity    = PARITY_NONE;           //无奇偶校验位

        /* step3:控制串口设备。通过控制接口传入命令控制字,与控制参数 */
        rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
        
        rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    }
        
    while(1){
        
        rt_thread_delay(1);
        
//        rt_device_write(serial, 0, "hello world", 11);
                
        if( rt_device_read(serial, -1, &ch, 1) > 0 ){
            
            comm_state.recv_time = 100;
                        
            switch( comm_state.recv_state )
            {
                case RECV_START:
                    if( ch == COMM_HEADER ){
                        comm_state.recv_buf[comm_state.recv_index++] = ch;
                        comm_state.recv_state++;
                    }
                    break;
                case RECV_ID:
                    if( ch == ROBOT_ID ){
                        comm_state.recv_buf[comm_state.recv_index++] = ch;
                        comm_state.recv_state++;
                        comm_state.recv_sub_len = 2;
                    }
                    else{
                        comm_state.recv_state = 0;
                        comm_state.recv_index = 0;
                    }
                    break;
                case RECV_LEN:
                    comm_state.recv_buf[comm_state.recv_index++] = ch;
                    comm_state.recv_sub_len --;
                    if( comm_state.recv_sub_len==0 ){
                        comm_header_t *header = (comm_header_t *)comm_state.recv_buf;
                        comm_state.recv_data_len = header->len;
                        comm_state.recv_state++;
                    }
                    break;
                case RECV_FUN_DATA:
                    comm_state.recv_buf[comm_state.recv_index++] = ch;
                    comm_state.recv_data_len --;
                    if( comm_state.recv_data_len == 0 ){
                        comm_state.recv_state++;
                        comm_state.recv_sub_len = 2;
                    }
                    break;
                case RECV_CRC:
                    comm_state.recv_buf[comm_state.recv_index++] = ch;
                    comm_state.recv_sub_len --;
                    if( comm_state.recv_sub_len == 0 ){
                        comm_state.recv_state++;
                    }
                    break;
                case RECV_END:
                    if( ch == COMM_ENDER ){
                        comm_state.recv_buf[comm_state.recv_index++] = ch;
                        comm_state.recv_len = comm_state.recv_index;
                        comm_state.recv_state = 0;
                        comm_state.recv_index = 0;
                        comm_state.recv_complete = 1;
                    }
                    else{
                        comm_state.recv_state = 0;
                        comm_state.recv_index = 0;
                    }
                    break;
                default:
                    break;
            }
        }
        
        //字节流接收超时
        if( comm_state.recv_time > 0 ){
            comm_state.recv_time --;
            if( comm_state.recv_time==0 ){
                if( comm_state.recv_state != RECV_START )
                    LOG_I("recv byte step %d timeout",comm_state.recv_state);
                comm_state.recv_state = RECV_START;
                comm_state.recv_len = 0;
                comm_state.recv_index = 0;
            }
        }
        
        if( comm_state.recv_complete ){
            
            comm_state.recv_complete = 0;
            
            LOG_HEX("RECV", 16, comm_state.recv_buf, comm_state.recv_len);
            
            comm_header_t *header_ptr = (comm_header_t *)comm_state.recv_buf;
            uint16_t *crc_ptr = (uint16_t *)&comm_state.recv_buf[comm_state.recv_len-3];
            if( comm_crc16( comm_state.recv_buf, comm_state.recv_len-3 ) == *crc_ptr ){

                switch( header_ptr->fun_code )
                {
                    case HAND_SETP_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"HAND_SETP_CMD");
                        comm_hand_set_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case DEPOT_POS_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_POS_CMD");
                        comm_depot_pos_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case AVOID_HIGHT_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"AVOID_HIGHT_CMD");
                        avoid_hight_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case MOTOR_PMT_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"MOTOR_RST_CMD");
                        motor_pmt_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case STATION_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"STATION_CMD");
                        station_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case DEPOT_OFFSET_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_OFFSET_CMD");
                        depot_offset_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case INIT_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"INIT_CMD");
                        comm_init_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case STATION_MOVE_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"STATION_MOVE_CMD");
                        comm_station_move_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case STATION_CLAMP_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"STATION_CLAMP_CMD");
                        comm_station_clamp_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case DEPOT_IN_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_IN_CMD");
                        comm_depot_in_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case DEPOT_A_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_A_CMD");
                        comm_depot_a_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case DEPOT_B_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_B_CMD");
                        comm_depot_b_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case DEPOT_OCCUPY_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_OCCUPY_CMD");
                        comm_occupy_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case CLAMP_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"CLAMP_CMD");
                        comm_clamp_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case STATUS_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"STATUS_CMD");
                        comm_status_cmd(&header_ptr->data, header_ptr->len-1);                        
                        break;
                    case RBT_MOVE_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"RBT_MOVE_CMD");
                        comm_rbt_move_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case DEPOT_MOVE_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_MOVE_CMD");
                        comm_depot_move_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case MOTOR_INIT_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"DEPOT_MOVE_CMD");
                        comm_motor_init_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case SWITCH_CTRL_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"SWITCH_CTRL_CMD");
                        comm_switch_ctrl_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case LIGHT_CTRL_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"LIGHT_CTRL_CMD");
                        comm_light_ctrl_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    case OTA_CMD:
                        LOG_I("recv cmd %02X %s",header_ptr->fun_code,"OTA_CMD");
                        comm_ota_cmd(&header_ptr->data, header_ptr->len-1);
                        break;
                    default:
                        LOG_E("illegal cmd %02X",header_ptr->fun_code);
                        break;
                }
            }
            else{
                LOG_E("recv cmd %02X crc error",header_ptr->fun_code);
            }
        }
    }
}

comm_state.recv_complete 接收一帧完整数据包标记,然后进行校验,判断功能码进行命令处理流转

csharp 复制代码
/** 
*  设置工位座标. 
* . 
* @param[in]   data:数据指针,len:长度.
* @param[out]  无.  
* @retval  无.
* @par 标识符 
*      保留 
* @par 其它 
*      无 
* @par 修改日志 
*      kun于2022-07-25创建 
*/
static void comm_depot_pos_cmd(void *data, uint16_t len)
{
    #pragma pack(push)
    #pragma pack(1)
    typedef struct _depot_pos_recv_t{
        uint8_t         mode;
        station_no_t    no;
        depot_pmt_t     pmt;
    }depot_pos_recv_t;
    #pragma pack(pop)
    
    #pragma pack(push)
    #pragma pack(1)
    typedef struct _depot_pos_send_t{
        uint8_t         mode;
        station_no_t    no;
        depot_pmt_t     pmt[DEPOT_MAX];
    }depot_pos_send_t;
    #pragma pack(pop)
    
    depot_pos_recv_t *depot_pos_recv_ptr = (depot_pos_recv_t *)data;
    
    if( depot_pos_recv_ptr->mode==0x00 ){
    
        if( depot_pos_recv_ptr->no <= DEPOT_MAX ){
            config_get_ptr()->depot_pmt[depot_pos_recv_ptr->no-1].speed = depot_pos_recv_ptr->pmt.speed;
            config_get_ptr()->depot_pmt[depot_pos_recv_ptr->no-1].door = depot_pos_recv_ptr->pmt.door;
            config_get_ptr()->depot_pmt[depot_pos_recv_ptr->no-1].clamp = depot_pos_recv_ptr->pmt.clamp;
            config_get_ptr()->depot_pmt[depot_pos_recv_ptr->no-1].chip = depot_pos_recv_ptr->pmt.chip;
            config_get_ptr()->depot_pmt[depot_pos_recv_ptr->no-1].scaner = depot_pos_recv_ptr->pmt.scaner;
            
            config_save();
            
            comm_reply(EXE_OK, 0, DEPOT_POS_CMD, RT_NULL, 0);
        }
    }
    else if( depot_pos_recv_ptr->mode==0x01 ){
        
        depot_pos_send_t depot_pos_send;
        
        depot_pos_send.mode = depot_pos_recv_ptr->mode;
        depot_pos_send.no = 0;
        
        rt_memcpy(depot_pos_send.pmt,config_get_ptr()->depot_pmt,sizeof(((config_t*)0)->depot_pmt));
        
        comm_reply(EXE_OK, 0, DEPOT_POS_CMD, &depot_pos_send, sizeof(depot_pos_send_t));
    }
}
csharp 复制代码
typedef struct _depot_pmt_t{
    float       speed;
    float       door;
    float       clamp;
    float       chip;
    float       scaner;
}depot_pmt_t;

这个函数传输各个工位的座标数据到下位机进行保存,传输格式为浮点,单位是mm

定义提取结构体

typedef struct _depot_pmt_t{

float speed;

float door;

float clamp;

float chip;

float scaner;

}depot_pmt_t;

typedef struct _depot_pos_recv_t{

uint8_t mode;

station_no_t no;

depot_pmt_t pmt;

}depot_pos_recv_t;

定义结构体指针指向接收的数据帧的数据区

depot_pos_recv_t *depot_pos_recv_ptr = (depot_pos_recv_t *)data;

通过结构体的指针提取需要的数据放到存储单元中,各个数据为浮点数,没有数据转换带来精度损失及转换繁琐问题

config_get_ptr()->depot_pmtdepot_pos_recv_ptr-\>no-1.speed = depot_pos_recv_ptr->pmt.speed;

config_get_ptr()->depot_pmtdepot_pos_recv_ptr-\>no-1.door = depot_pos_recv_ptr->pmt.door;

config_get_ptr()->depot_pmtdepot_pos_recv_ptr-\>no-1.clamp = depot_pos_recv_ptr->pmt.clamp;

config_get_ptr()->depot_pmtdepot_pos_recv_ptr-\>no-1.chip = depot_pos_recv_ptr->pmt.chip;

config_get_ptr()->depot_pmtdepot_pos_recv_ptr-\>no-1.scaner = depot_pos_recv_ptr->pmt.scaner;

三、下位机数据上报

csharp 复制代码
/** 
*  通讯状态返回. 
* . 
* @param[in]   status:状态,error_code:错误码,fun_code:功能码,data:数据指针,len:长度.
* @param[out]  无.  
* @retval  无.
* @par 标识符 
*      保留 
* @par 其它 
*      无 
* @par 修改日志 
*      kun于2022-07-25创建 
*/
void comm_reply(comm_cmd_retsult_t status, uint16_t error_code, uint8_t fun_code, void *data, uint16_t len)
{
    #pragma pack(push)
    #pragma pack(1)
    typedef struct {
        comm_cmd_retsult_t  status;
        uint16_t            error_code;
    }reply_t;
    #pragma pack(pop)
    
    uint16_t fix_data_len = sizeof(reply_t)+len;
    //comm_header_t包含一个数据字节所以需要减1,3为校验码+结束符
    uint8_t *send_ptr = rt_malloc(sizeof(comm_header_t) -1 + 3 + fix_data_len);
    
    if( send_ptr ){
        comm_header_t *comm_header;
        
        comm_header = (comm_header_t *)send_ptr;
        
        comm_header->header = COMM_HEADER;
        comm_header->id = ROBOT_ID;
        //1为命令码
        comm_header->len = fix_data_len+1;
        comm_header->fun_code = fun_code;
        
        reply_t *reply_ptr = (reply_t*)&comm_header->data;
        
        reply_ptr->status = status;
        reply_ptr->error_code = error_code;
        
        uint8_t *target_data = (uint8_t*)(&comm_header->data+sizeof(reply_t));
        uint8_t *source_data = (uint8_t*)data;
        for( uint16_t i=0; i<len; i++ ){
            *target_data++ = *source_data++;
        }
        uint16_t *crc_ptr = (uint16_t *)target_data;
        //comm_header_t包含一个数据字节所以需要减1
        *crc_ptr = comm_crc16( send_ptr, sizeof(comm_header_t) -1 + fix_data_len);
        
        target_data+=2;
        *target_data = COMM_ENDER;
        
        if( status == EXE_OK )
            LOG_D("reply EXE OK:%02X",fun_code);
        else if( status == EXE_FAIL )
            LOG_D("reply EXE FAIL:%02X",fun_code);
        else if( status == RECV_OK )
            LOG_D("reply RECV OK:%02X",fun_code);
//        LOG_HEX("REPLY", 16, send_ptr, sizeof(comm_header_t) -1 + 3 + fix_data_len);
        
        rt_device_write(serial, 0, send_ptr, sizeof(comm_header_t) -1 + 3 + fix_data_len);
        
        rt_free(send_ptr);
    }
    else{
        LOG_E("can not malloc memory:%02X",fun_code);
    }
}

所有命令的上报为统一格式,填入状态,错误码,功能码,及命令的私有数据,调用comm_reply函数将对上报数据进行打包发7送

四、运动执行

csharp 复制代码
/** 
*  移动运动轴. 
* . 
* @param[in]   data:数据指针,len:长度.
* @param[out]  无.  
* @retval  无.
* @par 标识符 
*      保留 
* @par 其它 
*      无 
* @par 修改日志 
*      kun于2022-07-25创建 
*/
static void comm_rbt_move_cmd(void *data, uint16_t len)
{
    #pragma pack(push)
    #pragma pack(1)
    typedef struct _move_cmd_t{
        uint8_t     mode;
        uint8_t     axle;
        float       speed;
        float       distance;
    }move_cmd_t;
    #pragma pack(pop)
    
    static const uint8_t rbt_axis[]={ROBOT_Y_AXIS,ROBOT_Z_AXIS};
    
    move_cmd_t *move_cmd_ptr = (move_cmd_t *)data;
    
    robot_msg_t msg;
    
    msg.type.move_msg.axle = rbt_axis[move_cmd_ptr->axle-1];
    msg.robot_cmd = ROBOT_CMD_MOVE;
    msg.type.move_msg.action = move_cmd_ptr->mode;
    msg.type.move_msg.abs_res = 0;
    msg.type.move_msg.position = move_cmd_ptr->distance;
    msg.type.move_msg.speed = move_cmd_ptr->speed;
    
    comm_reply(RECV_OK, 0, RBT_MOVE_CMD, RT_NULL, 0);
    
    robot_write_queue(&msg);
}

解释移动命令,提取运行座标及速度数据,建立一个消息,将数据放入消息中,由运动线程接收消息将进行电机的控制

五、运动控制

csharp 复制代码
/** 
*  机械臂动作执行线程. 
* . 
* @param[in]   parameter:建立线程传入参数.
* @param[out]  无.  
* @retval  无.
* @par 标识符 
*      保留 
* @par 其它 
*      无 
* @par 修改日志 
*      kun于2022-07-29创建 
*/
void robot_thread_entry(void *parameter)
{
    robot_msg_t robot_msg;
    uint8_t i;
    float speed;
    float dist = 0;
    station_xyz_t   station_target;

    while(1)
    {
        //读取命令队列
        if( robot_read_queue(&robot_msg, RT_WAITING_FOREVER) == RT_EOK ){
            
            const char *rbt_cmd_str[]={ "ROBOT_CMD_MOVE",
                                        "ROBOT_CMD_ROUTER",
                                        "ROBOT_CMD_CLAMP",
                                        "ROBOT_CMD_DEPOT",
                                        "ROBOT_CMD_INIT",
                                    };
            LOG_D("get robot cmd %s\n",rbt_cmd_str[robot_msg.robot_cmd]);
     
            //移动调试命令
            if( robot_msg.robot_cmd == ROBOT_CMD_MOVE ){
                
                if( robot_msg.type.move_msg.action == ACT_MOVE ){
                    motor_move(robot_msg.type.move_msg.axle, robot_msg.type.move_msg.position*ROBOT_AXIS_MM, robot_msg.type.move_msg.speed*ROBOT_AXIS_MM);
                    motor_wait_stop(robot_msg.type.move_msg.axle,MOTOR_TIMEOUT);
                }
                else if( robot_msg.type.move_msg.action == ACT_STOP ){
                    motor_stop(robot_msg.type.move_msg.axle);
                }
                
                //更新各个电机的距离
                if( robot_msg.type.move_msg.axle == ROBOT_Z_AXIS ){
                    robot_state.axis_mm_z = (float)motor_curr_step((motor_no_t)ROBOT_Z_AXIS)/(float)ROBOT_AXIS_MM;
                    comm_reply(EXE_OK,RBT_NO_ERR,RBT_MOVE_CMD,RT_NULL,0);
                }
                else if( robot_msg.type.move_msg.axle == ROBOT_Y_AXIS ){
                    robot_state.axis_mm_y = (float)motor_curr_step((motor_no_t)ROBOT_Y_AXIS)/(float)ROBOT_AXIS_MM;
                    comm_reply(EXE_OK,RBT_NO_ERR,RBT_MOVE_CMD,RT_NULL,0);
                }
                else if( robot_msg.type.move_msg.axle == ROBOT_IN_AXIS ){
                    robot_state.axis_mm_in = (float)motor_curr_step((motor_no_t)ROBOT_IN_AXIS)/(float)ROBOT_AXIS_MM;
                    comm_reply(EXE_OK,RBT_NO_ERR,DEPOT_MOVE_CMD,RT_NULL,0);
                }
                else if( robot_msg.type.move_msg.axle == ROBOT_A_AXIS ){
                    robot_state.axis_mm_a = (float)motor_curr_step((motor_no_t)ROBOT_A_AXIS)/(float)ROBOT_AXIS_MM;
                    comm_reply(EXE_OK,RBT_NO_ERR,DEPOT_MOVE_CMD,RT_NULL,0);
                }
                else if( robot_msg.type.move_msg.axle == ROBOT_B_AXIS ){
                    robot_state.axis_mm_b = (float)motor_curr_step((motor_no_t)ROBOT_B_AXIS)/(float)ROBOT_AXIS_MM;
                    comm_reply(EXE_OK,RBT_NO_ERR,DEPOT_MOVE_CMD,RT_NULL,0);
                }
            }
            //路径路由命令
            else if( robot_msg.robot_cmd == ROBOT_CMD_ROUTER ){
                
                //已经处于目标位置,直接返回
                if( robot_msg.type.router_msg.station == robot_state.curr_station ){
                    comm_reply(EXE_OK,RBT_NO_ERR,STATION_MOVE_CMD,RT_NULL,0);
                }
                else{
                    //如果当前已经处于制备、扩增、检测位,直接运动到各个待机位
                    //当前位置不在待机位先运动到待机位
                    if( robot_state.curr_station != DJ_STA ){
                        
                        if( robot_state.curr_station == JC_STA || robot_state.curr_station == KZ_STA ||\
                            robot_state.curr_station == ZB_STA ){
                        
                            dist = robot_state.axis_mm_z + config_get_ptr()->avoid_hight;
                                
                            dist>ROBOT_Z_UP_MAX?dist=ROBOT_Z_UP_MAX:0;
                        
                            //抬升避让高度
                            LOG_D("No1. Z-axis move to %s %d.%03d mm speed %d.%03d mm",\
                                station_name[robot_state.curr_station], \
                                (int)dist,\
                                float_to_int(dist),\
                                (int)(config_get_ptr()->station_pmt.speed.z),\
                                float_to_int(config_get_ptr()->station_pmt.speed.z));
                            robot_move_distance(ROBOT_Z_AXIS, dist, config_get_ptr()->station_pmt.speed.z);
                            if( motor_wait_stop((motor_no_t)ROBOT_Z_AXIS,MOTOR_TIMEOUT) == 3){
                                continue;
                            }
                        }
                        //运行到待机位Y轴
                        dist = config_get_ptr()->station_pmt.depot_in.y;
                        LOG_D("No2. Y-axis move to AXES %d.%03d mm speed %d.%03d mm",\
                            (int)dist,\
                            float_to_int(dist),\
                            config_get_ptr()->station_pmt.speed.y,\
                            float_to_int(config_get_ptr()->station_pmt.speed.y));
                        robot_move_distance(ROBOT_Y_AXIS, dist, config_get_ptr()->station_pmt.speed.y);
                        if( motor_wait_stop((motor_no_t)ROBOT_Y_AXIS,MOTOR_TIMEOUT) == 3){
                            continue;
                        }
                    }
                    
                    switch( robot_msg.type.router_msg.station )
                    {
                        case DJ_STA:               //待机位
                            station_target.y = config_get_ptr()->station_pmt.standby.y;
                            station_target.z = config_get_ptr()->station_pmt.standby.z;
                            break;
                        case JIN_STA:                //进料仓
                            station_target.y = config_get_ptr()->station_pmt.depot_in.y;
                            station_target.z = config_get_ptr()->station_pmt.depot_in.z;
                            break;
                        case FL1_STA:                //废料位1
                            station_target.y = config_get_ptr()->station_pmt.depot_a.y;
                            station_target.z = config_get_ptr()->station_pmt.depot_a.z;
                            break;
                        case FL2_STA:                //废料位2
                            station_target.y = config_get_ptr()->station_pmt.depot_b.y;
                            station_target.z = config_get_ptr()->station_pmt.depot_b.z;
                            break;
                        case ZB_STA:                 //制备位
                            station_target.y = config_get_ptr()->station_pmt.zb_pos.y;
                            station_target.z = config_get_ptr()->station_pmt.zb_pos.z;
                            break;
                        case JC_STA:                 //检测位
                            station_target.y = config_get_ptr()->station_pmt.jc_pos[robot_msg.type.router_msg.index].y;
                            station_target.z = config_get_ptr()->station_pmt.jc_pos[robot_msg.type.router_msg.index].z;
                            break;
                        case KZ_STA:                 //扩增位
                            station_target.y = config_get_ptr()->station_pmt.kz_pos[robot_msg.type.router_msg.index].y;
                            station_target.z = config_get_ptr()->station_pmt.kz_pos[robot_msg.type.router_msg.index].z;
                            break;
                        default:
                            break;
                    }

                    //当前位置已经是待机位,直接运行Y轴坐标
                    //运行到目标位置Z轴-20MM座标
                    if( robot_msg.type.router_msg.station != ZB_STA ){
                        dist = config_get_ptr()->station_pmt.depot_in.y;
                        LOG_D("No5. Y-axis move to %s-H %d.%03d mm speed %d.%03d mm",\
                            station_name[robot_msg.type.router_msg.station],\
                            (int)(dist),\
                            float_to_int(dist),\
                            (int)config_get_ptr()->station_pmt.speed.y,\
                            float_to_int(config_get_ptr()->station_pmt.speed.y));
                        
                        robot_move_distance(ROBOT_Y_AXIS, dist, config_get_ptr()->station_pmt.speed.y);
                        if( motor_wait_stop((motor_no_t)ROBOT_Y_AXIS,MOTOR_TIMEOUT) == 3){
                            continue;
                        }
                    }
                    
                    if( robot_msg.type.router_msg.station == KZ_STA || robot_msg.type.router_msg.station == JC_STA ||\
                        robot_msg.type.router_msg.station == ZB_STA){
                        dist  = station_target.z + config_get_ptr()->avoid_hight;
                        dist>ROBOT_Z_UP_MAX?dist=ROBOT_Z_UP_MAX:0;
                    }
                    else{
                        dist  = station_target.z;
                    }
                    //移动Y轴到目标位置坐标
                    LOG_D("No6. Z-axis move to %s %d.%03d mm speed %d.%03d mm",\
                        station_name[robot_msg.type.router_msg.station],\
                        (int)dist,\
                        float_to_int(dist),\
                        (int)config_get_ptr()->station_pmt.speed.z,\
                        float_to_int(config_get_ptr()->station_pmt.speed.z));
                    
                    robot_move_distance(ROBOT_Z_AXIS, dist, config_get_ptr()->station_pmt.speed.z);
                    if( motor_wait_stop((motor_no_t)ROBOT_Z_AXIS,MOTOR_TIMEOUT) == 3){
                        continue;
                    }
                    
                    //移动到Y轴目标坐标上方
                    dist  = station_target.y;
                    speed = config_get_ptr()->station_pmt.speed.y;
                    LOG_D("No7. Y-axis move to %s %d.%03d mm speed %d.%03d mm",\
                        station_name[robot_msg.type.router_msg.station],\
                        (int)dist,\
                        float_to_int(dist),\
                        (int)(speed),\
                        float_to_int(speed));
                    
                    robot_move_distance(ROBOT_Y_AXIS, dist, speed);
                    if( motor_wait_stop((motor_no_t)ROBOT_Y_AXIS,MOTOR_TIMEOUT) == 3){
                        continue;
                    }
                    
                    //除待机位外,其它位置的最后下降速度减半
                    if( robot_msg.type.router_msg.station == DJ_STA ){
                        speed = config_get_ptr()->station_pmt.speed.z;
                    }
                    else{
                        speed = config_get_ptr()->station_pmt.speed.z/2;
                    }
                    
                    dist  = station_target.z;
                    LOG_D("No8. Z-axis move to %s %d.%03d mm speed %d.%03d mm",\
                        station_name[robot_msg.type.router_msg.station],\
                        (int)dist,\
                        float_to_int(dist),\
                        (int)(speed),\
                        float_to_int(speed));
                    
                    robot_move_distance(ROBOT_Z_AXIS, dist, speed);
                    if( motor_wait_stop((motor_no_t)ROBOT_Z_AXIS,MOTOR_TIMEOUT) == 3){
                        continue;
                    }

                    robot_exe_exit:
                    robot_state.curr_station = robot_msg.type.router_msg.station;
                    
                    comm_reply(EXE_OK,RBT_NO_ERR,STATION_MOVE_CMD,RT_NULL,0);
                }
            }
            //手抓控制
            else if( robot_msg.robot_cmd == ROBOT_CMD_CLAMP ){
                //抓取
                 if( robot_msg.type.clamp_msg.clamp == CLAMP_TAKE ){
                     robot_clamp(1);
                     rt_thread_delay(500);
                     if( clamp_status()==CLAMP_TAKE_UP ){
                         comm_reply(EXE_OK,RBT_NO_ERR,STATION_CLAMP_CMD,RT_NULL,0);
                         LOG_D("robot clamp take up OK");
                     }
                     else{
                         comm_reply(EXE_OK,RBT_CLAMP_ERR,STATION_CLAMP_CMD,RT_NULL,0);
                         LOG_E("robot clamp take up error");
                     }
                 }
                 //释放
                 else if( robot_msg.type.clamp_msg.clamp == CLAMP_PUT ){
                     robot_clamp(0);
                     rt_thread_delay(500);
                     if( clamp_status()==CLAMP_PUT_DOWN ){
                         comm_reply(EXE_OK,RBT_NO_ERR,CLAMP_CMD,RT_NULL,0);
                         LOG_D("robot clamp put down OK");
                     }
                     else{
                         comm_reply(EXE_OK,RBT_CLAMP_ERR,CLAMP_CMD,RT_NULL,0);
                         LOG_E("robot clamp put down error");
                     }
                }
                else if( robot_msg.type.clamp_msg.clamp == CLAMP_RESET ){
                    clamp_power_up();
                    comm_reply(EXE_OK,RBT_NO_ERR,CLAMP_CMD,RT_NULL,0);
                    LOG_D("robot clamp reset");
                }
            }
            //仓位移位
            else if( robot_msg.robot_cmd == ROBOT_CMD_DEPOT ){
                
                float offset = 0;
                static const uint8_t depot_cmd[] = {DEPOT_IN_CMD,DEPOT_A_CMD,DEPOT_B_CMD};
                if( robot_msg.type.depot_msg.axle == ROBOT_IN_AXIS ){
                    offset = config_get_ptr()->depot_offset.depot_in;
                }
                else if( robot_msg.type.depot_msg.axle == ROBOT_A_AXIS ){
                    offset = config_get_ptr()->depot_offset.depot_a;
                }
                else if( robot_msg.type.depot_msg.axle == ROBOT_B_AXIS ){
                    offset = config_get_ptr()->depot_offset.depot_b;
                }
                
                if( robot_msg.type.depot_msg.loc == 0x00 ){
                    dist = config_get_ptr()->depot_pmt[robot_msg.type.depot_msg.axle-ROBOT_IN_AXIS].door;
                }
                else if( robot_msg.type.depot_msg.loc == 0x01 ){
                    dist = config_get_ptr()->depot_pmt[robot_msg.type.depot_msg.axle-ROBOT_IN_AXIS].clamp + offset*robot_msg.type.depot_msg.station;
                }
                else if( robot_msg.type.depot_msg.loc == 0x02 ){
                    dist = config_get_ptr()->depot_pmt[robot_msg.type.depot_msg.axle-ROBOT_IN_AXIS].chip + offset*robot_msg.type.depot_msg.station;
                }
                else if( robot_msg.type.depot_msg.loc == 0x03 ){
                    dist = config_get_ptr()->depot_pmt[robot_msg.type.depot_msg.axle-ROBOT_IN_AXIS].scaner + offset*robot_msg.type.depot_msg.station;
                }
                
                speed  = config_get_ptr()->depot_pmt[robot_msg.type.depot_msg.loc].speed;
                
                if( robot_msg.type.depot_msg.action == ACT_MOVE ){
                    
                    robot_move_distance(robot_msg.type.depot_msg.axle, dist, speed);
                    motor_wait_stop(robot_msg.type.depot_msg.axle,MOTOR_TIMEOUT);
                }
                else if( robot_msg.type.depot_msg.action == ACT_STOP ){
                    
                    motor_stop(robot_msg.type.depot_msg.axle);
                }
                
                if( robot_msg.type.depot_msg.axle == ROBOT_IN_AXIS ){
                    LOG_D("depot in move to %d.%d",(int)dist,float_to_int(dist));
                }
                else if( robot_msg.type.depot_msg.axle == ROBOT_A_AXIS ){
                    LOG_D("depot a move to %d.%d",(int)dist,float_to_int(dist));
                }
                else if( robot_msg.type.depot_msg.axle == ROBOT_B_AXIS ){
                    LOG_D("depot b move to %d.%d",(int)dist,float_to_int(dist));
                }
                
                comm_reply(EXE_OK,RBT_NO_ERR,depot_cmd[robot_msg.type.depot_msg.axle-ROBOT_IN_AXIS],RT_NULL,0);
            }
            //电机原点初始化
            else if( robot_msg.robot_cmd == ROBOT_CMD_INIT ){
                if( robot_reset(robot_msg.type.init_msg.motor_no) == RT_EOK ){
                    LOG_D("motor %d reset OK",robot_msg.type.init_msg.motor_no);
                }
                else{
                    LOG_E("motor %d reset failed",robot_msg.type.init_msg.motor_no);
                }
            }
        }
    }
}

比较消息队列发送的运动控制命令,例如单轴移动调试,运动路径路由,电机的初始化,手抓的控制,都将调用电机移位控制函数,执行成功与否通过comm_replay返回执行结果,电机移位控制功能可参考我博客另一篇关于步进电机S曲线计算https://editor.csdn.net/md/?articleId=132959818

相关推荐
十月的皮皮18 小时前
stm20260720-从新手 C 到量产 STM32 工程:程序设计推导指南
c语言·开发语言·stm32·stm32cubemx·hal库
开发笔记-阿牛18 小时前
解析一款有意思的产品||CK6159A语音芯片设计的儿童专注力训练机-舒尔特玩具
stm32·单片机·嵌入式硬件·音频
搞全栈小苏21 小时前
SIMetrix_simplis8.4安装教程——附安装包
stm32·单片机·嵌入式硬件·电力电子
qq_573967821 天前
STM32控制器
stm32·单片机·嵌入式硬件
某林2121 天前
履带小车底盘stm32F103RCT6开发
人工智能·stm32·单片机·嵌入式硬件·架构·人机交互·ros2
做萤石二次开发的哈哈1 天前
萤石 ERTC Windows SDK 包含哪些类型定义?
stm32·单片机·嵌入式硬件
亿道电子Emdoor1 天前
【Aitium】PCB导出DXF文件出现eDuplicateRecordName报错
stm32·单片机·嵌入式硬件·altium
巴巴媛6662 天前
STM32学习笔记【38.DHT11实验】
笔记·stm32·学习
深圳市泰凌微电子2 天前
HK航顺 HK32F407RGT7替STM32F405RGT6 微控制器32位MCU
stm32·单片机·嵌入式硬件
小心亦新2 天前
STM32学习16--定时器输出比较2直流电机
stm32·嵌入式硬件·学习