基于四足机器人和机械臂的运动控制系统(二)

文章目录

  • 前言
  • 一、四足步态
  • 二、视觉抓取
  • 三、远程遥控


谢绝转载,无作者许可不可用做其他用途(如教育展示产品、课程设计或毕业设计等)

前言

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

一、四足步态

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

  • 第一,组装。在组装时先将每个舵机的状态调到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即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/504869.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

常用的几种排序算法小结

目录 1.冒泡排序 2.堆排序 2.1堆的基础知识和特性 2.2向上调整算法和向下调整算法 2.3堆排序实现 3.插入排序 4.希尔排序 5.选择排序 5.1选择排序递归版 5.2选择排序非递归版 6.快速排序 6.1 Hoare版本之递归 6.1.1普通版 6.1.2随机数版 6.1.3三数取中版 6.1.4小区间优化…

前端虚拟滚动列表 vue虚拟列表

前端虚拟滚动列表 在大型的企业级项目中经常要渲染大量的数据&#xff0c;这种长列表是一个很普遍的场景&#xff0c;当列表内容越来越多就会导致页面滑动卡顿、白屏、数据渲染较慢的问题&#xff1b;大数据量列表性能优化&#xff0c;减少真实dom的渲染 看图&#xff1a;绿色…

安装最新的wxPython和Python3并保证二者兼容

要安装最新的wxPython和Python3并保证二者兼容&#xff0c;你可以按照以下步骤进行操作&#xff1a; 安装Python3&#xff1a; 访问Python官方网站下载适合你操作系统的最新版Python3安装包。运行安装程序&#xff0c;确保在安装过程中将Python添加到系统环境变量中。安装完成…

【Java】:static成员和代码块

目录 1.static成员 1.1再谈学生类 1.2static修饰成员变量 1.3static修饰成员方法 1.4static成员变量初始化 1.4.1就地初始化 1.4.2静态代码块初始化 2.代码块 2.1代码块概念以及分类 2.2普通代码块 2.3构造代码块 2.4静态代码块 1.static成员 1.1再谈学生类 使用类…

MATLAB 点云随机渲染赋色(51)

MATLAB 点云随机渲染赋色(51) 一、算法介绍二、算法实现1.代码2.效果总结一、算法介绍 为点云中的每个点随机赋予一种颜色,步骤和效果如图: 1、读取点云 (ply格式) 2、随机为每个点的RGB颜色字段赋值 3、保存结果 (ply格式) 二、算法实现 1.代码 代码如下(示例):…

gin基础学习笔记--参数验证

用gin框架的数据验证&#xff0c;可以不用解析数据&#xff0c;减少if else&#xff0c;会简洁许多。 package mainimport ("fmt""time""github.com/gin-gonic/gin""github.com/gorilla/sessions" )// 初始化一个cookie存储对象 // s…

基于STM32的武警哨位联动报警系统设计,支持以太网和WIFI通信

1.功能 本文提出的武警报警信息系统终端&#xff0c;可实现报警和联动响应&#xff0c;支持以太网和WIFI两种通信模式&#xff0c;可实现移动哨位报警和固定哨位报警&#xff0c;语音和显示报警信息用户可自行定制。 本终端主要由STM32F103处理器模块和C8051F340处理器模块构…

P-MapNet:Far-seeing Map Generator Enhanced by both SDMap and HDMap Priors

主页&#xff1a;homepage 参考代码&#xff1a;P-MapNet 动机与出发点 在感知系统中引入先验信息是可以提升静态元素感知网络的上限的&#xff0c;这篇文章对SD地图采用栅格化表示&#xff08;也就是图像形式&#xff09;&#xff0c;之后用CNN网络去抽取栅格化SD地图的信息&…

linux ubuntu 在保存文件不被允许,但是root权限

现象&#xff1a;MobaXterm_Personal_2登录到服务器&#xff0c;切换到root用户&#xff0c;然后使用MobaXterm_Personal_2自带的编辑器&#xff0c;编写文件&#xff0c;进行保存不被允许&#xff1b;查看目录root是有权限进行修改文件的&#xff0c;然后使用vim进行修改保存&…

