ardupilot-3.6.10——航点导航WPNav之样条曲线(Spline Navigation)

参考:慕离巷《ArduCopter——ArduPilot——航点导航WPNav(二)——Spline Navigation》三石の四夕《三次Hermite插值》zhangyue_lala《一些插值法及理解》

目录

前言

核心算法

软件仿真 

源点、目标点速度选取及飞行中的速度控制

结束语


 

前言

    样条曲线,是一种曲线。所谓样条本来是工程设计中使用的一种绘图工具,它是富有弹性的细木条或细金属条。绘图员利用它把一些已知点连接成一条光滑曲线(样条曲线),并使连接点处有连续的曲率。

核心算法

    ardupilot样条曲线导航的核心算法为两点三次埃尔米特(hermite)插值算法。插值法应该是数值分析中讲的内容,大致意思就是,给定N个点的坐标,可以得到一个N+1阶多项式,这个多项式过给定的每个点。实际上就是通过离散(有限个)数据,估计得到一个表示这些数据分布规律的函数。也就是通过多项式来给定函数,一般来说给的点越多,多项式的阶数越高,拟合越准确。但有时也会出现龙格现象。埃尔米特插值就是其中的一种插值方法。

不少实际的插值问题不但要求在节点上的函数值相等,而且还要求对应的导数值也相等,甚至要求高阶导数也相等,满足这种要求的插值多项式就是埃尔米特插值多项式。                                                                                      ——来自百度百科

    插值是要拟合一个函数。但在样条曲线导航里,实际上没有给定的函数。样条曲线导航是利用埃尔米特插值多项式的导数是连续的这一特点,用到多旋翼上,就是轨迹是曲线,速度是连续变化的(位置的导数是速度),这样多旋翼不会有剧烈的姿态变化,飞行比较顺滑。

    埃尔米特插值算法的公式推导我就不再这儿列举了,我认为工科对于这些理论要先知道是什么,怎么用,具体是怎么来的可以在熟悉了之后再去了解,一上来就粘贴些理论推导,容易看得一头雾水,也丧失了看下去的信心。

    两点三次埃尔米特(hermite)插值算法,给定两点坐标和两点处导数,可以得到一个3阶多项式。

p = p0*(2*t^3-3*t^2+1) + v0*(t^3-2*t^2+t) + p1*(-2*t^3+3*t^2) + v1*(t^3-t^2)

     这个函数p就是样条曲线导航的轨迹方程。其中p0为源点坐标,m0为源点速度,p1为目标点坐标,m1为目标点速度。假设t等于0时多旋翼在源点开始向目标点移动,t等于1时,到达目标点。令y0等于p0,y1等于p1,m0等于v0,m1等于v1,x等于t,x0等于0,x1等于1,代入下面公式,化简后得到上式。

    轨迹函数得到后,如何确定两点坐标及其导数是关键。尤其是导数的确定,和你的第一想法会有很大的不同。 

软件仿真 

    通过ardupilot软件仿真,规划含有样条曲线的航线,飞行轨迹如下。 其中航点4、6、8、11、13为样条曲线航点。其他航点为正常航点,悬停时间设置为0。9点到11点之间的最大飞行速度设置为1m/s。

    通过打印调试信息,找到航点9、11的坐标位置(以飞机home点为原点)依次为[14.28151;-36.7041]、[12.1338;-48.3227]。速度标量按照1m/s,矢量为[0.991302;-0.131600923]、[-0.992780826;0.11994262]。得到matlab仿真图如下

    发现和ardupilot软件仿真轨迹严重不一致。 通过打印调试信息发现,源点和目标点的速度并不是设置的最大速度,再次使用matlab仿真后,发现这次结果相同。

    通过上图发现,matab仿真出的速度标量在10~40m/s区间内,加速度在20~150m/s^2区间内,这明显和ardupilot软件仿真是冲突的。由此可以发现ardupilot样条曲线算法对速度的选取,轨迹跟踪过程中速度的控制,是有自己的逻辑的,依我个人的观点来看,这就是理论和工程实践的良好结合,不得不佩服ardupilot的那些核心维护人员是真厉害。

    仔细想想,不难看出,matlab仿真出的速度、加速度这么大的前提是,多旋翼飞行器用1秒钟的时间,飞完两点三次埃尔米特(hermite)插值算法生成的轨迹。通过ardupilot软件仿真发现,实际情况并不是这样。也就是说,ardupilot利用源点、目标点速度和1秒钟完成轨迹的这个假设生成轨迹方程,然后按照一种方法控制飞行速度,实现轨迹平滑的飞行。

    matlab源码如下

