基于野火F407骄阳开发板的苹果采摘机器人机械臂的采摘轨迹与夹持器的采摘动作的设计(1)

基于野火F407骄阳开发板的苹果采摘机器人机械臂的采摘轨迹与夹持器的采摘动作的设计(1)

  • 苹果采摘机器人
    • 1、采摘流程与硬件设计
    • 2、机械臂驱动以及采摘轨迹设计
      • 2.1、台达A2电机驱动实现
      • 2.2、机械臂寻找苹果巡逻轨迹

苹果采摘机器人

1、采摘流程与硬件设计

苹果采摘机器人的流程框图和硬件图,如下图所示。简单介绍下采摘流程,摄像头采集环境画面,如果画面中没有苹果,那么机械臂将以设定的运动轨迹运动,直至画面中出现苹果。一旦画面出现苹果,F04骄阳开发板将会驱动机械臂电机对准苹果与夹持器电机实现对苹果的抓取。完成采摘之后,机械臂将继续以设定的运动轨迹运动。
在这里插入图片描述
首先,由夹持器内侧的摄像头采集外部环境图片,将图片信息传输到nano开发板之后,由nano开发板进行深度学习图像处理,可以得到目标苹果与画面正中心位置的偏差量。将偏差量和是否存在苹果等信息量以串口的形式发送到野火F407骄阳开发板。F407会根据得到的信息量,进行处理,不存在苹果则机械臂以指定的轨迹动作。否则进行采摘苹果动作。
(注:本文将下图中机械臂和电动推杆合称机械臂。末端执行器部分将在后续文章中详细讲解)
在这里插入图片描述

2、机械臂驱动以及采摘轨迹设计

三轴机械臂的伺服驱动器皆为台达的asda-a2系列。设置了驱动器的驱动模式(默认为:脉冲+方向)、电子齿轮比(指令为:P1-44、P1-45。功能就是根据输入的PWM数量,决定电机的旋转圈数。具体如何设置可以查询A2的使用手册)、SON(以指令设置的方式强制使能伺服驱动器)。通过查询A2使用手册中的CN1部分信号接线,发现台达官方只提供了5V和24V的电源系统连接方式。但是通过实际测试,发现F407以5V系统的接线方式,发送PWM和方向信号,伺服驱动器是完全能够接收到脉冲的。下面给出了5V系统的接线方式和电子齿轮比的设置,具体内容可以查看A2的使用手册。
在这里插入图片描述
在这里插入图片描述

2.1、台达A2电机驱动实现

由于机械臂上限位开关的损坏,那个推杆就没有限位开关。于是决定使用主从定时器的方式实现软件限位。主定时器:产生PWM波,从定时器:监视主定时器产生的PWM波,并产生中断,中断内部根据当前电机方向信号的正负决定限制角度的加减,实现软件限位。为什么不用主定时器开启中断,一定使用从定时器产生中断呢?因为担心主定时器开启中断,会导致中断次数太频繁会影响到主函数的执行。这里就相当于主定时器对从定时器起分频作用。
首先就是脉冲引脚和方向引脚的初始化

