前言

衔接上一篇文章,这篇文章主要来介绍项目的初步实现
在这里插入图片描述

一、四足步态

可以知道,该四足机器人由八个舵机组成,其中大腿四个(①②③④),小腿四个(⑤⑥⑦⑧),如下图所示:
在这里插入图片描述

  • 第一,组装。在组装时先将每个舵机的状态调到90°,按90°状态进行组装。
  • 第二,角度。你需要知道这八个舵机点位的的转动区间,比如哪个点是0°,哪个点是180°,做好记录后才能更方便的去设计。
  • 第三,运动分析。其实可参考小猫的步态,通过观察发现有两种走法,一是在同一时刻有三支腿是同时踩在地上的只有一只腿提起来摆动,二是同一时刻成对角的两条腿动,两两交替行走。

在这里插入图片描述
我这里设计用成对角的两条腿交替运动的方法,需要注意的是在每次移动时都要将小腿提起来,再摆动大腿,然后放下小腿,这样才能控制移动到你想要的方向,具体设计如下:

  • 首先初始化各点位状态。这里初始化也是有讲究的,需要根据你想要移动的幅度去设计,可以45°,可以90°等,这里我选用45°,即大腿初始化位置如下图所示,小腿初始化皆为90°。
    在这里插入图片描述
void Init(void)
{
      rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL1, period, angle_90);      //大腿
      rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL2, period, angle_90);  
      rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL3, period, angle_135);  
      rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL4, period, angle_45);  
      rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL1, period, angle_90);      //小腿
      rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL2, period, angle_90);  
      rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL3, period, angle_90);  
      rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL4, period, angle_90); 
}
  • 向前迈进
    在这里插入图片描述
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL1, period, angle_45);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL1, period, angle_0);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL1, period, angle_90);  

    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL4, period, angle_45); 
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL4, period, angle_90);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL4, period, angle_90);  
    rt_thread_mdelay(400);

    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL4, period, angle_45);  
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL1, period, angle_45);  

    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL3, period, angle_45);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL3, period, angle_90);
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL3, period, angle_90);


    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL2, period, angle_45);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL2, period, angle_180); 
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL2, period, angle_90); 
    rt_thread_mdelay(400);

    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL3, period, angle_135);  
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL2, period, angle_135);  

在这里插入图片描述

  • 原地转圈。让每只脚顺/逆时针移动90°,然后同时摆动大腿点位
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL1, period, angle_45); 
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL1, period, angle_90); 
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL1, period, angle_90); 
    rt_thread_mdelay(100);

    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL2, period, angle_45);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL2, period, angle_180);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL2, period, angle_90);  
    rt_thread_mdelay(100);

    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL3, period, angle_45);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL3, period, angle_180); 
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL3, period, angle_90);
    rt_thread_mdelay(100);

    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL4, period, angle_45);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL4, period, angle_90);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm3_dev, PWM_DEV_CHANNEL4, period, angle_90);  
    rt_thread_mdelay(400);

    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL1, period, angle_0); 
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL2, period, angle_90); 
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL3, period, angle_90); 
    rt_pwm_set(pwm2_dev, PWM_DEV_CHANNEL4, period, angle_0);  

在这里插入图片描述

二、视觉抓取

通过OpenMV摄像头去识别物块且区分颜色,利用机械臂去抓取物块并放置于不同盒子里,摄像头视角可实时在PC/iPhone显示。

  • 1. 摄像头

(1) WiFi无线图传

import sensor, image, time, network, usocket, sys

SSID ='Bit_Dong'    # Network SSID
KEY  ='1234567890'    # Network key (must be 10 chars)
HOST = ''           # Use first available interface
PORT = 8080         # Arbitrary non-privileged port


sensor.reset()
sensor.set_framesize(sensor.QQVGA)
sensor.set_pixformat(sensor.GRAYSCALE)

wlan = network.WINC(mode=network.WINC.MODE_AP)
wlan.start_ap(SSID, key=KEY, security=wlan.WEP, channel=2)

def start_streaming(s):
    client, addr = s.accept()

    client.settimeout(2.0)

    data = client.recv(1024)

    client.send("HTTP/1.1 200 OK\r\n" \
                "Server: OpenMV\r\n" \
                "Content-Type: multipart/x-mixed-replace;boundary=openmv\r\n" \
                "Cache-Control: no-cache\r\n" \
                "Pragma: no-cache\r\n\r\n")

    clock = time.clock()
    while (True):
        clock.tick() # Track elapsed milliseconds between snapshots().
        frame = sensor.snapshot()
        cframe = frame.compressed(quality=35)
        header = "\r\n--openmv\r\n" \
                 "Content-Type: image/jpeg\r\n"\
                 "Content-Length:"+str(cframe.size())+"\r\n\r\n"
        client.send(header)
        client.send(cframe)


