环境

1. 导入需要的库

import numpy as np
import csv

2. 定义三角函数用于坐标系转换

# cos(x)
def C(x):
    return np.cos(x)
# sin(x)
def S(x):
    return np.sin(x)

3. 定义转换矩阵:大地坐标系---->随体坐标系

def earth_to_body_frame(ii, jj, kk):
    # C^b_n
    R = [[C(kk) * C(jj), C(kk) * S(jj) * S(ii) - S(kk) * C(ii), C(kk) * S(jj) * C(ii) + S(kk) * S(ii)],
         [S(kk) * C(jj), S(kk) * S(jj) * S(ii) + C(kk) * C(ii), S(kk) * S(jj) * C(ii) - C(kk) * S(ii)],
         [-S(jj), C(jj) * S(ii), C(jj) * C(ii)]]
    return np.array(R)

4. 定义转换矩阵:随体坐标系---->大地坐标系

def body_to_earth_frame(ii, jj, kk):
    # C^n_b
    return np.transpose(earth_to_body_frame(ii, jj, kk))

5. 将飞行器运动模型定义成一个类

5.1 定义__init__()函数

class PhysicsSim():
    def __init__(self, init_pose=None, init_velocities=None, init_angle_velocities=None, runtime=5.):
        self.init_pose = init_pose
        self.init_velocities = init_velocities
        self.init_angle_velocities = init_angle_velocities
        self.runtime = runtime

        self.gravity = -9.81  # m/s
        self.rho = 1.2        # 油门线性占空比
        self.mass = 0.958     # 300 g
        self.dt = 1 / 50.0    # Timestep
        self.C_d = 0.3        # 螺旋桨拉力系数
        self.l_to_rotor = 0.4 
        self.propeller_size = 0.1 # 螺旋桨尺寸
        width, length, height = .51, .51, .235 # 飞机的尺寸规格
        self.dims = np.array([width, length, height])  # x, y, z dimensions of quadcopter
        self.areas = np.array([length * height, width * height, width * length])
       
        # 转动惯量
        I_x = 1 / 12. * self.mass * (height**2 + width**2)
        I_y = 1 / 12. * self.mass * (height**2 + length**2)  # 0.0112 was a measured value
        I_z = 1 / 12. * self.mass * (width**2 + length**2)
        self.moments_of_inertia = np.array([I_x, I_y, I_z])  # 惯性矩
       
        # 限定飞行器的运动范围
        env_bounds = 300.0  # 300 m / 300 m / 300 m
        self.lower_bounds = np.array([-env_bounds / 2, -env_bounds / 2, 0])
        # [-150, -150, 0]
        self.upper_bounds = np.array([env_bounds / 2, env_bounds / 2, env_bounds])
        # [150,150,300]
        self.reset()

5.2 定义reset(self)函数

与最后的next_step()函数对应,这里出现的变量,在next_step()函数中都会再出现

  1. 时间
  2. 位姿:[x,y,z,\phi,\theta,\psi] 初始化为[0, 0, 10, 0, 0, 0]
  3. 对地速度:[dx,dy,dz] 初始化为[0, 0, 0]
  4. 对地角速度:[d\phi,d\theta,d\psi] 初始化为[0, 0, 0]
  5. 对地加速度
  6. 对地角加速度
  7. 螺旋桨风速
    def reset(self):
     1. self.time = 0.0
     2. self.pose = np.array([0.0, 0.0, 10.0, 0.0, 0.0, 0.0]) if self.init_pose is None else self.init_pose
     3. self.v = np.array([0.0, 0.0, 0.0]) if self.init_velocities is None else self.init_velocities
     4. self.angular_v = np.array([0.0, 0.0, 0.0]) if self.init_angle_velocities is None else self.init_angle_velocities
     5. self.linear_accel = np.array([0.0, 0.0, 0.0])
     6. self.angular_accels = np.array([0.0, 0.0, 0.0])
     7. self.prop_wind_speed = np.array([0., 0., 0., 0.])
     8. self.done = False

5.3 计算随体速度

调用 earth_to_body_frame(ii, jj, kk) 转换矩阵:大地坐标系---->随体坐标系
返回随体速度[u,v,w]

    def find_body_velocity(self):
        body_velocity = np.matmul(earth_to_body_frame(*list(self.pose[3:])), self.v)
        return body_velocity

5.4 计算阻力

    def get_linear_drag(self):
        linear_drag = 0.5 * self.rho * self.find_body_velocity()**2 * self.areas * self.C_d
        return linear_drag

5.5 计算螺旋桨产生的拉力

    def get_linear_forces(self, thrusts):
        # Gravity
        gravity_force = self.mass * self.gravity * np.array([0, 0, 1])
        # Thrust
        thrust_body_force = np.array([0, 0, sum(thrusts)])
        # Drag
        drag_body_force = -self.get_linear_drag()
        body_forces = thrust_body_force + drag_body_force

        linear_forces = np.matmul(body_to_earth_frame(*list(self.pose[3:])), body_forces)
        linear_forces += gravity_force
        return linear_forces

