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

news2024/11/17 23:34:36

基于野火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轴电机停止
		}
	}
...

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

fio 使用碰到的坑,一些不常用,但可能用到的参数(校验 跳跃 多线程)

1&#xff0c; 祼盘读写 一个分区 -filename/dev/sdb1 同时测试多个分区 -filename/dev/sdb1;/dev/sdb2 比例&#xff1a; fio -filename/dev/sdb1 -direct1 -iodepth 1 -thread -rwrandread -ioenginepsync -bs4k -size50G -numjobs10 -runtime1000 -group_reporting -nam…

es6的语法糖,展开运算符,类的实现

1.0 ES6语法糖 [重点] 1.1数组的解构赋值 // 声明多个变量 let [a,b,c] [1,2,3] ​ let a1&#xff0c;b2&#xff1b; // 交换数值 [a,b] [b,a] ​2 1.12 函数的参数结构 1.2对象的解构 对象存在键值对&#xff0c;如果需要解构对象&#xff0c;你需要使用对象的键名为变量…

Flask 知识点整理

文章目录 1.URL与视图的映射带参数的url&#xff1a;将参数固定到了path中查询字符串的方式传参 2.模板渲染给html文件传参 3.模板访问对象属性User 是个类User是个字典 4.过滤器的使用通过一个 | 管道符进行过滤自定义过滤器 5.控制语句iffor 1.URL与视图的映射 带参数的url&…

IIC总线简介

IIC总线 IIC总线是Philips公司在八十年代初推出的一种串行、半双工总线 主要用于近距离、低速的芯片之间的通信&#xff1b;IIC总线有两根双向的信号线一根数据线SDA用于收发数据&#xff0c;一根时钟线SCL用于通信双方时钟的同步&#xff1b;IIC总线硬件结构简单&#xff0c;成…

第9章 项目成本管理

文章目录 9.1.1 成本与成本管理概念 329项目成本管理的过程 9.1.2 相关术语 331成本的类型&#xff08;6种&#xff09;应急储备与管理储备 9.2.3 项目成本管理计划制订的 输出 3349.3.1 项目成本估算的主要相关因素 335项目估算还需要考虑但 容易被忽视的 主要因素 9.3.2 项目…

贪心 题目集

任务安排问题 某个系统中有一个设备&#xff0c;该设备每次只能分配给一个任务使用&#xff0c;且只有当任务结束后才能再分配给另一个任务使用。 假设系统启动时间计为时间0点&#xff0c;预先有一份任务计划表&#xff0c;预定了每个任务的开始时间点和持续时间。 要求设计算…

[大二下]手把手1小时下载Pandoc

老规矩先给各位友友们提供参考解决方法,再说为啥是怎么和这哥们结缘的~ 为了能更加详细,小卓又卸载了重装了一遍!!! 所以麻烦各位佬, 能给个赞, 谢谢各位佬了,坦诚的说,因为友友们免费的点赞收藏,却是我写下去的动力~ 第一步:进入官网(如果没有科学上网的可能比较慢, 如果真的…

腾讯云 Ubuntu Desktop 22.04 桌面版

安装 Ubuntu Server 22.04 安装 Ubuntu Server 22.04重置登陆密码&#xff0c; 默认用户名 ubuntu 添加用户 不建议直接使用默认用户&#xff0c; 添加用户&#xff08;demodeom&#xff09; sudo adduser demodeom将 demodeom 添加到 sudoer 文件 sudo visudo在文件末尾添…

2023五一赶制个人系统:基于SpringBoot+MyBatisPlus+Vue+ElementUI前后端分离

小钊记前言 &#x1f351;一、背景&#x1f351;二、调研准备阶段&#x1f34a;2.1、项目-自己搭建&#x1f353; 搭建步骤 &#x1f34a;2.2、项目需求-自己X造&#x1f34a;2.2、数据模型设计 &#x1f351;三、开发阶段&#x1f351;四、renxiaozhao 1.0.0-alpha发布&#x…

BPMN2.0 任务-服务任务

服务任务是任务的一种,工作由软件自动完成,比如一个Web服务或者一个自动化的应用。 服务任务用于调用服务。 在flowable中分为java服务任务,用于调用java类,web服务任务用于同步的调用外部的web服务。 在Camunda是通过调用java代码或者为外部执行者提供一个工作单元来完…

真题详解(ICMP)-软件设计(六十五)

真题详解&#xff08;对象&#xff09;-软件设计&#xff08;六十四)https://blog.csdn.net/ke1ying/article/details/130459425 程序的三种基本控制结构&#xff1a;顺序、选择和重复。 在网络系统中&#xff0c;通常吧_____置于DMZ区。 答案&#xff1a;Web服务器 解析&am…

STL常用梳理——VECTOR常用接口及其迭代器实现

Vector篇 Vector介绍Vector实现1、定义默认构造函数使用实现 2、迭代器Iterator迭代器使用 3、空间增长问题使用实现 迭代器迭代器介绍迭代器实现 Vector介绍 vector是STL中容器之一&#xff0c;特性如下&#xff1a; vector是表示可变大小数组的序列容器。就像数组一样&#…

【python入门篇】你好python

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; Python入门&#xff0c;本专栏主要内容为Python的基础语法&#xff0c;Python中的选择循环语句…

软件测试实战,Web测试详细总结 (覆盖所有测试点),你要的都有

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Web自动化测试&…

Python 将 PDF 转换为 Word

大家好&#xff0c;我是水滴~ 在平时的工作中&#xff0c;我们总会希望将需要的 PDF 文件转换为 Word 文件&#xff0c;而市面上很多工具都是收费的&#xff0c;这无疑增加了我们的成本。 所以&#xff0c;我使用 Python 编写了一个转换代码&#xff0c;可以 将 PDF 转换为 W…

从远程桌面客户端提取明文凭证的工具RdpThief

导语&#xff1a;在本文中&#xff0c;我将描述我编写的一个工具&#xff0c;能使用API钩子从Microsoft RDP客户端提取明文凭据&#xff0c;而且如果是在已经受感染用户的权限下操作&#xff08;比如网络钓鱼导致&#xff09;&#xff0c;并且该用户已打开RDP会话&#xff0c;则…

elasticsearch 使用 RestAPI 操作索引库

1.mysql与elasticsearch 我们统一的把mysql与elasticsearch的概念做一下对比&#xff1a; MySQLElasticsearch说明TableIndex索引(index)&#xff0c;就是文档的集合&#xff0c;类似数据库的表(table)RowDocument文档&#xff08;Document&#xff09;&#xff0c;就是一条条…

如何从0到1落地自动化测试?何为成熟模型?测试老鸟的总结...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 过去十年&#xf…

离散数学_九章:关系(5)

&#x1f6a9;9.5 等价关系 1、等价关系&#xff08;Equivalence Relations&#xff09;等价关系等价的元素&#x1f4d8;例1&#xff1a;模m同余 &#x1f4d8;例2&#xff1a;字符串 &#x1f4d8;例3&#xff1a;整除 2、等价类&#xff08;Equivalence Classes&#xff09…

DP动态规划

1.背包问题 1.1 0/1背包 1.1.1经典做法 def solve(N,C): # 从左到右&#xff0c;从上到下 &#xff08;先种类&#xff0c;再体积&#xff09;for i in range(1,N1): # N种物品&#xff0c;先1种&#xff0c;再2种......for j in range(0,C1): # 当前背包体积if c[i]>j :…