while (True):
    s = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
    try:
        s.bind([HOST, PORT])
        s.listen(5)
        s.settimeout(3)
        start_streaming(s)
    except OSError as e:
        s.close()

(2) 色块识别
①寻找最大色块

def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    return max_blob

②颜色辨识,读取20次判断结果,取众数并传到MCU

for i in range(20):
    for blob in img.find_blobs([thresholds[0]], roi=ROI, x_stride=10, y_stride=5,pixels_threshold=10, area_threshold=10, merge=True):   #模板匹配函数
        x=blob.area()
    for blob in img.find_blobs([thresholds[1]], roi=ROI, x_stride=10, y_stride=5,pixels_threshold=10, area_threshold=10, merge=True):   #模板匹配函数
        y=blob.area()
    if x>y:
        x_num+=1
    else:
        y_num+=1

if x_num>y_num:
    uart.write("1")
else:
    uart.write("2")
  • 2. 机械臂
    我这里为四自由度的舵机,抓取释放可分为如下四个步骤进行。

(1)初始化

    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL1, period, angle_90);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL2, period, angle_90);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL3, period, angle_135);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL4, period, angle_90);  
    rt_thread_mdelay(400);

(2)向下抓取

    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL1, period, angle_45);  /* 爪子打开*/
    rt_thread_mdelay(100);
    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL2, period, angle_180);  
    rt_thread_mdelay(100);
    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL4, period, angle_90);  
    rt_thread_mdelay(400);

(3)抓到搬运

    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL1, period, angle_110);  /* 爪子闭紧*/
    rt_thread_mdelay(300);
    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL2, period, angle_90); 
    rt_thread_mdelay(100);

(4)放盒回正

    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL4, period, angle_165);  
    rt_thread_mdelay(400);
    rt_pwm_set(pwm4_dev, PWM_DEV_CHANNEL1, period, angle_45);  
    rt_thread_mdelay(400);

在这里插入图片描述

三、远程遥控

MCU之间采用蓝牙进行通信

  • 遥控器
    通过用ADC采集四个电位器信息和按键键值控制四足机器人或机械臂运动。

1. 数据采集

    rt_uint8_t typeId=key_sw1_status;
    uploadpackT.linear  = value[0]/22.75;    // 4095/22.75=180°
    uploadpackT.angular = value[1]/22.75;
    uploadpackT.vra     = value[2]/22.75;
    uploadpackT.vrb     = value[3]/22.75;
    uploadpackT.switch_code = key_sw2_status;

2. 打包

int8_t  pack(ProtocolBufferT *handler,uint8_t type, void* src, uint16_t size, uint8_t** dest,uint16_t* dest_size )
{
    assert(size+7 < handler->max_size);
    assert(type>0 && type < 128);
    handler->data[0] = PROTO_HEAD0;
    handler->data[1] = PROTO_HEAD1;
    handler->data[2] = size & 0xff;
    handler->data[3] = size >> 8;
    handler->data[4] = type;
    memcpy(handler->data+5, src, size );
    handler->pack_len = size;
    uint16_t sum = calc_sum(handler);
    handler->data[size+5] = sum & 0xff;
    handler->data[size+6] = sum >> 8;
    handler->data_ptr = size+7 ;
    if (dest)      (*dest) = handler->data;
    if (dest_size) (*dest_size) = handler->data_ptr;
    return 0;
}

3. 验包

int8_t  check_pack(ProtocolBufferT *handler)
{
    int8_t check_header = 1;
    do {
        check_header = 0;
        if (!(handler->data[0] == PROTO_HEAD0 && handler->data[1] == PROTO_HEAD1))
        {
            update_next_header(handler,1);
            check_header = 1;
        }
        if (handler->data_ptr < 5 ) {
            handler->status = 0;
            return 0;
        }
        handler->pack_len = *((uint16_t*) (&handler->data[2]));
        if (handler->pack_len + 7 >= handler->max_size)
        {
            update_next_header(handler,1);
            check_header = 1;
        }
    } while(check_header);
    if (handler->data_ptr < handler->pack_len +7 ) {
        handler->status = 0;
        return 0;
    }
    uint16_t checksum = handler->data[handler->pack_len + 5] + (handler->data[handler->pack_len + 6]<<8);
    uint16_t sum = calc_sum(handler);
    if (sum == checksum)
    {
        handler->status = 1;
        handler->type   = handler->data[4];
        return handler->type;
    }
    // else checksum failed
    printf("checksum failed\n");
    for(int i = 0 ; i < handler->pack_len; ++i) {
        printf("%02x ", handler->data[i]);
    }
    update_next_header(handler,1);
    handler->status = 0;
    return 0;
}

技术交流,联系下方wx即可

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