车辆运动学方程推导和代码实现

文章目录

    • 1. 运动学方程
    • 2. 模型实现

1. 运动学方程

自行车模型(Bicycle Model)是车辆数字化模型中最常见的一种运动学模型。其除了可以反映车辆的一些基础特性外,更重要的是简单易用。通常情况下我们会把车辆模型简化为二自由度的自行车模型。

自行车模型主要基于以下假设:

  • 车辆是在一个二维平面上运动,不考虑车辆垂直平面的(Z轴)方向上的移动。
  • 车辆左右两个轮胎的运动可以合并为一个轮胎来描述,即假设车辆左右轮胎在任意时刻都拥有相同(或者近乎相同)的转向角度和速度。
  • 车辆处于低速运动,可以忽略前后轴载荷的偏移。
  • 车辆整体是刚体结构。

一般情况下,我们可以将车辆运动学模型简化为如下形式:

在这里插入图片描述

  • δ f \delta_f δf:前轮转角
  • δ r \delta_r δr:后轮转角
  • β \beta β:质心侧偏角,即质心速度与车身坐标系 X X X轴的夹角
  • φ \varphi φ:横摆角,即车的轴线与 X X X轴的夹角
  • β + φ \beta+\varphi β+φ:航向角
  • v v v:质心速度
  • O O O:速度瞬心
  • C C C:质心
  • L f L_f Lf:质心 C C C到前轴距离
  • L r L_r Lr:质心 C C C到后轴距离
  • L L L:轴距, L = L f + L r L=L_f+L_r L=Lf+Lr

我们对质心速度 v v v进行矢量分解,如上图中的 X ˙ \dot{X} X˙ Y ˙ \dot{Y} Y˙所示,可以得到下式子 ( 1 ) (1) (1) ( 2 ) (2) (2),根据理论力学刚体角速度公式可得公式 ( 3 ) (3) (3)。由此得到单车模型下的车辆运动学微分模型为
X ˙ = v c o s ( β + φ ) (1) \dot{X} = vcos(\beta+\varphi) \tag{1} X˙=vcos(β+φ)(1)

Y ˙ = v s i n ( β + φ ) (2) \dot{Y} = vsin(\beta+\varphi) \tag{2} Y˙=vsin(β+φ)(2)

φ ˙ = v R (3) \dot{\varphi} = \frac{v}{R} \tag{3} φ˙=Rv(3)

:一个刚体的角速度 = 线速度/线速度到速度瞬心的距离

根据图中几何关系和正弦定理可知:
L f s i n ( δ f − β ) = R s i n ( π 2 − δ f ) (4) \frac{L_f}{sin(\delta_f - \beta)} = \frac{R}{sin(\frac{\pi}{2} - \delta_f)} \tag{4} sin(δfβ)Lf=sin(2πδf)R(4)

L r s i n ( δ r + β ) = R s i n ( π 2 − δ r ) (5) \frac{L_r}{sin(\delta_r + \beta)} = \frac{R}{sin(\frac{\pi}{2} - \delta_r)} \tag{5} sin(δr+β)Lr=sin(2πδr)R(5)

由上式展开可得
L f R = s i n δ f c o s β − c o s δ f s i n β c o s δ f = t a n δ f c o s β − s i n β (6) \frac{L_f}{R} = \frac{sin\delta_f cos\beta - cos\delta_f sin\beta}{cos\delta_f} = tan\delta_fcos\beta - sin\beta\tag{6} RLf=cosδfsinδfcosβcosδfsinβ=tanδfcosβsinβ(6)

L r R = s i n δ r c o s β + c o s δ r s i n β c o s δ r = t a n δ r c o s β + s i n β (7) \frac{L_r}{R} = \frac{sin\delta_r cos\beta + cos\delta_r sin\beta}{cos\delta_r} = tan\delta_rcos\beta+sin\beta \tag{7} RLr=cosδrsinδrcosβ+cosδrsinβ=tanδrcosβ+sinβ(7)

