25/1/6 算法笔记<强化学习> 初玩V-REP

我们安装V-REP之后,使用的是下面Git克隆的项目。

git clone https://github.com/deep-reinforcement-learning_book/Chapter16-Robot-Learning-in-Simulation.git

项目中直接组装好了一个机械臂。

我们先来分析下它的对象树

DefaultCamera:摄像机,用于捕捉场景的视图

Dummy:虚拟对象,作为参照或者用于定位其他对象

target:抓住任务中的目标物体。机器人需要抓取的物体

Vision_sensor:视觉传感器,用于捕捉场景图像,通常用于视觉反馈或识别目标

diningTable:场景中的桌子,通常作为抓取任务的基础

Sawyer:机器人手臂,执行抓取任务

Sawyer_jointX:机器人手臂的关节,用于控制各个链接之间的运动

Sawyer_tip:机器人的末端执行器,用于抓取物体

BaxterGripper:夹具部分,抓取物体的执行器

BaxterGripper_attachPoint:夹具的附加点,链接夹具和机器人手臂

BaxterGripper_attachProxSensor:接近传感器,用于检测夹具是否接近目标物体

BaxterGripper_leftJoint和BaxterGripper_rightJoint:夹具的左右关节,控制夹具的打开和关闭

BaxterGripper_leftPad和BaxterGripper_rightPad:夹具的抓取垫,实际接触目标物体的部分

在V-REP中设置好环境之后,我们需要用PyRep软件包写一个定义环境中动力学过程和奖励函数的控制脚本。我们仓库提供了定义环境的代码,我们来看下代码。

导入库和模块

from os.path import dirname, join, abspath
from pyrep import PyRep   #用与物理仿真环境交互的库
from pyrep.robots.arms.sawyer import Sawyer #机器人手臂和夹具的类
from pyrep.robots.end_effectors.baxter_gripper import BaxterGripper #夹具的类
from pyrep.objects.proximity_sensor import ProximitySensor #用于检测物体的传感器类
from pyrep.objects.vision_sensor import VisionSensor
from pyrep.objects.shape import Shape #用于场景中的物体和虚拟目标
from pyrep.objects.dummy import Dummy
from pyrep.const import JointType, JointMode #常量类,用于定义关节类型和控制模式
import numpy as np
import matplotlib.pyplot as plt
import math

定义有效位置范围

POS_MIN, POS_MAX = [0.1, -0.3, 1.], [0.45, 0.3, 1.]  # valid position range of target object 

创建GraspEnv类

class GraspEnv(object):''' Sawyer robot grasping a cuboid '''

设置公共变量

self.headless = headless #设置可视化
self.reward_offset = 10.0  #成功抓取目标物体时的奖励值
self.reward_range = self.reward_offset#奖励范围,用于注册Gym环境
self.penalty_offset = 1.    #不良情况的惩罚值
self.fall_down_offset = 0.1 #判断目标物体是否掉落的距离阈值
self.metadata = []          #存储与Gym环境相关的元数据
self.control_mode = control_mode #设置控制模式

启动和设置场景

self.pr = PyRep()   #创建一个PyRep实例,用于与仿真环境交互
if control_mode == 'end_position':  #根据控制模式选择不同的场景文件SCENE_FILE = join(dirname(abspath(__file__)), './scenes/sawyer_reacher_rl_new_ik.ttt')
elif control_mode == 'joint_velocity':SCENE_FILE = join(dirname(abspath(__file__)), './scenes/sawyer_reacher_rl_new.ttt')
self.pr.launch(SCENE_FILE, headless=headless)
self.pr.start()

根据控制模式选择不同的场景文件,end_position 模式使用逆向运动学场景,而 joint_velocity 使用正向运动学场景。

获取机器人和夹具

self.agent = Sawyer() #为场景中Sawyer机器人手臂实例
self.gripper = BaxterGripper() #为场景中的Baxter Gripper夹具实例

设置传感器和物体

self.gripper_left_pad = Shape('BaxterGripper_leftPad')  #夹具的左垫,左侧接触面
self.proximity_sensor = ProximitySensor('BaxterGripper_attachProxSensor')#接近传感器
self.vision_sensor = VisionSensor('Vision_sensor') #视觉传感器
self.table  = Shape('diningTable') #桌子,在场景中用于碰撞检测的物体