function Hermite_apm(N,p0,v0,p1,v1)
% 程序使用两点三次埃尔米特插值
% N代表节点个数,数组形式
% p0----origin
% m0----origin_vel
% p1----dest
% m1----dest_vel


syms t;
p = p0*(2*t^3-3*t^2+1) + v0*(t^3-2*t^2+t) + p1*(-2*t^3+3*t^2) + v1*(t^3-t^2);
v = diff(p);
a = diff(p,2);

p_m = [];
v_m = [];
a_m = [];

t1=linspace(0,1,N);%插值节点的确认

    for j=1:N
        sp = subs(p,t,t1(j));
        sv = subs(v,t,t1(j));
        sa = subs(a,t,t1(j));
        
        p_m = [p_m sp];
        v_m = [v_m sv];
        a_m = [a_m sa];
        
        %drawnow;
        pause(0.02);
        
        hold on;
        subplot(2,2,1);
        plot(sp(2,1),sp(1,1),'o')
        axis equal
        ylabel('north(m)')
        xlabel('east(m)')
        title('水平位置')
        
        hold on;
        subplot(2,2,2);
        plot(sv(2,1),sv(1,1),'o')
        axis equal
        ylabel('north(m)')
        xlabel('east(m)')
        title('速度矢量')
        
        hold on;
        subplot(2,2,3);
        plot(t1(j),norm(sv),'o')
        %axis equal
        ylabel('speed(m/s)')
        xlabel('time(s)')
        title('速度标量')
        
        hold on;
        subplot(2,2,4);
        plot(t1(j),norm(sa),'o')
        %axis equal
        ylabel('Acceleration(m/s^2)')
        xlabel('time(s)')
        title('加速度标量')
    end
    x = p_m(1,:);
    y = p_m(2,:);
    
    n = v_m(1,:);
    m = v_m(2,:);
    
    subplot(2,2,1);
    plot(y,x);%绘图
    axis equal
end

    将上述源码保存为 Hermite_apm.m文件,然后添加到搜索路径,在命令行窗口输入

Hermite_apm(100,[14.28151;-36.7041],[35.6694;-4.73531],[12.1338;-48.3227],[-11.1978;1.35286])

可以看到上述仿真结果。 

源点、目标点速度选取及飞行中的速度控制

    先说结论,源点、目标点速度选取和航线长度有关,也和段类型和样条线段结束类型有关。AC_WPNav中有一个关于段类型的标志,表明这个段是直线或者曲线。

// segment types, either straight or spine
    enum SegmentType {
        SEGMENT_STRAIGHT = 0,
        SEGMENT_SPLINE = 1
    };

    还有一个标志来表明样条线段结束类型,及样条曲线这个点是最后一个点,或者这个点之后的端是直线或曲线。

// spline segment end types enum
    enum spline_segment_end_type {
        SEGMENT_END_STOP = 0,
        SEGMENT_END_STRAIGHT,
        SEGMENT_END_SPLINE
    };

    以下图为例

 段2-3的段类型为直线(SEGMENT_STRAIGHT),段3-4的段类型为样条曲线(SEGMENT_SPLINE),段4-5为直线。点4为样条曲线航点,它之后的点5为普通航点,所以点4的样条线段结束类型为直线(SEGMENT_END_STRAIGHT)。

    段类型的判断比较简单,普通航点(MAV_CMD_NAV_WAYPOINT) 就是直线类型,样条曲线(MAV_CMD_NAV_SPLINE_WAYPOINT)就是样条曲线类型。样条线段结束类型的判断依赖于下一个航点的类型,如果下一个航点是普通航点,就是直线类型(SEGMENT_END_STRAIGHT),如果下一个航点是样条曲线,就是样条曲线类型(SEGMENT_END_SPLINE),如果下一个航点不存在,就是停止类型(SEGMENT_END_STOP)。

    源点速度判断条件:

    1.如果样条曲线为第一个航点或运行AC_WPNav库的第一个航点或运行还没有到达目标点(例如在飞行下一个目标点之前激活样条曲线航点为目标点),使用(目标点-源点)*0.0025作为源点的速度矢量。代码在函数set_spline_origin_and_destination中,下面是代码片段

bool prev_segment_exists = (_flags.reached_destination && ((AP_HAL::millis() - _wp_last_update) < 1000));