void TIMx_GPIO_Config(void)
{
	/* 定义一个 GPIO_InitTypeDef 类型的结构体 */
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 开启定时器相关的 GPIO 外设时钟 */
	TIMER_1_Master_CLK_ENABLE();
	TIMER_2_Master_CLK_ENABLE();
	TIMER_3_Master_CLK_ENABLE();
	Motor_A_CLK_ENABLE();
	Motor_B_CLK_ENABLE();
	Motor_C_CLK_ENABLE();
	
	/* 定时器PWM脉冲复用引脚初始化 */
	GPIO_InitStructure.Pin = TIMER_1_Master_PIN;
	GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStructure.Pull = GPIO_NOPULL;
	GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
	GPIO_InitStructure.Alternate = TIMER_1_Master_AF;
	HAL_GPIO_Init(TIMER_1_Master_GPIO_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.Pin = TIMER_2_Master_PIN;
  GPIO_InitStructure.Alternate = TIMER_2_Master_AF;
	HAL_GPIO_Init(TIMER_2_Master_GPIO_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.Pin = TIMER_3_Master_PIN;
	GPIO_InitStructure.Alternate = TIMER_3_Master_AF;
	HAL_GPIO_Init(TIMER_3_Master_GPIO_PORT, &GPIO_InitStructure);
	
	
	GPIO_InitTypeDef GPIO_InitStructureDR;
	/* 伺服电机方向引脚初始化 */
	GPIO_InitStructureDR.Pin = Motor_A_DIR_PIN;
	GPIO_InitStructureDR.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStructureDR.Pull = GPIO_NOPULL;
	GPIO_InitStructureDR.Speed = GPIO_SPEED_HIGH;
	HAL_GPIO_Init(Motor_A_DIR_GPIO_PORT, &GPIO_InitStructureDR);
	
	GPIO_InitStructureDR.Pin = Motor_B_DIR_PIN;
	HAL_GPIO_Init(Motor_B_DIR_GPIO_PORT, &GPIO_InitStructureDR);
	
	GPIO_InitStructureDR.Pin = Motor_C_DIR_PIN;
	HAL_GPIO_Init(Motor_C_DIR_GPIO_PORT, &GPIO_InitStructureDR);
}

然后是主从定时器的设置,设置TIM1为主定时器,TIM2为从定时器。主从定时器的设置是有限制要求的。触发源只能是ITR0~ITR4,每组主从定时器只能用一个,且不能重复。本文一共是三轴,三组主从定时器。具体细节可以查询其他人的文章,这里不具体详解。PWM波的周期越小,电机转速就越快。而想要实现电机转速变快,只要修改主定时器的period周期和pulse变量就行,占空比尽可能在50%。Error_Handler();可以自己设置,查看是否主从定时器配置出了问题。
在从定时器的最后,开启了从定时器中断,来记录产生的PWM波的数量

/**********************X轴PWM定时器配置:主TIM1、从TIM2***********************************/
/*******************************主定时器配置***********************************/
void MX_Master_TIM1_Init(uint16_t period,uint16_t prescaler,uint16_t pulse)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef          sConfigOC = {0};
	/* TIM1 clock enable */
	__HAL_RCC_TIM1_CLK_ENABLE();

    
  htim1.Instance = TIM1;                                //设置主定时器为TIM1
  htim1.Init.Prescaler = prescaler;                     //设置PWM频率
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;          //设置计数模式为向上计数
  htim1.Init.Period = period;                           //设置占空比-周期
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;    //设置为无分频
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
 
    
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;              //更新事件被选为触发输入
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;       //开启主从模式
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1 , &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
    
  sConfigOC.OCMode = TIM_OCMODE_PWM1;            //设置PWM模式为PWM1
  sConfigOC.Pulse = pulse;                       //设置PWM占空比 = pulse / period 
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;     //设置PWM空闲状态引脚拉低
	sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }    
	
	HAL_TIM_Base_Stop(&htim1);
}


/**********************从TIM2定时器配置***********************************/
void MX_Slave_TIM2_Init(uint16_t period)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
	TIM_MasterConfigTypeDef sMasterConfig = {0};
	/* TIM2 clock enable */
  __HAL_RCC_TIM2_CLK_ENABLE();

  htim2.Instance = TIM2;                                   //设置从定时器为TIM2
  htim2.Init.Prescaler = 0;                                 //设置从定时器频率为0
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;             //设置计数模式为向上计数
  htim2.Init.Period =period;                               //这个大于0就行
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;       //设置为无分频 
  htim2.Init.RepetitionCounter = 0;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;	
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
        
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ITR0;  //设置为内部时钟触发,即为TIM1
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
    
  sSlaveConfig.SlaveMode =  TIM_SLAVEMODE_EXTERNAL1;          //设置为外部触发
  sSlaveConfig.InputTrigger = TIM_TS_ITR0;                    //设置ITR0(tim1)为输入源
  sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;  //设置触发模式为上升沿
  sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;  //设置无预分频 
  sSlaveConfig.TriggerFilter = 0x0;                           //设置无滤波
    
  if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
	
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
	
	/* TIM2 interrupt Init */
  HAL_NVIC_SetPriority(TIM2_IRQn, 2, 2);
  HAL_NVIC_EnableIRQ(TIM2_IRQn);
	
}
/****************************************************************************/