网络安全-内网渗透2

一、MIC 将我们上次未描述完的MIC在这里详细解释一下 咱们所抓的第二个包会给返回一个服务端的challenge 之后服务器回包的第三个包会回复一个client challenge 所以咱们客户端和服务端现在分别有两个challenge&#xff0c;相当于客户端和服务端互相交换了一下challenge 因此…

本地搭建多人协作ONLYOFFICE文档服务器并结合Cpolar内网穿透实现公网访问远程办公

文章目录 1. 安装Docker2. 本地安装部署ONLYOFFICE3. 安装cpolar内网穿透4. 固定OnlyOffice公网地址 本篇文章讲解如何使用Docker在本地服务器上安装ONLYOFFICE&#xff0c;并结合cpolar内网穿透实现公网访问。 Community Edition允许您在本地服务器上安装ONLYOFFICE文档&…

高精度(大整数)

本文用于记录个人算法竞赛学习&#xff0c;仅供参考 一.什么是大整数 当一个数的位数已经很大了&#xff08;比如有10^6&#xff09;&#xff0c;常规的数据类型已经存不下了&#xff0c;那么这个时候就可以用数组来存&#xff0c;数组的每个元素代表数的每一位&#xff0c;且…

Base64编码的全面介绍

title: Base64编码的全面介绍 date: 2024/3/31 18:55:49 updated: 2024/3/31 18:55:49 tags: Base64编码网络传输文本转换数据膨胀非加密性质应用场景安全传输 1. Base64的定义和作用 Base64是一种用64个字符表示二进制数据的编码方式&#xff0c;通常用于在网络传输中将二进…

什么是Redis数据一致性?如何解决?

在系统中缓存最常用的策略是&#xff1a;服务端需要同时维护DB和cache&#xff0c;并且是以DB的结果为准–Cache-Aside Pattern&#xff08;缓存分离模式、旁路缓存&#xff09; 读数据 单纯的读数据是不会产生数据不一致&#xff0c;只有并发下读和写才会存在数据不一致。 写…

安装即启动?探索流氓App的自启动“黑科技” (Android系统内鬼之ContentProvider篇)

前段时间发现了一个神奇的app&#xff0c;它居然可以在安装之后立即自启动&#xff1a; 看到没有&#xff0c;在提示安装成功大概1到2秒后&#xff0c;就直接弹出Toast和通知了&#xff01; 好神奇啊&#xff0c;在没有第三方app帮忙唤醒的前提下&#xff0c;它是怎么做到首次安…

2024年 前端JavaScript 进阶 第2天 笔记

2.1-内容和创建对象方式 2.2-164-构造函数 2.3-new实例化执行过程 2.4-实例成员和静态成员 2.5-基本包装类型 2.6-0bject静态方法 2.7-数组reduce累计方法 对象数组 加0 2.7-数组find、every和转换为真 --说明手册文档 MDN Web Docs 2.8-字符串常见方法 2.3 String 1.常见实例…

【yolo检测】基于YOLOv8与DeepSORT实现多目标跟踪

1.配置环境 conda版本23.5.0 创建虚拟环境&#xff0c;Python版本选择3.10&#xff0c;环境命名为yolov8 conda create --name yolov8 python3.10进入环境 conda activate yolov82.安装工具包 实测网络问题可以用手机热点或者加-i镜像解决。 pip install -r requirements.t…

C语言操作符详细讲解

前言 本次博客一定会让刚刚学习C语言小白有所收获 本次操作符讲解不仅分类还会有代码示例 好好看 好好学 花上几分钟就可以避免许多坑 1 操作符的基本使用 1.1操作符的分类 按功能分 算术操作符&#xff1a; 、- 、* 、/ 、% 移位操作符: >> << 位操作符…

Keil界面乱了,某些图标消失

文章目录 如图 如图 我都不知道怎么搞的第一个 重启界面解决了

【微服务框架】微服务简介

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…