// calculate spline velocity at origin
    if (stopped_at_start || !prev_segment_exists) {
    	// if vehicle is stopped at the origin, set origin velocity to 0.02 * distance vector from origin to destination
    	_spline_origin_vel = (destination - origin) * dt;
    	_spline_time = 0.0f;
    	_spline_vel_scaler = 0.0f;
    }

    2.如果上一段是直线,源点速度为上一段的(目标点-源点)

// look at previous segment to determine velocity at origin
        if (_flags.segment_type == SEGMENT_STRAIGHT) {
            // previous segment is straight, vehicle is moving so vehicle should fly straight through the origin
            // before beginning it's spline path to the next waypoint. Note: we are using the previous segment's origin and destination
            _spline_origin_vel = (_destination - _origin);
            _spline_time = 0.0f;	// To-Do: this should be set based on how much overrun there was from straight segment?
            _spline_vel_scaler = _pos_control.get_vel_target().length();    // start velocity target from current target velocity
        }

    3.如果上一段是样条曲线,则以上一段的目标点速度作为这一段的源点速度。

// look at previous segment to determine velocity at origin
        if (_flags.segment_type == SEGMENT_STRAIGHT) {
            // previous segment is straight, vehicle is moving so vehicle should fly straight through the origin
            // before beginning it's spline path to the next waypoint. Note: we are using the previous segment's origin and destination
            _spline_origin_vel = (_destination - _origin);
            _spline_time = 0.0f;	// To-Do: this should be set based on how much overrun there was from straight segment?
            _spline_vel_scaler = _pos_control.get_vel_target().length();    // start velocity target from current target velocity
        }else{
            // previous segment is splined, vehicle will fly through origin
            // we can use the previous segment's destination velocity as this segment's origin velocity
            // Note: previous segment will leave destination velocity parallel to position difference vector
            //       from previous segment's origin to this segment's destination)
            _spline_origin_vel = _spline_destination_vel;
            if (_spline_time > 1.0f && _spline_time < 1.1f) {    // To-Do: remove hard coded 1.1f
                _spline_time -= 1.0f;
            }else{
                _spline_time = 0.0f;
            }
            // Note: we leave _spline_vel_scaler as it was from end of previous segment
        }

    目标点速度判断条件 :

    1.如果样条线段结束类型为SEGMENT_END_STOP,则目标点速度为(目标点-源点)*0.0025。

case SEGMENT_END_STOP:
        // if vehicle stops at the destination set destination velocity to 0.02 * distance vector from origin to destination
        _spline_destination_vel = (destination - origin) * dt;
        _flags.fast_waypoint = false;
        break;

    2.如果样条线段结束类型为SEGMENT_END_STRAIGHT,则目标点速度为(下一个航点-目标点)。

case SEGMENT_END_STRAIGHT:
        // if next segment is straight, vehicle's final velocity should face along the next segment's position
        _spline_destination_vel = (next_destination - destination);
        _flags.fast_waypoint = true;
        break;

    3.如果样条线段结束类型为SEGMENT_END_SPLINE,则目标点速度为(下一个航点-源点)。

case SEGMENT_END_SPLINE:
        // if next segment is splined, vehicle's final velocity should face parallel to the line from the origin to the next destination
        _spline_destination_vel = (next_destination - origin);
        _flags.fast_waypoint = true;
        break;

    速度选择好后,把源点、目标点速度加起来和(目标点-源点)*4做比较,然后缩放相应的比例,变成最终轨迹方程中的源点、目标点速度。

// code below ensures we don't get too much overshoot when the next segment is short
    float vel_len = _spline_origin_vel.length() + _spline_destination_vel.length();
    float pos_len = (destination - origin).length() * 4.0f;
    if (vel_len > pos_len) {
        // if total start+stop velocity is more than twice position difference
        // use a scaled down start and stop velocityscale the  start and stop velocities down
        float vel_scaling = pos_len / vel_len;
        // update spline calculator
        update_spline_solution(origin, destination, _spline_origin_vel * vel_scaling, _spline_destination_vel * vel_scaling);
    }else{
        // update spline calculator
        update_spline_solution(origin, destination, _spline_origin_vel, _spline_destination_vel);
    }

    飞行中的速度控制:

    在函数advance_spline_target_along_track(float dt)中进行轨迹跟踪,飞行速度、位置都在这个函数控制中。

    下面函数计算3次多项式各个项的系数