由载荷的影响,质心 C C C位置会发生变化,导致 L f L_f Lf L r L_r Lr的长度发生变化,但是由于 L = l f + L r L = l_f +L_r L=lf+Lr是不变的,因此由式子 ( 6 ) ( 7 ) (6)(7) (6)(7)可得
L f + L r R = L R = ( t a n δ f + t a n δ r ) c o s β (8) \frac{L_f + L_r}{R} = \frac{L}{R} = (tan\delta_f + tan\delta_r)cos\beta \tag{8} RLf+Lr=RL=(tanδf+tanδr)cosβ(8)
( 3 ) (3) (3) ( 8 ) (8) (8)可得
φ ˙ = v R = v ( t a n δ f + t a n δ r ) c o s β L (9) \dot{\varphi} = \frac{v}{R} =\frac{v(tan\delta_f + tan\delta_r)cos\beta}{L} \tag{9} φ˙=Rv=Lv(tanδf+tanδr)cosβ(9)
由于低速条件下,我们可以假设车辆不会发生侧向滑动(漂移),此时我们可以将 v y ≈ 0 v_y \approx 0 vy0,因此 β ≈ 0 \beta \approx 0 β0,则横摆角 φ \varphi φ约等于航向角 φ + β \varphi + \beta φ+β 。又由于大部分车辆不具备后轮转向的功能,因此我们可以假设后轮转角 δ r ≈ 0 \delta_r\approx0 δr0,因此基于我们假设的前提下的运动学微分方程化简为
X ˙ = v c o s φ Y ˙ = v s i n φ φ ˙ = v t a n δ f L (10) \dot{X} = vcos\varphi \\ \dot{Y} = vsin\varphi \tag{10} \\ \dot{\varphi} = \frac{vtan\delta_f}{L} X˙=vcosφY˙=vsinφφ˙=Lvtanδf(10)

2. 模型实现

python代码如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import math
import matplotlib.pyplot as plt
import numpy as np
from celluloid import Camera


class Vehicle:
    def __init__(self,
                 x=0.0,
                 y=0.0,
                 yaw=0.0,
                 v=0.0,
                 dt=0.1,
                 l=3.0):
        self.steer = 0
        self.x = x
        self.y = y
        self.yaw = yaw
        self.v = v
        self.dt = dt
        self.L = l  # 轴距
        self.x_front = x + l * math.cos(yaw)
        self.y_front = y + l * math.sin(yaw)

    def update(self, a, delta, max_steer=np.pi):
        delta = np.clip(delta, -max_steer, max_steer)
        self.steer = delta

        self.x = self.x + self.v * math.cos(self.yaw) * self.dt
        self.y = self.y + self.v * math.sin(self.yaw) * self.dt
        self.yaw = self.yaw + self.v / self.L * math.tan(delta) * self.dt

        self.v = self.v + a * self.dt
        self.x_front = self.x + self.L * math.cos(self.yaw)
        self.y_front = self.y + self.L * math.sin(self.yaw)


class VehicleInfo:
    # Vehicle parameter
    L = 3.0  #轴距
    W = 2.0  #宽度
    LF = 3.8  #后轴中心到车头距离
    LB = 0.8  #后轴中心到车尾距离
    MAX_STEER = 0.6  # 最大前轮转角
    TR = 0.5  # 轮子半径
    TW = 0.5  # 轮子宽度
    WD = W  #轮距
    LENGTH = LB + LF  # 车辆长度

def draw_trailer(x, y, yaw, steer, ax, vehicle_info=VehicleInfo, color='black'):
    vehicle_outline = np.array(
        [[-vehicle_info.LB, vehicle_info.LF, vehicle_info.LF, -vehicle_info.LB, -vehicle_info.LB],
         [vehicle_info.W / 2, vehicle_info.W / 2, -vehicle_info.W / 2, -vehicle_info.W / 2, vehicle_info.W / 2]])

    wheel = np.array([[-vehicle_info.TR, vehicle_info.TR, vehicle_info.TR, -vehicle_info.TR, -vehicle_info.TR],
                      [vehicle_info.TW / 2, vehicle_info.TW / 2, -vehicle_info.TW / 2, -vehicle_info.TW / 2, vehicle_info.TW / 2]])

    rr_wheel = wheel.copy() #右后轮
    rl_wheel = wheel.copy() #左后轮
    fr_wheel = wheel.copy() #右前轮
    fl_wheel = wheel.copy() #左前轮
    rr_wheel[1,:] += vehicle_info.WD/2
    rl_wheel[1,:] -= vehicle_info.WD/2

    #方向盘旋转
    rot1 = np.array([[np.cos(steer), -np.sin(steer)],
                     [np.sin(steer), np.cos(steer)]])
    #yaw旋转矩阵
    rot2 = np.array([[np.cos(yaw), -np.sin(yaw)],
                     [np.sin(yaw), np.cos(yaw)]])
    fr_wheel = np.dot(rot1, fr_wheel)
    fl_wheel = np.dot(rot1, fl_wheel)
    fr_wheel += np.array([[vehicle_info.L], [-vehicle_info.WD / 2]])
    fl_wheel += np.array([[vehicle_info.L], [vehicle_info.WD / 2]])

    fr_wheel = np.dot(rot2, fr_wheel)
    fr_wheel[0, :] += x
    fr_wheel[1, :] += y
    fl_wheel = np.dot(rot2, fl_wheel)
    fl_wheel[0, :] += x
    fl_wheel[1, :] += y
    rr_wheel = np.dot(rot2, rr_wheel)
    rr_wheel[0, :] += x
    rr_wheel[1, :] += y
    rl_wheel = np.dot(rot2, rl_wheel)
    rl_wheel[0, :] += x
    rl_wheel[1, :] += y
    vehicle_outline = np.dot(rot2, vehicle_outline)
    vehicle_outline[0, :] += x
    vehicle_outline[1, :] += y

    ax.plot(fr_wheel[0, :], fr_wheel[1, :], color)
    ax.plot(rr_wheel[0, :], rr_wheel[1, :], color)
    ax.plot(fl_wheel[0, :], fl_wheel[1, :], color)
    ax.plot(rl_wheel[0, :], rl_wheel[1, :], color)

    ax.plot(vehicle_outline[0, :], vehicle_outline[1, :], color)
    # ax.axis('equal')



