UnityVR--机械臂场景12-简单流水线应用4

本文介绍了如何在Unity3D环境中实现机械臂的手爪控制、红外线传感器以及工件生成器的功能。手爪控制包括抓取和释放工件的逻辑,传感器用于检测工件并触发机械臂抓取,工件生成器则周期性地在传送带上放置工件。这些组件共同构建了一个简单的自动化生产线模拟。
摘要由CSDN通过智能技术生成

目录

一. 手爪

二. 红外线传感器

三. 工件生成器

四. 总结


  上一篇已经实现了机械臂各种动作的控制,本篇实现一下其余的组成部分,比如手爪、传感器和自动放置工件等。

一. 手爪

  手爪的模型调整就不多说了,需要设置的是Rigidbody、Collider,还需要判断手爪开合的方向和距离等, 详见机械臂场景3-手爪一文。

  实现的主要功能有:

  1. 当手爪上的碰撞器触发时,将工件设为手爪的子物体,跟随手爪一起移动;

  2. 当手爪打开时,将工件的父物体设置为空,并且发送给机械臂回零事件;

  这里直接放一下手爪的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Robot_ClawCtrl : MonoBehaviour
{
    public Transform finger1, finger2;//两个手指
    float MoveDis, OpenDis = 0.1f, CloseDis = 0.02f, curDir;
    //需要移动的距离,打开时的距离,闭合时的距离,当前距离
    public bool isHold = false; //是否抓到物体
    public Transform ClawTarget = null;  //手爪抓到的目标

    void Start()
    {
        EventManager.Instance.AddEvent(EventType.OnClawCtrl,this, OnClawControl);
    }
    public void OnClawControl(EventDataBase data)
    {
        EventDataClaw eventData = data as EventDataClaw;
        EClawType clawType = eventData.clawType;
        Transform target = eventData.target;
        float settime = eventData.waitTime;

        if(clawType==EClawType.Close)
           OnCloseClaw();    //如果闭合的时间有误,可以添加一个定时器

        if (clawType == EClawType.Open)  //添加了定时器的打开命令
        {
            if (timer <= settime)
                timer += Time.deltaTime;
            else
            {
                OnOpenClaw();
                timer = 0;
                return;
            }
        }
    }

    public void OnOpenClaw()
    {//打开手爪
        MoveDis = OpenDis;
        finger1.localPosition = new Vector3(0, 0, -OpenDis);
        finger2.localPosition = new Vector3(0, 0, OpenDis);
        if(ClawTarget!=null||isHold)
        {
            ClawTarget.transform.GetComponent<Rigidbody>().isKinematic = false;
            ClawTarget.transform.SetParent(null);
            isHold = false;
            //发送回零事件
            EventManager.Instance.SendEvent(EventType.OnArmCtrl, new EventDataArm
            {
                armType = EArmMoveType.Home,
                clawType = EClawType.Close,
                target = null,
                waitTime = 0
            });
            ClawTarget = null;
        }
    }

    public void OnCloseClaw()
    {//关闭手爪
        MoveDis = CloseDis;
        finger1.localPosition = new Vector3(0, 0, MoveDis);
        finger2.localPosition = new Vector3(0, 0, -MoveDis);
    }
    private void OnTriggerStay(Collider other)
    {
        ClawTarget = other.transform;
        //如果判断物体是工件
        //这里设置的是layer,判断tag也是可以的
        if (ClawTarget.gameObject.layer == LayerMask.NameToLayer("Load")&& ClawTarget!= null)
        {
            ClawTarget.transform.SetParent(transform);
            ClawTarget.transform.GetComponent<Rigidbody>().isKinematic = true;
            isHold = true;
            EventManager.Instance.SendEvent(EventType.OnArmCtrl, new EventDataArm 
            { armType = EArmMoveType.Put,target=ClawTarget,clawType=EClawType.Close,waitTime=0.1f});
        }
        else return;
    }

  可以将手爪的脚本挂在手爪节点上,和它的刚体放在一起。需要指明两个移动的手指,IsHold和ClawTarget两个参数不需要赋初值,仅用于调试时参看。

二. 红外线传感器

  当有工件经过传感器时发送事件,通知传送带停止和机械臂抓取,可以参照激光门伤害文中的射线检测,其他检测方式也很多。

  1. 建立两个立柱RayEmitter和RayReciever,用于指明发射和接收射线的位置。在这两个节点下再设置两个空节点point1和point2,作为真正的发射和接收位置;

   2. 传感器代码,其中最重要的API是物理系统中的射线检测LineCast。代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//传感器
public class RaySensor : MonoBehaviour
{
    public Transform emitter;
    public Transform receiver;
    void Start()
    {//使用工具包中的划线工具,画一条线段代表红外线
        Tools.DrawLine(transform, emitter.position, receiver.position, Color.cyan);
    }

    void FixedUpdate()
    {
        Physics.Linecast(emitter.position, receiver.position, out RaycastHit hit, 64);//64是Layer号
        if (hit.collider != null)
        {//当检测到工件时,发送传送带停止事件
            EventManager.Instance.SendEvent(EventType.OnConveyerCtrl, new EventDataConveyer
            {
                conveyerType = EConveyerType.Stop  //通知传送带停止
            });
            EventManager.Instance.SendEvent(EventType.OnArmCtrl, new EventDataArm
            {//发送机械臂抓取事件
                armType = EArmMoveType.Get,
                target = hit.transform,    //传输给机械臂抓取命令和目标
                clawType=EClawType.Close,  //发送手爪闭合的数据
                waitTime=0.2f  
            });
        }
        else
        {
            EventManager.Instance.SendEvent(EventType.OnConveyerCtrl, new EventDataConveyer
            {//传送带移动
                conveyerType = EConveyerType.Move
            });
        }
    }
}

三. 工件生成器

  它的作用是源源不断地将工件放在传送带上,使用在ResourceManager--资源管理中写的资源管理工具Resload.cs,将放置在Assets->Recources->BeltLoaders文件夹下的工件生成到传送带上去

   1. 场景中的设置:随便放置一个模型,作为生成器。重点是放置一个空节点(粉色的),所有工件都是从这个空节点中生成出来的。

   2. 工件生成器的代码LoadersManager:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

public class LoadersManager : MonoBehaviour
{//Dispenser管理器
 //挂在控制节点上,管理所有生成的传送带负载工件
    public GameObject[] loaders;  //所有的负载工件放入数组
    public float passedTime=0, loaderRate=10; //计时器和间隔放负载的时间
    public bool ifLoad = true;    //是否可以发放工件的标记

    void Update()
    {
        passedTime+= Time.deltaTime;
        if (loaders.Length>0 && passedTime>=loaderRate&&ifLoad)
        {//当数组中有工件物体&时间到&红外线发送信号
            GameObject loader =loaders[Random.Range(0,loaders.Length)]; //随机加载一个工件
            if (loader == null)
                Debug.Log("没有找到物体");
            else
            {
                var go=GameObject.Instantiate(loader); //实例化物体
                go.transform.SetParent(transform);
                go.transform.localPosition = Vector3.zero;
                go.SetActive(true);
                go.AddComponent<Loaders>(); //生成的每一个工件都要挂上Loaders脚本
                passedTime = 0;
            }
        }  
    }
}

  3. 工件的脚本:上面的生成器在每生成一个工件时,除了设置工件的初始位置、父节点外,还要给每一个工件挂上Loaders.cs脚本,脚本中需要给工件加上刚体和碰撞体,代码如下:

public class Loaders : MonoBehaviour
{//挂在每一个被抓取工件上
    private Rigidbody rig;
    void Start()
    {
        rig = gameObject.AddComponent<Rigidbody>();
        rig.useGravity = true;
        gameObject.GetComponent<MeshCollider>().convex = true;
        gameObject.layer = LayerMask.NameToLayer("Load");
    }

  4. 最终效果:

四. 总结

  至此,传送带的场景搭建完毕,这只是一个简单的示例,很多情况都作为最简模型处理,并且在调试过程中还有累计误差和节拍误差等问题仍待解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值