/// update_spline_solution - recalculates hermite_spline_solution grid
///		relies on _spline_origin_vel, _spline_destination_vel and _origin and _destination
void AC_WPNav::update_spline_solution(const Vector3f& origin, const Vector3f& dest, const Vector3f& origin_vel, const Vector3f& dest_vel)
{
    _hermite_spline_solution[0] = origin;
    _hermite_spline_solution[1] = origin_vel;
    _hermite_spline_solution[2] = -origin*3.0f -origin_vel*2.0f + dest*3.0f - dest_vel;
    _hermite_spline_solution[3] = origin*2.0f + origin_vel -dest*2.0f + dest_vel;
 }

    下面函数把时间变量t代入轨迹方程计算目标位置和速度(位置的微分是速度)

// calc_spline_pos_vel_accel - calculates target position, velocity and acceleration for the given "spline_time"
/// 	relies on update_spline_solution being called when the segment's origin and destination were set
void AC_WPNav::calc_spline_pos_vel(float spline_time, Vector3f& position, Vector3f& velocity)
{
    float spline_time_sqrd = spline_time * spline_time;
    float spline_time_cubed = spline_time_sqrd * spline_time;

    position = _hermite_spline_solution[0] + \
               _hermite_spline_solution[1] * spline_time + \
               _hermite_spline_solution[2] * spline_time_sqrd + \
               _hermite_spline_solution[3] * spline_time_cubed;

    velocity = _hermite_spline_solution[1] + \
               _hermite_spline_solution[2] * 2.0f * spline_time + \
               _hermite_spline_solution[3] * 3.0f * spline_time_sqrd;
}

    上面两个函数所做的计算,和一开头给出的公式是一模一样的。

p = p0*(2*t^3-3*t^2+1) + v0*(t^3-2*t^2+t) + p1*(-2*t^3+3*t^2) + v1*(t^3-t^2) 

    如果严格按照时间假设t\in [0,1] ,飞行所需要的速度、加速度是相当大的。所以apm做了十分聪明的速度限制,用时间来显示速度,及通过时间控制目标点位置,从而达到控制速度的目的

// advance spline time to next step
_spline_time += _spline_time_scale*dt;

    _spline_time就是刚才所说的时间t ,运行频率400Hz,时间间隔(上述代码中的dt)0.0025,如果_spline_time_scale是1,飞行情况就会像是matlab仿真中的那样,但那个结果显然已经超出了飞行器的能力,所以apm通过控制_spline_time_scale,来实现限速。

    _spline_time_scale(时间比例) = 飞行的最大速度/_spline_time时刻通过公式算出的速度。

    不得不佩服这个设计真是十分的巧妙。下面附上速度控制的主要程序片段,完整程序请自行下载apm源代码。

// update target position and velocity from spline calculator
calc_spline_pos_vel(_spline_time, target_pos, target_vel);

// if within the stopping distance from destination, set target velocity to sqrt of distance * 2 * acceleration
if (!_flags.fast_waypoint && spline_dist_to_wp < _slow_down_dist) {
    _spline_vel_scaler = safe_sqrt(spline_dist_to_wp * 2.0f * _wp_accel_cmss);
}else if(_spline_vel_scaler < vel_limit) {
    // increase velocity using acceleration
    _spline_vel_scaler += _wp_accel_cmss * dt;
}

// constrain target velocity
_spline_vel_scaler = constrain_float(_spline_vel_scaler, 0.0f, vel_limit);

// scale the spline_time by the velocity we've calculated vs the velocity that came out of the spline calculator
_spline_time_scale = _spline_vel_scaler / target_vel_length;