if __name__ == "__main__":

    vehicle = Vehicle(x=0.0,
                      y=0.0,
                      yaw=0,
                      v=0.0,
                      dt=0.1,
                      l=VehicleInfo.L)
    vehicle.v = 1
    trajectory_x = []
    trajectory_y = []
    fig = plt.figure()
    # 保存动图用
    # camera = Camera(fig)
    for i in range(600):
        plt.cla()
        plt.gca().set_aspect('equal', adjustable='box')
        vehicle.update(0, np.pi / 10)
        draw_trailer(vehicle.x, vehicle.y, vehicle.yaw, vehicle.steer, plt)
        trajectory_x.append(vehicle.x)
        trajectory_y.append(vehicle.y)
        plt.plot(trajectory_x, trajectory_y, 'blue')
        plt.xlim(-12, 12)
        plt.ylim(-2.5, 21)
        plt.pause(0.001)
    #     camera.snap()
    # animation = camera.animate(interval=5)
    # animation.save('trajectory.gif')

运行结果如下:

在这里插入图片描述

文章首发公众号:iDoitnow如果喜欢话,可以关注一下

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1.分组

#include<bits/stdc.h> using namespace std; int main() {unsigned long long a,b,c0,d,s0;cin>>a>>b;for(long long i1;i<a;i){cin>>d;cd;if(c>b){c0;s;}}cout<<s;return 0; }

【软件测试】概述

《软件缺陷》 定义 &#xff08;从产品内部看&#xff09;软件产品开发或维护过程中存在的错误、毛病等各种问题&#xff08;从产品外部看&#xff09;系统所需要实现的某种功能的失效或违背 表现形式(1) 软件没有实现产品规格说明所要求的功能模块(2) 软件中出现了产品规格说…

Micro-app 微前端框架demo介绍

Micro-app 框架 1、框架安装 npm i micro-zoe/micro-app --save2、子应用对应的view页面 <template><div><!-- name(必传)&#xff1a;应用名称url(必传)&#xff1a;应用地址&#xff0c;会被自动补全为http://localhost:3000/index.htmlbaseroute(可选)&…

Java 堆的设计,如何用堆进行排序

Java 学习面试指南&#xff1a;https://javaxiaobear.cn 1、堆的定义 堆是计算机科学中一类特殊的数据结构的统称&#xff0c;堆通常可以被看做是一棵完全二叉树的数组对象。 1、堆的特性 它是完全二叉树&#xff0c;除了树的最后一层结点不需要是满的&#xff0c;其它的每一层…

mac版viso软件 流程图软件omnigraffile

OmniGraffle 是一款由 The Omni Group 开发的绘图工具&#xff0c;主要用于创建各种类型的图表、流程图、组织结构图、网站地图等。它提供了丰富的绘图工具和功能&#xff0c;包括形状、线条、文本、颜色、样式等&#xff0c;可以帮助用户轻松地创建出精美的图表和图形。 OmniG…

《PySpark大数据分析实战》-24.数据可视化图表介绍

&#x1f4cb; 博主简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是wux_labs。&#x1f61c; 热衷于各种主流技术&#xff0c;热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员&#xff08;PCTA&#xff09;、TiDB数据库专家&#xff08;PCTP…

深度解析基于模糊数学的C均值聚类算法

深度解析基于模糊数学的C均值聚类算法 模糊C均值聚类 (FCM)聚类步骤&#xff1a;FCM Python代码&#xff1a; 模糊C均值聚类 (FCM) 在数据挖掘和聚类分析领域&#xff0c;C均值聚类是一种广泛应用的方法。模糊C均值聚类&#xff08;FCM&#xff09;是C均值聚类的自然升级版。相…

WebSocket的优点和缺点:一文详解。

WebSocket 的优缺点 WebSocket 协议是一种双向通信协议&#xff0c;它使用单个 TCP 连接实现全双工通信&#xff0c;这使它比传统的 HTTP 协议更有效率。 WebSocket 优点 双向通信&#xff1a; WebSocket 协议支持双向通信&#xff0c;使服务器和客户端之间的通信更加方便和快…

