尝试对MoveIt2的轨迹进行插值控制舵机机械手

30 篇文章 35 订阅

1.现状分析

机械手在运动时,要尽可能平稳、少冲击,显得丝滑。
Moveit给到的轨迹,除了描述了各个关键时刻的各个关节的位置,还描述了此时的各个关节的速度、加速度。假如我们的执行机构可以完全按照这些位置、速度、加速度来进行操作,理论上就可以实现平滑的移动。
但是由于我们目前用的是舵机,除了位置可控外,速度、加速度都不能直接控制。
所以,只能通过插值来插补两个位置之间的各个小位置,让运动大概实现【加速-匀速-减速 】的过程。
舵机的转动速度会因为负载的不同而不同,不能够简单认为是一个固定值。因此,想要间接通过设置定位的方式来设定速度,可行性也不太。
假如我们让舵机从位置a走到位置b,等待时间为T1。舵机实际从a走到b的时间为T2。
那么只有T1大于等于T2才能确保舵机运动到位。

2.委曲求全

由于测算舵机实际的运算速度太麻烦了。
我们先进行固定时间步进的方式算了。
从ros上可以收到各个点位的信息,以及时间戳。因此可以根据时间戳,把位置均分一下。然后再发送给下位机。
实现的代码如下,仅供参考

void MainWindow::processGoal(std::shared_ptr<const FollowJointTrajectory::Goal> goal)
{
    // 该轨迹分成若干个点位(每个点位都包括了此点位下,若干关节的角度信息)
    int pointSize = goal->trajectory.points.size();
    if(pointSize <= 0)
    {
        return;
    }

    // 关于time_from_start,
    // 第一个点位的time_from_start为0,后面的每个时间都是与第一个位置时间做的偏移。
    // 直观地理解,该轨迹要求在各个时间点,机械手要在要求的位置
    // 我们先人为地规定,timeStep(ms)更新一次位置给下位机

    int timeStep = 50;         // 更新频率

    // 先不进行加速、匀速、减速的操作。现在直接均分。
    // 目前是按照时间来插值

    // 存放移动数据的队列
    static QQueue<QList<float>> angleQueue;
    angleQueue.clear();

    QList<float> angleList;
    for(int i = 0; i < pointSize; i++)
    {
        // 当前点位
        auto curPoint = goal->trajectory.points.at(i);

        if(i == 0) // 第一个是起始位置,直接放进去进行
        {
            angleList.clear();
            foreach(auto pos, curPoint.positions)
            {
                angleList << qRadiansToDegrees(pos);
            }

            angleQueue << angleList;

            continue;
        }

        auto lastPoint = goal->trajectory.points.at(i - 1);

        auto last_time = lastPoint.time_from_start;
        auto current_time = curPoint.time_from_start;

        rclcpp::Time time1(last_time.sec, last_time.nanosec);
        rclcpp::Time time2(current_time.sec, current_time.nanosec);
        auto duration_time = time2 - time1;

        // 从上一个点位跑到此处计划耗时
        qint64 duration_ms = duration_time.nanoseconds() / 1e6;

        qDebug() << "[sec:" << current_time.sec << ", nanosec:" << current_time.nanosec << "]" << duration_time.seconds() << duration_time.nanoseconds() ;
        qDebug() << "duration ms:" << duration_ms;

        if(duration_ms < timeStep) // 小于时间步进,无需插值
        {
            angleList.clear();
            foreach(auto pos, lastPoint.positions)
            {
                angleList << qRadiansToDegrees(pos);
            }

            angleQueue << angleList;
        }
        else // 需要插值
        {
            // 需要分几步进行插值
            float divCount = duration_ms / timeStep;
            if(duration_ms % timeStep)
            {
                divCount++;
            }

            // 插值步进
            QList<float> stepList;
            for(int idx = 0; idx < lastPoint.positions.size(); idx++)
            {
                stepList << (curPoint.positions[idx] - lastPoint.positions[idx]) / divCount;
            }

            // 均分插值
            for(int divIdx = 0; divIdx < divCount; divIdx++)
            {
                angleList.clear();
                for(int idx = 0; idx < lastPoint.positions.size(); idx++)
                {
                    angleList << qRadiansToDegrees(lastPoint.positions[idx] + stepList[idx] * (divIdx + 1));
                }

                angleQueue << angleList;
            }

        }

    }

    qDebug() << angleQueue;

    // 算出了整个移动队列,通过定时器定时发送该数据给单片机
    //(也可以把整个移动数据发送至单片机,然后单片机再在自己内部慢慢跑)
    QTimer *timer = new QTimer();
    timer->setInterval(timeStep);
    connect(timer, &QTimer::timeout, [=](){
        if(angleQueue.length() == 0)
        {
            timer->stop();
            timer->deleteLater();

            return;
        }
        QList<float> angleList = angleQueue.dequeue();

        // 转动方向修正(根据实际情况)
        angleList[0] = -angleList[0];
        angleList[1] = -angleList[1];
        angleList[3] = -angleList[3];

        sendPose(angleList);
    });
    timer->start();

}

3.实际效果

不好。还是晃得厉害,有时候甚至还不如原来的不插值的。下面视频的是用原来的没有插值的。
【Ros2中使用MoveIt进行虚拟避障】


参考资料
http://www.51hei.com/mcu/2548.html
https://www.elecfans.com/d/608940.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
是的,ROS MoveIt可以使用力反馈控制对机器人进行控制。 在ROS MoveIt中,可以使用MoveIt Simple Controller Manager(SCM)来实现力反馈控制。MoveIt SCM是一个ROS包,可以在MoveIt中使用,它提供了一个接口,使得可以轻松地将MoveIt与其他力反馈控制器集成。 具体来说,MoveIt SCM提供了两种类型的接口:PositionJointInterface和VelocityJointInterface。PositionJointInterface接口可以使用位置控制器,VelocityJointInterface接口可以使用速度控制器。这两种接口都支持力反馈控制,可以使用机器人的传感器数据来实现力反馈控制。 要使用MoveIt SCM进行力反馈控制,需要进行以下步骤: 1. 安装MoveIt SCM:可以使用以下命令在ROS中安装MoveIt SCM: ``` sudo apt-get install ros-<distro>-moveit-simple-controller-manager ``` 2. 创建MoveIt 控制器:可以使用MoveIt Setup Assistant来创建MoveIt 控制器。在创建控制器时,需要选择支持力反馈控制的接口。 3. 配置MoveIt 控制器:在ROS Launch文件中配置MoveIt 控制器,并将其与机器人的传感器数据连接起来。 4. 启动MoveIt 控制器:使用ROS Launch文件启动MoveIt 控制器,并开始使用力反馈控制对机器人进行控制。 需要注意的是,使用力反馈控制器需要机器人具有足够的传感器数据,以便能够正确地感知外界环境和机器人状态。此外,需要确保控制器的稳定性和安全性,以避免机器人损坏或造成伤害。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值