控制模式设置

if control_mode == 'end_position': #根据控制模式启用或禁用控制循环。self.agent.set_control_loop_enabled(True) #根据控制模式定义动作空间的维度self.action_space = np.zeros(4)
elif control_mode == 'joint_velocity':self.agent.set_control_loop_enabled(False)self.action_space = np.zeros(7)
else:raise NotImplementedError

观察空间设置

self.observation_space = np.zeros(17)

包含7个关节的位置和速度以及目标的位置,总共17维。

锁定电机

self.agent.set_motor_locked_at_zero_velocity(True)

防止电机在初始化时移动。

获取目标和末端执行器

self.target = Shape('target') #目标物体
self.agent_ee_tip = self.agent.get_tip()#末端执行器
self.tip_target = Dummy('Sawyer_target')#目标点
self.tip_pos = self.agent_ee_tip.get_position()#获取末端执行器的当前位置

末端执行器(End Effector)是机器人或自动化系统中用于与环境进行交互的部件。它通常位于机器人手臂的末端,负责执行特定的任务,如抓取、搬运、切割、焊接等。

末端执行器的类型:夹具,吸盘,工具,手,喷嘴

设置初始姿态

if control_mode == 'end_position':  #设置末端执行器的初始位置和朝向initial_pos = [0.3, 0.1, 0.9]  #关节速度控制,设置各个关节的初始位置self.tip_target.set_position(initial_pos)self.tip_target.set_orientation([0, np.pi, np.pi/2], reset_dynamics=True)
elif control_mode == 'joint_velocity':self.initial_joint_positions = [0.001815199851989746, -1.4224984645843506, 0.704303503036499, 2.54307222366333, 2.972468852996826, -0.4989511966705322, 4.105560302734375]self.agent.set_joint_positions(self.initial_joint_positions)

记录初始位置

self.pr.step()   #更新仿真,进行一步仿真以更新状态
self.initial_tip_positions = self.agent_ee_tip.get_position()#获取末端执行器和目标物体的初始位置
self.initial_target_positions = self.target.get_position()

其他函数设置

_get_state:返回机器人的状态,包括关节位置,速度和目标位置
def _get_state(self):return np.array(self.agent.get_joint_positions()+self.agent.get_joint_velocities()+self.target.get_position())
_is_holding:检查夹具是否抓住物体
def _is_holding(self):pad_collide_object = self.gripper_left_pad.check_collision(self.target)#检查碰撞if pad_collide_object and self.proximity_sensor.is_detected(self.target)==True:return True  #检测目标else:return False
_move:根据给定的动作移动机器人末端执行器

函数_move可以在有效范围内通过反向运动学模式操控移动机械臂末端执行器,PuRep中可以谈股票在机械臂末端放置一个部件来实现以反向运动学控制末端执行器,具体做法是设置这个末端不见的位置和旋转角,如果调用pr.step()函数,你们在PyRep中机械臂关节的反向运动控制可以自动求解。由于单个较大步长的控制可能是不精确的,这里我们将整个动作产生的位移运动分解为一系列小步长运动,并采用一个有u自大迭代次数和最大容错值的反馈控制闭环来执行这些小步长动作。

def _move(self,action,bounding_offset=0.15,step_factor=0.2,max_itr=20,max_error=0.05,rotarion_norm=5.):pos=self.gripper.get_position()if pos[0]+action[0]>POS_MIN[0]-bounding_offset and pos[0]+action[0]<POS_MAX[0]+bounding_offset \and pos[1]+action[1]>POS_MIN[1]-bounding_offset and pos[1]+action[1]<POS_MAX[1]+2*bounding_offset \and pos[2]+action[2] > POS_MIN[2]-2*bounding_offset:  ori_z=-self.agent_ee_tip.get_orientation()[2] target_pos = np.array(self.agent_ee_tip.get_position())+np.array(action[:3])diff=1 itr=0while np.sum(np.abs(diff))>max_error and itr<max_itr:itr+=1cur_pos = self.agent_ee_tip.get_position()diff=target_pos-cur_pos  #计算当前和目标位置之间的差pos = cur_pos+step_factor*diff   #根据当前差值和步长因子计算新位置self.tip_target.set_position(pos.tolist())self.pr.step()     #每次设置目标位置后,调用仿真步骤以更新状态ori_z+=rotation_norm*action[3]  self.tip_target.set_orientation([0, np.pi, ori_z])  self.pr.step()else:print("Potential Movement Out of the Bounding Box!")pass 