关于使用统一服务器,vscode和网页版jupyter notebook的交互问题

autodl 查看虚拟环境 在antodl上租借了一个服务器&#xff0c;通过在网页上运行jupyter notebook和在vscode中运行&#xff0c;发现环境都默认的是miniconda3。 conda info --envs 当然环境中所有的包都是一样的。 要查看当前虚拟环境中安装的所有包&#xff0c;可以使用以…

解决Typescript报错问题[亲测有效]

目录 1、安装 2、报错 3、分析 4、三种更新途径 如果你tsc -v报错&#xff0c;请看这篇文章&#xff0c;本人亲测有效&#xff01; 1、安装 在前端项目中使用TS&#xff0c;需要进行安装&#xff0c;命令为&#xff1a;npm install -g typescript 查看TS版本&#xff1a; …

图像解析力测试

什么是图像解析力测试 图像解析力测试是衡量成像系统性能的关键指标之一,它决定了摄像头捕捉到的图像细节和清晰度。目前主流的图像解析力测试方法主要有TV line检测、MTF检测和SFR检测。 TV line检测主要用于主观测试,通过观察图像中的线条来评估解析力。然而,这种方法缺乏…

Django(六)

员工管理系统(用户管理&#xff09; {% extends layout.html %}{% block content %}<div class"container"><div style"margin-bottom: 10px"><a class"btn btn-success" href"#"><span class"glyphicon gl…

【python】连上钉钉机器人每日推送

使用Python向钉钉机器人发送消息 导入必要的库 导入json库用于处理JSON数据&#xff0c;time库用于获取当前时间&#xff0c;requests库用于发送HTTP请求。 定义send_ding_message函数 该函数接收一个消息作为参数&#xff0c;并通过POST请求发送给钉钉机器人。请求的URL和头部…

C语言光速入门笔记

C语言是一门面向过程的编译型语言&#xff0c;它的运行速度极快&#xff0c;仅次于汇编语言。C语言是计算机产业的核心语言&#xff0c;操作系统、硬件驱动、关键组件、数据库等都离不开C语言&#xff1b;不学习C语言&#xff0c;就不能了解计算机底层。 目录 C语言介绍C语言特…

Java二叉树的遍历以及最大深度问题

Java学习面试指南&#xff1a;https://javaxiaobear.cn 1、树的相关概念 1、树的基本定义 树是我们计算机中非常重要的一种数据结构&#xff0c;同时使用树这种数据结构&#xff0c;可以描述现实生活中的很多事物&#xff0c;例如家谱、单位的组织架构、等等。 树是由n&#…

C#: 和时间相关,延时、获取系统时间、时间格式转换、定时器 等

说明&#xff1a;本文记录C# 和时间相关&#xff0c;延时、获取系统时间、时间格式转换、定时器 等&#xff0c;应用和代码。 1.延时函数 System.Threading.Thread.Sleep(20); //毫秒 1.1 主线程不卡延时函数 /* 主线程不卡延时函数 */public static void Delay_ms(int mil…

「斗破年番」5位斗宗大战,韩枫献海心焰晋斗宗,菩提涎争夺开战

Hello,小伙伴们&#xff0c;我是拾荒君。 国漫《斗破苍穹年番》第78期超前爆料&#xff0c;本期透露菩提化体涎的背后秘密。天鹰老人抢夺菩提化体涎后&#xff0c;迅速逃匿&#xff0c;却遭到了各路强者的围攻。然而&#xff0c;这位四星斗宗强者并非浪得虚名&#xff0c;他仅…

Defi安全-Monox攻击事件Foundry复现

其它相关内容可见个人主页 Mono攻击事件的介绍见&#xff1a;Defi安全–Monox攻击事件分析–phalconetherscan 1. 前情提要和思路介绍 Monox使用单边池模型&#xff0c;创建的是代币-vCash交易对&#xff0c;添加流动性时&#xff0c;只需添加代币&#xff0c;即可进行任意代…

Docker常用命令Docker命令 docker常用命令

Docker常用命令Docker命令 docker常用命令 Docker常用命令Docker命令 docker常用命令1、拉取镜像2、查看镜像列表3、run命令帮助信息3.1、创建容器并且运行, 最基本的创建运行3.2、创建容器并且运行, 容器端口绑定宿主机端口3.3、创建容器并且运行, 启动容器传递参数3.4、创建容…

Vue3 结合typescript 组合式函数(1)

在App.vue文件中 实现鼠标点击文件&#xff0c;显示坐标值 第一种方法 第二种方法&#xff1a;组合式函数 结果&#xff1a; 官网推荐组合函数&#xff1a;https://vueuse.org