5.6 计算力矩

    def get_moments(self, thrusts):
       # 推力矩
        thrust_moment = np.array([(thrusts[3] - thrusts[2]) * self.l_to_rotor,
                            (thrusts[1] - thrusts[0]) * self.l_to_rotor,
                            0])# (thrusts[2] + thrusts[3] - thrusts[0] - thrusts[1]) * self.T_q])  # Moment from thrust

        drag_moment =  self.C_d * 0.5 * self.rho * self.angular_v * np.absolute(self.angular_v) * self.areas * self.dims * self.dims
        moments = thrust_moment - drag_moment # + motor_inertia_moment
        return moments

5.7 计算螺旋桨风速

    def calc_prop_wind_speed(self):
        body_velocity = self.find_body_velocity()
        phi_dot, theta_dot = self.angular_v[0], self.angular_v[1]
        s_0 = np.array([0., 0., theta_dot * self.l_to_rotor])
        s_1 = -s_0
        s_2 = np.array([0., 0., phi_dot * self.l_to_rotor])
        s_3 = -s_2
        speeds = [s_0, s_1, s_2, s_3]
        for num in range(4):
            perpendicular_speed = speeds[num] + body_velocity
            self.prop_wind_speed[num] = perpendicular_speed[2]

5.8 计算净推力 - thrusts

    def get_propeler_thrust(self, rotor_speeds):
        '''根据螺旋桨的速度和输入功率计算净推力(推力 - 阻力)'''
        thrusts = []
        for prop_number in range(4):
            V = self.prop_wind_speed[prop_number]
            D = self.propeller_size
            n = rotor_speeds[prop_number]
            J = V / n * D
            # From http://m-selig.ae.illinois.edu/pubs/BrandtSelig-2011-AIAA-2011-1255-LRN-Propellers.pdf
            C_T = max(.12 - .07*max(0, J)-.1*max(0, J)**2, 0)
            thrusts.append(C_T * self.rho * n**2 * D**4)
        return thrusts

5.9 计算下一时间步的状态

此处使用的是前向欧拉方程:从当前时刻出发,根据当前时刻的函数值及其导数,可得到下一时刻的值
参考://www.greatytc.com/p/e774e75f1263

    def next_timestep(self, rotor_speeds):
    7.  self.calc_prop_wind_speed()
        thrusts = self.get_propeler_thrust(rotor_speeds)
    5.  self.linear_accel = self.get_linear_forces(thrusts) / self.mass

        position = self.pose[:3] + self.v * self.dt + 0.5 * self.linear_accel * self.dt**2
    3.  self.v += self.linear_accel * self.dt

        moments = self.get_moments(thrusts)

    6.  self.angular_accels = moments / self.moments_of_inertia
        angles = self.pose[3:] + self.angular_v * self.dt + 0.5 * self.angular_accels* self.dt*self.dt
        angles = (angles + 2 * np.pi) % (2 * np.pi)
    4.  self.angular_v = self.angular_v + self.angular_accels * self.dt

        new_positions = []
        for ii in range(3):
            if position[ii] <= self.lower_bounds[ii]:
                new_positions.append(self.lower_bounds[ii])
                self.done = True
            elif position[ii] > self.upper_bounds[ii]:
                new_positions.append(self.upper_bounds[ii])
                self.done = True
            else:
                new_positions.append(position[ii])

    2.  self.pose = np.array(new_positions + list(angles))
    1.  self.time += self.dt
        if self.time > self.runtime:
            self.done = True
        return self.done
  1. 位姿:[x,y,z,\phi,\theta,\psi]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 一. 环境搭建 需要准备资源GLTools 工具类和libGLTools.a文件 如下: 包含了一个可移动正方块的...
    TeeMo_Yan阅读 381评论 1 1
  • 1. 概述 细节:动力不足的汽车必须爬上一维小山才能到达目标。 与MountainCar-v0不同,动作(应用的引...
    博士伦2014阅读 17,741评论 0 5
  • **微生物群落多样性的基本概念**环境中微生物的群落结构及多样性和微生物的功能及代谢机理是微生物生态学的研究热点。...
    相见很不晚阅读 9,952评论 1 47
  • 在这个离别的黄昏, 你立在那里,如一座孤城 暮色的薄纱披在你的肩上, 沉默是一片落叶, 飘过。 我无力对你的爱。 ...
    简兮5阅读 210评论 0 0
  • 【书籍名称】《10倍数目标达成法》 【阅读感受】 原来目标达成还有这么多高效的方法论! 1. 三大策略 稻草战略 ...
    詹绯阅读 115评论 0 0