这段代码首先获取夹具当前的位置,

然后检查移动是否在有效范围内,如果新位置超出边界,则不执行移动。

获取当前末端执行器的朝向,特别是 Z 轴的旋转角度,并进行反转(因为在设置时方向可能存在差异)。

计算目标位置并进行移动,并通过一个循环逐步移动末端执行器到目标位置。计算当前位置与目标位置之间的差值 diff,并根据步长因子更新当前位置。

更新末端执行器的朝向,

边界检测失败时的处理。

reinit:重新初始化环境
def reset(self,random_target = False):self.shutdown()   #关闭原环境self.__init__(self.headless)#重新初始化环境,确保环境处于一个干净的状态
reset:重置环境,设置目标位置
def reset(self, random_target=False):'''在一个立方体内获取随机位置并设置目标位置。'''# 设置目标物体if random_target:  # 随机化pos = list(np.random.uniform(POS_MIN, POS_MAX))  # 从有效范围内均匀抽样self.target.set_position(pos)  # 随机位置else:  # 非随机化self.target.set_position(self.initial_target_positions)  # 固定位置self.target.set_orientation([0,0,0])  # 设置目标物体的朝向为零self.pr.step()  # 进行一步仿真# 设置末端位置以进行初始化if self.control_mode == 'end_position':  # 关节模式为逆运动学self.agent.set_control_loop_enabled(True)  # 启用逆运动学模式self.tip_target.set_position(self.initial_tip_positions)  # 由于在逆运动学模式下不能直接设置关节位置,因此设置末端目标位置self.pr.step()  # 进行一步仿真# 防止卡住的情况。由于使用逆运动学进行移动,卡住可能导致逆运动学无法求解,因此在目标位置未达到时采取一些随机动作。itr = 0max_itr = 10while np.sum(np.abs(np.array(self.agent_ee_tip.get_position() - np.array(self.initial_tip_positions)))) > 0.1 and itr < max_itr:itr += 1self.step(np.random.uniform(-0.2, 0.2, 4))  # 采取随机动作以防止卡住self.pr.step()  # 进行一步仿真elif self.control_mode == 'joint_velocity':  # 关节模式为前向运动学self.agent.set_joint_positions(self.initial_joint_positions)  # 设置初始关节位置self.pr.step()  # 进行一步仿真# 设置可碰撞,以便进行碰撞检测self.gripper_left_pad.set_collidable(True)  # 设置夹具的左垫为可碰撞,以便检查碰撞self.target.set_collidable(True)  # 设置目标物体为可碰撞# 如果夹具没有完全打开,则打开夹具if np.sum(self.gripper.get_open_amount()) < 1.5:self.gripper.actuate(1, velocity=0.5)  # 以一定速度打开夹具self.pr.step()  # 进行一步仿真return self._get_state()  # 返回当前环境状态
step:根据动作更新环境状态,计算奖励和完成状态
def step(self, action):'''根据给定的动作移动机器人手臂。如果控制模式为 'joint_velocity',则动作是 7 维的关节速度值 + 1 维夹具的旋转值;如果控制模式为 'end_position',则动作是 3 维的末端(手臂末端)位置值 + 1 维夹具的旋转值。'''# 初始化done = False  # 表示回合是否结束reward = 0  # 奖励初始化hold_flag = False  # 是否抓住物体的标志if self.control_mode == 'end_position':if action is None or action.shape[0] != 4:  # 检查动作是否有效print('没有动作或动作维度错误!')action = list(np.random.uniform(-0.1, 0.1, 4))  # 生成随机动作self._move(action)  # 根据动作移动末端执行器elif self.control_mode == 'joint_velocity':if action is None or action.shape[0] != 7:  # 检查动作是否有效print('没有动作或动作维度错误!')action = list(np.random.uniform(-0.1, 0.1, 7))  # 生成随机动作self.agent.set_joint_target_velocities(action)  # 在手臂上执行动作self.pr.step()  # 进行一步仿真else:raise NotImplementedError  # 如果控制模式不支持,抛出异常ax, ay, az = self.gripper.get_position()  # 获取夹具的当前位置if math.isnan(ax):  # 捕捉夹具位置为 NaN 的情况print('夹具位置为 NaN。')self.reinit()  # 重新初始化环境done = True  # 标记为结束tx, ty, tz = self.target.get_position()  # 获取目标物体的位置offset = 0.08  # 增强奖励:目标位置在目标物体上方的偏移量sqr_distance = (ax - tx) ** 2 + (ay - ty) ** 2 + (az - (tz + offset)) ** 2  # 夹具与目标物体之间的平方距离# ''' 仅用于基于视觉的控制,时间消耗大! '''# current_vision = self.vision_sensor.capture_rgb()  # 使用视觉传感器捕捉视图的截图# plt.imshow(current_vision)  # 显示捕捉到的图像# plt.savefig('./img/vision.png')  # 保存图像# 如果夹具与物体足够接近,并且接近传感器检测到目标,则关闭夹具if sqr_distance < 0.1 and self.proximity_sensor.is_detected(self.target) == True:# 确保在抓取之前夹具是打开的self.gripper.actuate(1, velocity=0.5)  # 打开夹具self.pr.step()  # 进行一步仿真self.gripper.actuate(0, velocity=0.5)  # 关闭夹具,0 表示关闭,1 表示打开;速度 0.5 确保夹具在一帧内关闭self.pr.step()  # 进行一步仿真if self._is_holding():  # 检查是否抓住物体reward += self.reward_offset  # 抓取物体时的额外奖励done = True  # 标记为结束hold_flag = True  # 设置抓住物体的标志else:self.gripper.actuate(1, velocity=0.5)  # 如果没有抓住物体,确保夹具是打开的self.pr.step()  # 进行一步仿真elif np.sum(self.gripper.get_open_amount()) < 1.5:  # 如果夹具关闭(未完全打开),则打开夹具self.gripper.actuate(1, velocity=0.5)  # 打开夹具self.pr.step()  # 进行一步仿真else:pass  # 如果夹具状态正常,什么都不做# 基础奖励是与目标的负距离reward -= np.sqrt(sqr_distance)  # 根据夹具与目标的距离调整奖励# 检查物体是否掉落if tz < self.initial_target_positions[2] - self.fall_down_offset:  done = True  # 标记为结束reward = -self.reward_offset  # 物体掉落的惩罚奖励# 增强奖励:如果夹具的朝向与目标物体垂直,则抓取姿势更好desired_orientation = np.concatenate(([np.pi, 0], [self.target.get_orientation()[2]]))  # 夹具在 z 轴上垂直于目标并朝下rotation_penalty = -np.sum(np.abs(np.array(self.agent_ee_tip.get_orientation()) - desired_orientation))  # 计算朝向惩罚rotation_norm = 0.02  # 旋转惩罚的归一化因子reward += rotation_norm * rotation_penalty  # 将旋转惩罚添加到奖励中# 碰撞惩罚if self.gripper_left_pad.check_collision(self.table):  # 检查夹具是否与桌子碰撞reward -= self.penalty_offset  # 如果发生碰撞,减少奖励# print('惩罚与桌子的碰撞。')if math.isnan(reward):  # 捕捉数值问题的情况reward = 0.  # 如果奖励为 NaN,重置为 0return self._get_state(), reward, done, {'finished': hold_flag}  # 返回当前状态、奖励、是否结束和抓取标志
shutdown:关闭仿真
def shutdown(self):self.pr.stop()self.pr.shutdown()