下面是中断部分。根据Motor_A_DIR_PIN方向引脚的正负来决定限制角度Limit_angle_A的加减,以此来记录当前电机相对初始状态的旋转位置。

void TIM2_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&htim2);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/************************从定时器5中断*********************************/
    if(htim==(&htim2))
    {
		//	更新中断,计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
			if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_TRIGGER) != RESET)
			{
				__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_TRIGGER);
				if(HAL_GPIO_ReadPin(Motor_A_DIR_GPIO_PORT, Motor_A_DIR_PIN))
				{
					Limit_angle_A += 2;		
				}
				else
				{
					Limit_angle_A -= 2;
				}			
			}	
	  }
}

主函数部分,PWM的产生与停止由HAL_TIM_PWM_Start()与HAL_TIM_PWM_Stop()函数控制。

/*PWM输出引脚、方向引脚初始化(机械臂电机控制)*/
	TIMx_GPIO_Config();
	//主定时器1周期、分频、占空比配置
	MX_Master_TIM1_Init(400,71,200);
	//从定时器2周期配置
	MX_Slave_TIM2_Init(20);
	/******************X轴PWM发生、限位启动项*******************/
	//主定时器1时基使能
	HAL_TIM_Base_Start(&htim1);
	//主定时器2开始产生PWM波、停止产生PWM波
//	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
//	HAL_TIM_PWM_Stop(&htim1,  TIM_CHANNEL_1);
	//开启从定时器2中断模式
	HAL_TIM_Base_Start_IT(&htim2);

以上是单轴电机控制的代码,需要多个轴运动的话,复制修改即可。

2.2、机械臂寻找苹果巡逻轨迹

巡逻轨迹就是机械臂来回往复寻找苹果的过程。代码实现就是机械臂对准的方位由采摘机器人主视图左上角移动到右上角,然后控制机械臂下降一定距离。再由右到左以此往复,直至巡逻完成一整个苹果树。