结束语

    感谢您耐心的阅读。

    生命不息,学习不止。唯有前进!前进!前进!

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
专题综述 课程名称 工业自动化专题 题目名称 工业机器人的运动轨迹 学生学院____ _ 自动化________ 专业班级___ _ _ 学 号 学生姓名___ _ _ 指导教师_____ _____ 2021 年 6月 27日 工业机器 的运动轨迹全文共6页,当前为第1页。 工业机器 的运动轨迹全文共6页,当前为第1页。 工业机器人的运动轨迹综述 【摘要】:随着知识经济时代的到来,高技术已成为世界各国争夺的焦点,机器人技术作为高技术的一个重要分支普遍受到了各国政府的重视。自此,多种不同的研究方向都在工业机器人实时高精度的途径跟踪来实现预期目的。而工业机器人的运动轨迹又是重中之重,在得到反响信息之后,如何作出应答,并且实时检查轨迹与所计算出的轨迹是否吻合,为此也要进展追踪与动作修正。 【关键词】:工业机器人,视觉,途径跟踪,轨迹规划,高精度 1.机器人视觉,运动前的准备 实际的工业现场环境复杂,多种因素都有可能导致系统在运行过程中产生一定的偏向、 测量精度降低,引起误差的原因主要有温度漂移和关节松动变形等,使测量模型的参数值改变从而导致定位误差增大,因此需要定期对工业机器人视觉测量系统进展准确的校准,从而实现准确定位和视觉测量。更少不得必要的优化。 基于单目视觉的工业机器人运动轨迹准确度检测 建立的工业机器人单目视觉系统,整个系统主要由单目视觉单元,监控单元和机器人执行单元三大单元组成。单目视觉单元为一台固定在机器人上方的CCD摄像机,负责摄取工作环境中的目的并存入图像采集卡缓冲区;监控单元负责监控各工作站的当前状态,并完成对存储图像进展相关处理的工作,到达识别定位目的的目的;执行单元负责驱动机械手施行抓取操作。 基于双目视觉的工业机器人运动轨迹准确度检测 以立体视觉理论为根底,研究了基于空间直线的二维投影面方程。根据投影面的空间解析几何约束关系,建立基于直线特征匹配的双目视觉误差测量的数学模型。在该模型根底上采用将两台摄像机固定于工业机器人末端的方案.对关节型工业机器人运动轨迹的准确度进展了检测。结果说明,该检测方法简单实用,根本上可以满足工业机器人CP性能检测的要求。 一种面向工业机器人智能抓取的视觉引导技术研究 为实现工业机器人自主识别并抓取指定的目的,提出了一种基于计算机视觉引导的解决 工业机器人的运动轨迹全文共6页,当前为第2页。方法。该方法利用指定目的的3D数据模型,以及由两台或者多台CCD摄像机从工作场景中不同角度获;取到的数字图像,经过目的姿态估算、投影计算并生成投影图像,再利用投影图像与目的真实图像进展比较,实现了目的的识别与位姿获取。实验结果说明该方法可以较复杂的环境下识剐指定目的,并获得目;标的姿态信息,从而为工业机器人抓取目的提供引导。 工业机器人的运动轨迹全文共6页,当前为第2页。 视觉温度测量系统在线校准改进 汽车车身总成、分总成的加工过程中应用工业机器人视觉测量系统对关键尺寸进展在线实时监测。机械臂及环境温度变化导敛杆件和关节热膨胀变形,造成测量结果产生温度漂移.本文提出了一种在线校准方法.首先根据机器人的D.H正向运动学模型和微分运动学模型建沈末端关节坐标系的定位误差模型,然后结合轴动实验并利用多元线性pJ归方法确定受温度变化影响最为显著的机器人连杆参数,最后建口基于基准球的温度误差补偿模型.现场测量数据说明,该方法能将温度变化引起的测量误差控制在0.05mm左右,并且适应消费线的正常节拍。 2.途径跟踪与轨迹规划 手部途径跟踪和关节轨迹规划是机器人应用领域中一个非常重要的课题 在以往的研究中往往是通过在设定的途径上增加节点数和途径分段数来进步机器人手部跟踪设定途径的精但这种方法会导致在线计算量大幅度增加。 一种新的实时高精度途径跟踪与关节轨迹规划方法 通常,为了减少工业机器人控制系统的在线计算负担,运动控制是在关节坐标空间中进展的。为此,首先必须在笛卡儿空间中设定的途径上选取足够多的点称为节点,再将它们一一转换成对应的关节坐标,然后在关节空间中将这些坐标用某种方式进展拟合形成光滑的关节轨迹。 在实际控制过程中,只需让各关节沿其对应的轨迹运动,所有关节运动的综合效果就表现为机器人手部近似地沿笛卡儿空间中设定的途径运动。显然,所取的节点数越多,途径跟踪的精度也就越高。但这会 致关节轨迹分段数和关节轨迹方程数量大大增加,在线计算时控制系统的运算量大幅度增加。 同时,手部途径跟踪精度在首尾两段途径中的各节点之间有所降低。 新方法对这一缺陷将对其首、尾2段途径上的关节轨迹方程进展改进 在这2段途径上除引入1个正弦函数和1余弦函数外再引入1新的函数,函数由1正弦函数和1个1次多项式的乘积构成,并且这2段上原来的4次多项式将降低为3次多项式。这样,在首、尾2段途径上关节轨迹方程将由1个3次多项式与1个正弦

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值