主程序

if __name__ == '__main__':
#设置控制模式CONTROL_MODE='joint_velocity'  # 'end_position' or 'joint_velocity'env=GraspEnv(headless=False, control_mode=CONTROL_MODE) #初始化抓取环境for eps in range(30):env.reset() #每个回合的开始,重置环境for step in range(30):if CONTROL_MODE=='end_position': #根据控制模式生成动作action=np.random.uniform(-0.2,0.2,4)elif CONTROL_MODE=='joint_velocity':action=np.random.uniform(-2.,2.,7)else:raise NotImplementedErrortry: env.step(action)   #执行生成的动作并更新环境       except KeyboardInterrupt:print('Shut Down!')env.shutdown()env.shutdown()

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CODESYS MODBUS TCP通信(AM400PLC作为主站通信)

禾川Q1 PLC MODBUS-TCP通信 禾川Q1 PLC MODBUS-TCP通信(CODESYS平台完整配置+代码)-CSDN博客文章浏览阅读17次。MATLAB和S7-1200PLC水箱液位高度PID控制联合仿真(MODBUSTCP通信)_将matlab仿真导入plc-CSDN博客文章浏览阅读722次。本文详细介绍了如何使用MATLAB与S7-1200PLC进行…

OSPF - 影响OSPF邻居建立的因素