void Picking_auto_posture()
{
//最初状态:将机械臂回归到摄像头视野最左上方
	if ((Save_locus_A == 8000 && Save_locus_B == 4000) || Save_locus_Flag == K)
	{
		Motor_A_CW; 														
		//X轴电机左转
		HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
		while(Limit_angle_A < 12000);
		HAL_TIM_PWM_Stop(&htim1,  TIM_CHANNEL_1);
		Motor_B_CCW;             								//Y轴上升
		HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
		while(Limit_angle_B > 1000);
		HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
		
		Save_locus_A = Limit_angle_A;
		Save_locus_B = Limit_angle_B;
		Save_locus_Flag = 0;   //机械臂初始状态已经完成 flag = 0
	}
	
//状态:x最左侧,y轴第一行运动,由左->右
	if (Save_locus_Flag == 0)
	{
		Motor_A_CCW; 														//X轴电机右转
		HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
		if (Limit_angle_A < 4000)
		{
			Save_locus_Flag = 1;
			HAL_TIM_PWM_Stop(&htim1,  TIM_CHANNEL_1); //X轴电机停止
		}
	}
//状态:y轴下降,x轴最右侧
	if (Save_locus_Flag == 1)
	{
		Motor_B_CW; 														//Y轴电机下降
		HAL_TIM_PWM_Start(&htim3,  TIM_CHANNEL_1);
		if (Limit_angle_B > 1500)
		{
			Save_locus_Flag = 2;
			HAL_TIM_PWM_Stop(&htim3,  TIM_CHANNEL_1); //Y轴电机停止
		}
	}
...

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

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

相关文章

C++/Qt 小知识记录3

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识 QLineEdit限制输入大于0的正整数QLayout内清空已布局的WidgetWindows结束进程直接结束&#xff0c;子进程不响应结束事件正常结束&#xff0c;子进程响应结束事件 CMake关闭控制台Console实体与值对…

尾调用优化

尾调用优化 最近遇到一个堆栈溢出的问题&#xff0c;分析后发现可收敛为递归边界问题。结合“红宝书”中相关内容和ES6规范中的一些优化机制&#xff0c;整理记录如下。 前言 程序运行时&#xff0c;计算机会为应用程序分配一定的内存空间。应用程序会自行分配所获得的内存空…

数组或结构体赋值时memcpy与直接赋值的效率比较

先上结论&#xff1a; 二者不一定谁快通常情况下&#xff0c;数组维度越大&#xff0c;使用memcpy效率更高数组维度越大&#xff0c;直接赋值耗时主体是循环耗时 Note&#xff1a; “等号赋值”被编译器翻译成一连串的MOV指令&#xff0c;而memcpy则是一个循环。“等号赋值”比…

深入解析PyTorch中的模型定义:原理、代码示例及应用

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【一起啃书】《机器学习》第六章 支持向量机

文章目录 第六章 支持向量机6.1 间隔和支持向量6.2 对偶问题6.3 核函数6.4 软间隔与正则化6.5 支持向量回归6.6 核方法6.7 一些问题 第六章 支持向量机 6.1 间隔和支持向量 给定训练样本集 D { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } , y i ∈ { − 1 , …

Day 1 认识软件测试——(软件测试定义、目的、原则)

Day 1 认识软件测试——(软件测试定义、目的、原则) 文章目录 Day 1 认识软件测试——(软件测试定义、目的、原则)软件测试的定义软件测试的目的软件测试的经济学问题黑盒测试白盒测试软件测试原则小结所谓软件测试,就是一个过程或一系列过程,用来确定计算机代码完成了其…

《我命由我不由天》蔡志忠——笔记一

目录 简介 经典摘录 三岁决定一生 父母该什么时候放手 确定将来要成为什么 积极主动为目标而努力 叛逆是最伟大的创意 父亲给蔡志忠最大的影响是教会他两件事 价值观缺陷导致的后果 人有三个阶段 简介 作者 蔡志忠&#xff0c;李虹。 蔡志忠&#xff1a;漫画家、哲…

Vue加SpringBoot实现项目前后端分离

首先需要搭建一个Vue的脚手架项目&#xff08;已经放在gitee里面了&#xff0c;下面是gitee网址&#xff0c;可以直接拉&#xff09; (vue-web: 这个是Vue项目模板&#xff0c;没有后台数据) 那么接下来就是实现前后端分离的步骤 首先我们需要有一个登录页面 登录的点击事件利用…

图神经网络:(节点分类)在KarateClub数据集上动手实现图神经网络

文章说明&#xff1a; 1)参考资料&#xff1a;PYG官方文档。超链。 2)博主水平不高&#xff0c;如有错误还望批评指正。 3)我在百度网盘上传了这篇文章的jupyter notebook。超链。提取码8888。 文章目录 文献阅读&#xff1a;代码实操&#xff1a; 文献阅读&#xff1a; 参考文…

【Hello Algorithm】归并排序及其面试题

作者&#xff1a;小萌新 专栏&#xff1a;算法 作者简介&#xff1a;大二学生 希望能和大家一起进步 本篇博客简介&#xff1a;介绍归并排序和几道面试题 归并排序及其面试题 归并排序归并排序是什么归并排序的实际运用归并排序的迭代写法归并排序的时间复杂度 归并排序算法题小…

(十一)地理数据库创建——创建新的地理数据库

地理数据库创建——创建新的地理数据库 目录 地理数据库创建——创建新的地理数据库 1.地理数据库概述2.地理数据库建立一般过程2.1地理数据库设计2.2地理数据库建立2.2.1从头开始建立一个新的地理数据库2.2.2移植已经存在数据到地理数据库2.2.3用CASE工具建立地理数据库 2.3建…

Python 科研绘图可视化(后处理)Matplotlib - 2D彩图

Introduction 科研可视化是将数据和信息转化为可视化形式的过程&#xff0c;旨在通过图形化展示数据和信息&#xff0c;使得科研工作者能够更好地理解和分析数据&#xff0c;并从中发现新的知识和洞见。科研可视化可以应用于各种领域&#xff0c;如生物学、物理学、计算机科学…

C++类和对象再探

文章目录 const成员再谈构造函数成员变量的定义函数体内赋值初始化列表 隐式类型转换explicitstatic成员 const成员 我们知道在调用类的成员函数时,会有一个默认的this指针且这个this指针时不可以被修改的,例如在日期类中,会有隐式的Date * const this;注意这里默认会在this前…

一五一、web+小程序骨架屏整理

骨架屏介绍 请点击查看智能小程序骨架屏 车载小程序骨架屏 车载小程序为方便开发者设置骨架屏&#xff0c;在智能小程序的基础上抽取出骨架屏模板&#xff0c;开发者只需要在 skeleton 文件夹下配置config.json&#xff08;page 和骨架屏的映射关系文件&#xff09;即可生效骨…

第十四届蓝桥杯青少组模拟赛Python真题 (2022年11月8日)

第十四届蓝桥杯青少组模拟赛Python真题 (2022年11月8日) 编程题 第 1 题 问答题 二进制位数 十进制整数2在十进制中是1位数,在二进制中对应10,是2位数。 十进制整数22在十进制中是2位数,在二进制中对应10110,是5位数。 请问十进制整数2022在二进制中是几位数? 第2题问…

Pr 拍立得风格图片展示

哈喽&#xff0c;各位小伙伴&#xff01;今天我们来学习一下如何制作拍立得风格的照片展示效果&#xff1f; 新建三个序列 在开始之前&#xff0c;我们需要新建三个序列 序列1&#xff1a;总合成-尺寸1902*1080序列2&#xff1a;照片合成-尺寸1920*1080序列3&#xff1a;照片…

自动驾驶TPM技术杂谈 ———— I-vista验收标准(试验规程)

文章目录 术语介绍试验准备场地要求环境要求精度要求边界车辆&路沿石 试验方法能力试验双边界车辆平行车位白色标线平行车位双边界车辆垂直车位白色标线垂直车位方柱垂直车位双边界车辆斜向车位白色标线斜向车位 新功能评价平行车位远程操控泊入泊出试验垂直车位远程操控泊…

能伸展脖子的机器人?东京大学最新研究成果:基于鸵鸟肌肉骨骼结构和行为,具有高度灵活性的新型机械臂—RobOstrich(附论文)

原创 | 文 BFT机器人 得益于高度灵活的颈部&#xff0c;鸟类可以做很多事情&#xff0c;无论是转过头梳理自己的后背&#xff0c;在飞行过程中“眼观六路”&#xff0c;还是在地面或树上难以触及的角落和缝隙寻找食物。而在所有鸟类中&#xff0c;鸵鸟以其结实灵巧的颈部脱颖而…

​ NISP一级备考知识总结之信息安全概述、信息安全基础

参加每年的大学生网络安全精英赛通过初赛就可以嫖一张 nisp&#xff08;国家信息安全水平考试&#xff09; 一级证书&#xff0c;nisp 一级本身没啥考的价值&#xff0c;能白嫖自然很香 1.信息安全概述 信息与信息技术 信息概述 信息奠基人香农认为&#xff1a;信息是用来消…

【Linux】如何实现单机版QQ,来看进程间通信之管道

学会了管道&#xff0c;就可以实现简单的qq哦~ 文章目录 前言一、匿名管道总结 前言 为什么要进行进程间通信呢&#xff1f;因为需要以下这些事&#xff1a; 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 …