总结为这么10种 routerID 冲突区域id不一致认证MA网络掩码需一致区域类型(特殊区域)hello、dead时间MTU(如果开启检查)静默接口网络类型不匹配MA网络中路由器接口优先级全为0 如何建立邻居可以查看上一篇文章&#xff0c;可以直接专栏找&#xff08;&#x1f92b;挂链接会没流…

【大数据】(选修)实验4 安装熟悉HBase数据库并实践

实验4 安装熟悉HBase数据库并实践 1、实验目的 (1)理解HBase在Hadoop体系结构中的角色; (2)熟练使用HBase操作常用的Shell命令; (3)熟悉HBase操作常用的Java API。 2、实验平台 操作系统:Linux Hadoop版本:2.6.0或以上版本 HBase版本:1.1.2或以上版本 JDK版…

windeployqt.exe打包qt程序总结(MSVC)

文章目录 前言打包步骤问题 前言 打包环境&#xff1a;windows10VS2017QT5.12.12 参考&#xff1a;Qt 打包发布程序&#xff0c;解决找不到msvcp140.dll等动态库问题正确方案 打包步骤 运行Qt5.12.12&#xff08;MSVC 2017 64-bits&#xff09; 在开始软件菜单里找到Qt文件夹…

算法的学习笔记—不用常规控制语句求 1 到 n 的和

&#x1f600;前言 在算法编程中&#xff0c;有时我们会遇到一些特殊的限制条件&#xff0c;这些限制会迫使我们跳出常规思维。本文讨论的问题就是一个典型案例&#xff1a;在不能使用基本控制语句的情况下&#xff0c;如何求解 1 到 n 的和。这个问题不仅考验编程技巧&#xf…

计算机网络 (27)IP多播

前言 IP多播&#xff08;也称多址广播或组播&#xff09;技术是一种允许一台或多台主机&#xff08;多播源&#xff09;发送单一数据包到多台主机&#xff08;一次性的、同时的&#xff09;的TCP/IP网络技术。 一、基本概念 定义&#xff1a;多播作为一点对多点的通信&#xff…

CSS 学习之正确看待 CSS 世界里的 margin 合并

一、什么是 margin 合并 块级元素的上外边距(margin-top)与下外边距(margin-bottom)有时会合并为单个外边距&#xff0c;这样的现象称为“margin 合并”。从此定义上&#xff0c;我们可以捕获两点重要的信息。 块级元素&#xff0c;但不包括浮动和绝对定位元素&#xff0c;尽…

小程序组件 —— 28 组件案例 - 推荐商品区域 - 实现结构样式

这一节目标是实现底部推荐商品的结构和样式&#xff0c;由于这里要求横向滚动&#xff0c;所以需要使用上节介绍的 scroll-view 功能&#xff0c;并使用 scroll-x 属性支持横向滚动&#xff0c;推荐商品区域中的每一个商品是一个单独的 view&#xff0c;每个view 中需要写三个组…

单片机-LED点阵实验

要将第一个点点亮&#xff0c;则 1 脚接高电平 a 脚接低电平&#xff0c;则第一个点就亮了&#xff1b;如果要将第一行点亮&#xff0c;则第 1 脚要接高电平&#xff0c;而&#xff08;a、b、c、d、e、f、g、h &#xff09;这些引脚接低电平&#xff0c;那么第一行就会点亮&…

软件项目体系建设文档,项目开发实施运维,审计,安全体系建设,验收交付,售前资料(word原件)

软件系统实施标准化流程设计至关重要&#xff0c;因为它能确保开发、测试、部署及维护等各阶段高效有序进行。标准化流程能减少人为错误&#xff0c;提升代码质量和系统稳定性。同时&#xff0c;它促进了团队成员间的沟通与协作&#xff0c;确保项目按时交付。此外&#xff0c;…

Java基础 注解

分类 Java自带的标准注解&#xff0c;包括Override、Deprecated和SuppressWarnings&#xff0c;分别用于标明重写某个方法、标明某个类或方法过时、标明要忽略的警告&#xff0c;用这些注解标明后编译器就会进行检查。元注解&#xff0c;元注解是用于定义注解的注解&#xff0…

Linux中rsync命令使用

一、rsync简介 rsync 是一种高效的文件复制和同步工具&#xff0c;常用于在本地或远程计算机之间同步文件和目录 主要特性增量同步&#xff1a;rsync 会检测源和目标文件之间的差异&#xff0c;只传输发生变化的部分&#xff0c;而不是重新传输整个文件。这样就能有效减少数据…

基于STM32的自动水满报警系统设计

目录 引言系统设计 硬件设计软件设计系统功能模块 水位检测模块报警模块自动控制模块控制算法 水位检测逻辑报警触发逻辑代码实现 水位检测模块报警控制模块自动控制逻辑系统调试与优化结论与展望 1. 引言 水满报警系统在家庭、农业、工业等领域广泛应用&#xff0c;通过实时…

【Java数据结构】二叉树

1.树型结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;由n个结点组成的具有层次关系的集合。下面是它的特点&#xff1a; 根结点是没有前驱的结点&#xff08;没有父结点的结点&#xff09;子结点之间互不相交除了根结点外&#xff0c;其它结点都只有一个父结点n个结…

学习threejs,导入AWD格式的模型

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.AWDLoader AWD模型加…

Chapter4.3:Implementing a feed forward network with GELU activations

4 Implementing a GPT model from Scratch To Generate Text 4.3 Implementing a feed forward network with GELU activations 本节即将实现子模块&#xff0c;用于transformer block&#xff08;变换器块&#xff09;的一部分。为此&#xff0c;我们需要从激活函数开始。 深…

弥散张量分析开源软件 DSI Studio 简体中文汉化版可以下载了

网址&#xff1a; (63条消息) DSIStudio简体中文汉化版(2022年7月)-算法与数据结构文档类资源-CSDN文库

【信号滤波 (补充)】二阶陷波滤波代码推导过程(C++)

目录 二阶陷波滤波器计算实例一、 传递函数的参数推导1. 首先 b 0 , b 1 , b 2 b_0, b_1, b_2 b0​,b1​,b2​是怎么推导出来的&#xff1f;2. 带入实际值求解3. 验证上述的传递函数 二、将传递函数转化成差分方程2.1 传递函数写成输入输出形式2.2 Z域转化为时域 三、将差分方程…

C++进阶——用Hash封装unordered_map和unordered_set

目录 前言 源码怎么说 为什么要兼容&#xff1f; 兼容的具体做法&#xff1f; 为什么要把Key转为整数&#xff08;HashFcn&#xff09;&#xff1f; 模拟实现 一、建立框架 二、迭代器 运算符重载 迭代器兼容大法 三、[ ]重载 四、实现不能修改key 实现及测试代码 …

安装MySQL的五种方法(Linux系统和Windows系统)

一.在Linux系统中安装MySQL 第一种方法:在线YUM仓库 首先打开MySQL官网首页 www.mysql.com 找到【DOWNLOADS】选项&#xff0c;点击 下拉&#xff0c;找到 【MySQL Community(GPL) Downloads】 在社区版下载页面中&#xff0c;【 MySQL Yum Repository 】链接为在线仓库安装…