AUTOSAR 到底是什么?

一、AUTOSAR 到底是什么?

1.1 先从传统嵌入式开发说起

假设你之前开发一个低速智能车的 VCU,使用 STM32 + FreeRTOS。

你的工程可能类似这样:

传统 VCU 工程(示意)

VCU_Project/

main.c

— 系统初始化、启动任务

can.c

— CAN 收发、协议解析

vcu_control.c

— 整车状态机、扭矩控制

fault_manager.c

— 故障检测与处理

uds.c

— 诊断服务

motor_control.c

— 电机控制逻辑

freertos.c

— 任务创建和调度

stm32_hal_xxx.c

— 硬件驱动

这套架构完全可以开发出实际产品。

例如:

void VCU_Task(void *argument)
{
    for (;;)
    {
        Read_CAN_Data();       // 读取 CAN 数据
        Update_Vehicle_State();// 更新整车状态
        Check_Faults();       // 检查故障
        Calculate_Torque();   // 计算目标扭矩
        Send_Motor_Command(); // 发送控制命令

        vTaskDelayUntil(...); // 周期调度,省略具体参数
    }
}

作为开发工程师,你要自己考虑:

  • CAN 驱动怎么接入,如何解析信号。
  • 模块之间怎么传递数据。
  • 任务如何调度,哪些任务需要 1ms、10ms、100ms。
  • UDS 诊断如何处理。
  • 故障如何记录到 Flash。
  • 换一个 MCU 后,需要修改哪些驱动与应用代码。

问题不是这套程序不能用,而是不同公司、不同团队的 ECU 软件往往采用各自的一套架构。

假设后续:

  • 原先 STM32 换成英飞凌 AURIX。
  • 原先自己开发的 CAN 驱动换成 Vector 的通信栈。
  • 原先自己写的 UDS 模块换成另一家供应商的诊断模块。
  • 需要把部分控制逻辑移植到其他车型。

如果接口设计不规范,就可能涉及大量修改、集成和重复测试。

这就是 AUTOSAR 想解决的问题之一。

1.2 AUTOSAR 的定义

AUTOSAR = AUTomotive Open System ARchitecture,汽车开放系统架构。

它是一套由汽车行业共同制定的软件架构、接口、方法论和配置标准。

它不是一块芯片,也不是一个单独的操作系统,更不是下载下来就能运行的完整开源软件工程。

AUTOSAR 的核心思想是:

将车辆应用功能与 ECU 底层软硬件解耦,通过标准化接口实现组件化开发、集成和复用。

这是 AUTOSAR 官方所强调的设计目标。

举个例子:

你原来的 VCU 控制代码可能直接调用:

CAN_Send(TORQUE_CAN_ID, data, 8);

应用层既要知道 CAN ID,又要知道 CAN 驱动和具体的数据格式。

AUTOSAR 希望在典型场景下把它改成:

Rte_Write_PpTorqueCmd_TorqueCmd(torque);

这里的函数名称是示例,实际接口由工程配置生成。

现在应用层主要关心的是:

我要提供一个名叫 TorqueCmd 的目标扭矩数据。

至于这个数据到底是:

  • 传递给同一 ECU 内的另一个软件组件;
  • 通过 CAN 发送到电机控制器;
  • 经过其他已配置的通信路径传递;

主要由组件连接关系、RTE 和通信基础软件共同实现。

当然,真正的量产系统还需要考虑信号转换、通信超时、数据安全、配置一致性等,不是换个函数名就完成了 AUTOSAR 改造。

1.3 AUTOSAR 分成 Classic 和 Adaptive

这是需要先分清楚的事情。

对比 AUTOSAR Classic(CP) AUTOSAR Adaptive(AP)
主要硬件 MCU、汽车控制器 高性能 SoC、计算平台
典型系统 AUTOSAR OS POSIX 系统,例如 Linux、QNX
主要语言 C 以 C++ 为主
实时性重点 确定性、严格实时控制 高性能、服务化及复杂应用
应用例子 VCU、BMS、电驱、车身控制 域控、高级辅助驾驶、高性能计算
通信接口 Classic RTE ara::com 等 Adaptive 接口

AUTOSAR 官方也将 Classic 定位于实时性、安全性要求较高的嵌入式 ECU,将 Adaptive 定位于高性能计算类 ECU

注意,这个表只是典型适用场景,不代表 Classic 不能用以太网,也不代表 Adaptive 只能用 Linux。

二、AUTOSAR 的整体软件架构

这是最重要的一张架构图。

注意,图中 BSW 模块的位置是教学简化示意。实际层次里还有通信硬件抽象、存储硬件抽象、加密服务等多个模块,不能把所有模块严格理解成逐层垂直调用。

AUTOSAR 官方架构明确将软件分为应用层、RTE、BSW,并进一步划分 BSW 的服务、ECU 抽象、MCAL 和复杂驱动

2.1 ASW:Application Software

你可以把 ASW 理解为:

真正决定车辆或控制器应该做什么的软件。

举几个例子。

对于 VCU:

ASW 模块 负责的工作
VehicleState 整车上下电、READY、故障状态管理
TorqueManager 目标扭矩计算、限幅
GearManager 档位状态、换档条件判断
FaultMonitor 业务故障检测、处理策略
ThermalManager 温度监控、热降额策略

对于新能源电控:

ASW 模块 可能的工作
PowerState 充电机、DC/DC 或逆变器状态管理
VoltageControl 电压调节控制
CurrentControl 电流调节控制
Protection 过流、过温、过压保护策略
Diagnostics 应用诊断逻辑及状态管理

在 ASW 中,你仍然需要写 C 语言的判断、算法、状态机和控制逻辑。

AUTOSAR 不会自动帮你写好扭矩算法,也不会自动实现电流闭环。它主要规范组件之间怎样连接、怎样运行,以及怎样接入标准化基础软件。

2.2 RTE:Runtime Environment

这是 AUTOSAR 最有代表性的部分。

RTE 位于 ASW 与 BSW 之间,提供标准化交互接口。

例如有两个软件组件:

在应用代码中,可能是:

/* SWC A:输出目标扭矩 */
void TorqueRequest_10ms(void)
{
    sint16 torque = 1000;  // 示例:0.1Nm/LSB,即100Nm

    Rte_Write_PpTorqueReq_TorqueReq(torque);
}

另一个组件:

/* SWC B:读取目标扭矩 */
void TorqueLimit_10ms(void)
{
    sint16 torque = 0;

    if (Rte_Read_RpTorqueReq_TorqueReq(&torque) == E_OK)
    {
        /* 进行扭矩限制和安全检查 */
    }
}

上面代码仅用于解释 RTE 接口的使用方式,省略了工程头文件、配置、初始化和其他必要判断,并不是可以直接编译的完整 AUTOSAR 项目。

这两个 SWC 不需要直接包含对方的头文件,也不需要彼此调用对方的应用函数。

RTE 通过配置好的接口和组件连接关系完成交互。

还有一个细节:AUTOSAR 可以让应用组件分布在不同 ECU 上。若两个组件属于不同 ECU,通信会经过底层网络栈,而不是说 RTE 本身可以脱离 CAN 或以太网跨控制器发送数据。

2.3 BSW:Basic Software

BSW 可以理解为 ECU 的标准化基础软件设施。

你以前自己写过 CAN 协议、诊断、Flash 存储、看门狗等内容。

在 AUTOSAR 工程中,这些功能往往由对应的 BSW 模块承担。

BSW 模块 英文名称 作用
OS Operating System 任务调度、中断管理、系统资源管理
COM Communication 应用信号与 I-PDU 的处理
PduR PDU Router 通信数据单元路由
CanIf CAN Interface CAN 驱动的统一接口
CanTp CAN Transport Protocol CAN 多帧传输
DCM Diagnostic Communication Manager UDS 诊断服务处理
DEM Diagnostic Event Manager 故障事件及 DTC 相关管理
NvM NVRAM Manager 非易失性数据管理
EcuM ECU State Manager ECU 启动、休眠、状态协调
BswM BSW Mode Manager 基础软件模式协调
WdgM Watchdog Manager 软件实体执行监督及看门狗管理

这里你可以直接关联以前的 VCU 工作。

你自己实现过 UDS 升级、故障诊断,应该比较熟悉诊断服务与控制器状态管理。

在 AUTOSAR 中,你需要理解这些功能如何通过 BSW 和应用层的接口协作,而不只是知道 UDS 的服务 ID。

2.4 MCAL:Microcontroller Abstraction Layer

MCAL 是 BSW 中靠近 MCU 硬件的一层。

比如换一个 MCU:

原本是 STM32:

HAL_CAN_AddTxMessage(...);

另一个平台可能采用英飞凌的硬件驱动接口。

而在对应的 AUTOSAR CAN 驱动中,上层一般通过标准化的驱动接口和 CanIf 交互。

MCAL 模块常见的有:

模块 作用
Can CAN 控制器驱动
Adc ADC 采样驱动
Pwm PWM 输出
Dio 数字 IO
Spi SPI 通信
Mcu 时钟、复位等 MCU 管理
Fls Flash 驱动
Port 引脚配置

注意:MCAL 只是规范驱动接口,并不代表不同 MCU 的底层驱动二进制文件可以直接通用。

更换 MCU 后,MCAL 实现和硬件配置通常仍需要重新适配。

对于法雷奥这种可能使用 AURIX TriCore 的控制器,你至少要知道 MCAL、BSW 和 ASW 各自负责什么。

三、SWC、Runnable、Port、Event、Task 分别是什么?

这一节非常关键。面试 AUTOSAR ASW 开发,基本绕不开这几个概念。

先记住一个关系:

SWC 是功能组件,Runnable 是组件中的执行函数,Event 决定什么时候触发它,OS Task 则负责实际的 CPU 调度。Port 是组件与外界交互的接口,RTE 把这些接口连接起来。

3.1 SWC:Software Component

SWC 是 AUTOSAR 应用软件组件。

我们拿以前的 VCU 扭矩管理举例。

你的 VCU 可能有这么一个函数:

void VCU_CalculateTorque(void)
{
    // 读取油门请求
    // 判断车辆状态
    // 检查故障
    // 计算扭矩限制
    // 输出目标扭矩
}

在 AUTOSAR 中,可以设计一个 TorqueManagerSWC。

一个 SWC 并不等于一个 .c 文件,也不等于一个 FreeRTOS Task。

它更像一个有明确定义接口、内部行为和运行要求的软件功能单元。

SWC 内部可以定义多个 Runnable,也可以声明需要访问哪些数据、使用哪些服务,以及有哪些标定参数。

3.2 Runnable:可执行实体

Runnable 是 SWC 内部实际执行的软件单元,通常对应一个 C 函数。

例如:

void TorqueManager_10ms(void)
{
    /* 读取输入数据 */
    /* 计算扭矩 */
    /* 输出控制结果 */
}

这里有一个常见误区:

Runnable 不是一个线程,也不是一个独立的操作系统任务。

它只是一个按 AUTOSAR 定义的可执行实体。

Runnable 可能被分配到某个 OS Task 内运行,也可能通过客户端服务调用等机制触发。

对于典型的周期应用 Runnable,你可以把它理解成:

你原来 FreeRTOS 任务循环里面需要周期调用的那个业务函数。

例如以前:

void Task_10ms(void *argument)
{
    TickType_t lastWake = xTaskGetTickCount();

    while (1)
    {
        CalculateTorque();
        CheckFault();

        vTaskDelayUntil(
            &lastWake,
            pdMS_TO_TICKS(10)
        );
    }
}

现在 AUTOSAR 可以把这两个功能建模为 Runnable,再配置它们的触发事件和到 OS Task 的映射。

注意:这里不是让你在 Runnable 内继续创建一个 FreeRTOS 死循环。

3.3 Event:什么时候运行 Runnable?

Event 就是触发 Runnable 执行的条件。

Event 类型 含义 示例
TimingEvent 按周期触发 每 10ms 计算一次目标扭矩
DataReceivedEvent 收到配置的数据时触发 新的输入数据到达
OperationInvokedEvent 客户端调用服务时触发 处理某个服务操作
InitEvent 初始化时触发 软件组件初始化
ModeSwitchEvent 模式变化时触发 ECU 进入某种运行模式

假设你给扭矩 Runnable 配置了:

TimingEvent = 10ms

这表示要求它每 10ms 被激活。

但它具体运行在哪个核、哪个 OS Task 中,以什么优先级执行,是 ECU 集成配置需要解决的事情。

3.4 OS Task 和 Runnable 的关系

这是经常考的问题。

你可以类比成:

FreeRTOS 经验 AUTOSAR 对应概念
FreeRTOS Task AUTOSAR OS Task
业务函数 Runnable
周期调用业务函数 TimingEvent + Task 映射
任务中的共享数据 RTE 数据交换、组件内部数据等
Semaphore / Mutex AUTOSAR OS Resource、Exclusive Area 等同步机制

需要特别注意,Runnable 有可能存在并发执行、共享变量竞争的问题。

如果不同 Runnable 分配到不同 OS Task 或 CPU 核,就要考虑数据一致性、重入性、执行顺序和时序约束。

对于你之前做的机器人多执行器实时控制,这类问题应该比较容易联系起来。

四、Port 和 RTE 是怎么传递数据的?

前面讲了 SWC 和 Runnable,接下来讲组件之间如何传数据。

4.1 Port 是什么?

Port 是 SWC 对外提供或使用接口的连接点。

最基本的有两种:

端口 含义 作用
P-Port Provided Port 提供数据或服务
R-Port Required Port 接收数据或请求服务

但还需要区分接口类型,因为端口只是连接点,具体怎样通信取决于 Port Interface。

常见的有 Sender-Receiver 和 Client-Server 两种。

4.2 Sender-Receiver:数据发送与接收

假设两个组件:

SpeedSensorSWC 负责提供当前车速。

TorqueControlSWC 负责根据车速进行扭矩限制。

你写代码时可以使用:

Rte_Write_PpSpeed_Speed(speed);

接收侧:

Rte_Read_RpSpeed_Speed(&speed);

注意还有一个细节。

AUTOSAR RTE 支持显式和隐式数据访问。

显式访问常见函数是:

Rte_Read()` / `Rte_Write()

隐式访问则可能使用:

Rte_IRead()` / `Rte_IWrite()

隐式读取通常可以在一次 Runnable 执行期间提供稳定的数据快照,避免多次读取时输入数据变化造成不一致。具体语义由 AUTOSAR RTE 规范定义。

这与你之前关注的多执行器状态缓存、线程并发读取问题很相关。

不过还需要强调:数据读取成功,不一定代表传感器数据是最新的。

比如车速 20km/h 这个数值可能是 200ms 前收到的,因此通信超时和数据有效性仍然需要单独设计。

4.3 Client-Server:客户端调用服务

另一种常见模式是 Client-Server。

比如应用软件需要读取存储数据或调用某个诊断相关服务。

调用形式可能类似:

Std_ReturnType result;

result = Rte_Call_RpConfigService_ReadConfig(&config);

这是接口名称和类型均已配置好的假设示例。

两种通信模式的区别:

Sender-Receiver Client-Server
核心 传递数据 调用服务
典型用途 车速、扭矩、电压、温度 读取参数、诊断操作、服务请求
交互方式 发送端写,接收端读 客户端调用,服务端处理
是否必须同步等待 不需要 可同步或异步,依配置而定

记忆方法:Sender-Receiver 更像数据流,Client-Server 更像函数服务调用。

两者并不等同于 ROS2 的 Topic 和 Service,但可以用它们帮助理解通信模式的差异。

五、最重要的实战:CAN 数据如何进入 ASW?

如果你面试汽车 ECU 的 ASW 开发,面试官很可能会让你解释 CAN 数据的传递路径。

假设 VCU 通过 CAN 向法雷奥的电机控制器发送目标扭矩。

报文定义如下(仅为假设):

字段 示例
CAN ID 0x180
DLC 8 字节
扭矩信号 TorqueReq
分辨率 0.1 Nm/bit
接收周期 10ms
超时阈值 假设 50ms

这时 ASW 不应该简单地直接解析 CAN ID 0x180。

在典型 AUTOSAR Classic 通信栈中,数据会经过下面的路径。

这是一条典型的普通 CAN 信号接收路径,实际还可能涉及 CanSM、ComM、E2E 保护、信号转换等相关模块或机制。

第一步:CAN Driver

负责 MCU CAN 外设驱动,包括报文接收、发送以及控制器相关操作。

你以前写 STM32 CAN 或 FDCAN 驱动时做的部分工作,就属于这一层所负责的范畴。

第二步:CanIf

CanIf 提供 CAN 接口抽象,使上层通信模块不需要直接操作底层控制器寄存器。

第三步:PduR

PduR 负责通信 PDU 的路由。

在汽车通信架构中,需要区分 PDU 和具体业务信号。一个 CAN 报文通常可以承载多个信号。

第四步:COM

COM 根据通信配置处理信号与 I-PDU 的打包、解包,以及相关的接收超时等通信行为。

例如 CAN ID 0x180 中包含:

TorqueReq、Enable、Counter 等信号。

COM 负责从对应的通信数据结构中取得信号值,而不是每个应用 SWC 都重复手写字节移位和位掩码解析。

如果存在计数器、CRC 或 E2E 保护,还需要配置相应机制,不能认为 COM 自动完成所有应用数据安全校验。

第五步:RTE

RTE 将数据提供给应用软件的端口。

第六步:ASW

应用程序读到扭矩数据以后,还需要判断它是否有效。

例如:

void TorqueManager_10ms(void)
{
    sint16 torqueReq = 0;

    if (Rte_Read_RpVcuTorque_TorqueReq(&torqueReq) == E_OK)
    {
        /* 判断请求有效性 */
        /* 判断当前控制器状态 */
        /* 根据温度、电流进行限幅 */
        /* 输出实际允许的目标扭矩 */
    }
    else
    {
        /* 按故障策略处理读取异常 */
    }
}

还需要结合通信超时状态、信号范围、计数器校验和故障状态等信息判断输入是否可以使用。单独一个 E_OK 不足以证明接收到的是有效的新数据。

这就是 ASW 工程师需要负责的部分。

六、你之前做过 UDS,AUTOSAR 诊断应该很容易理解

你以前自己做过诊断和 Bootloader。

在 AUTOSAR 中,UDS 诊断一般由 DCM、DEM 以及应用软件配合完成。

首先区分三个概念:

UDS 是诊断通信协议;DCM 是 AUTOSAR 中主要处理诊断服务的模块;DEM 负责诊断事件与 DTC 相关管理。

6.1 UDS 诊断请求如何处理?

例如诊断仪请求读取一个 DID:

0x22 F1 90

常见的 CAN UDS 路径:

如果诊断仪请求读取 DTC,例如 SID 0x19,DCM 一般需要与 DEM 协作取得相应故障码、状态等信息。

6.2 DEM 是什么?

假设你的电机控制器检测到过温。

在以前的项目中,你可能自己维护一个故障结构体:

fault.motor_over_temp = true;

然后在诊断模块中转换为故障码、记录到 Flash。

AUTOSAR 中可以采用类似以下分工:


一个典型的故障报告调用形式:

Dem_SetEventStatus(
    DemConf_DemEventParameter_MotorOverTemp,
    DEM_EVENT_STATUS_FAILED
);

这里的事件 ID 由项目配置产生,实际 ASW 可能通过生成的 RTE 服务接口来访问诊断功能,未必直接调用 DEM API。

另外,DEM 负责的故障状态管理,不等于 ASW 的安全控制策略。

例如:

电机过温以后究竟降低多少扭矩、是否进入故障状态、是否禁止使能,这些仍然属于应用控制策略或功能安全设计。

DEM 可以按照配置实现去抖、事件状态管理、DTC 映射和故障信息保存,但它不会自动替你设计整车的安全降级算法。

这个区别面试时一定要讲清楚。

七、ARXML 到底是什么?为什么还需要 DaVinci?

你现在应该发现一个问题:

我们前面写了很多 Rte_Read() 和 Rte_Write(),但这些函数从哪里来?

而且,RTE 怎么知道:

  • 哪些 SWC 需要连接?
  • 两个组件之间的数据类型是什么?
  • 哪个 Runnable 每 10ms 执行?
  • 哪个 Runnable 需要分配到哪个 OS Task?
  • 哪个应用信号要映射到哪个 CAN 报文?

答案就在于 AUTOSAR 配置描述、ARXML、工具链和代码生成。

7.1 ARXML 是什么?

ARXML 是 AUTOSAR XML 格式的描述文件。

它可以描述软件组件、端口、数据类型、接口、ECU 配置等多种 AUTOSAR 工程信息。

你可以把它理解成一套标准化的、由工具处理的工程配置数据。

例如,我们想设计一个软件组件:

TorqueManagerSWC

它拥有:

属性 定义
SWC 名称 TorqueManagerSWC
输入端口 RpTorqueRequest
输出端口 PpTorqueCommand
输入数据 TorqueRequest,sint16
输出数据 TorqueCommand,sint16
Runnable TorqueManager_10ms
触发事件 TimingEvent,10ms

这些信息可以使用 AUTOSAR 工具建模,形成相应的 ARXML 描述。

接下来,工具会根据设计和 ECU 集成配置生成所需要的 RTE 接口和代码。

但注意,ARXML 并不是随便写一个 XML 文件就可以用。它必须符合相应 AUTOSAR Release 的 Schema 和语义约束。

十一、面试时最容易被追问的 6 个问题

问题 1:AUTOSAR 与 FreeRTOS 有什么区别?

FreeRTOS 是实时操作系统,主要提供任务调度、同步、定时器等机制。AUTOSAR Classic 是一整套汽车软件标准,包括 ASW、RTE、BSW 和 AUTOSAR OS。AUTOSAR OS 只是其基础软件的一部分。

问题 2:Runnable 和 Task 的区别?

Runnable 是 SWC 中的可执行实体,OS Task 是调度实体。Runnable 根据事件触发,并在 ECU 集成时映射到具体任务执行。

问题 3:RTE 有什么作用?

RTE 为应用组件提供通信和服务访问接口,通过配置连接 SWC 与 SWC、SWC 与相关基础软件服务,使应用逻辑尽可能独立于底层实现。

问题 4:ASW 和 BSW 的区别?

ASW 负责控制器的应用功能和业务策略,BSW 提供通信、诊断、存储、操作系统和硬件抽象等基础设施。

问题 5:CAN 信号超时应该在哪一层处理?

通信栈可以按照配置监测信号接收超时并提供相关状态或替代值,但 ASW 还需要根据控制器的安全需求,判断当前输入是否可以使用,以及是否需要限制输出或进入安全状态。

问题 6:如果需要增加一个新的控制 SWC,开发流程是什么?

根据需求定义组件职责、端口、数据类型和 Runnable;维护相应 ARXML,完成组件连接及 ECU 配置;生成或更新 RTE;开发 ASW 代码;完成编译、集成以及各层级软件验证。

问题 7:假设你开发一个新能源汽车 VCU:

VCU 每 10ms 通过 CAN 收到电机的实际转速和故障状态,然后根据油门踏板计算目标扭矩,再通过 CAN 发送给电机控制器。

以前你可能自己用 FreeRTOS 创建任务,然后写 CAN 收发和控制函数。

现在如果使用 AUTOSAR Classic:

  • 应用控制算法放在哪一层?
  • CAN 接收和信号解析分别由什么模块负责?
  • 哪个部分负责组件之间交换数据?
  • 谁决定控制函数每 10ms 执行一次?
  • CAN 断线以后,谁负责检测超时,谁负责把扭矩限制为零?

在 AUTOSAR Classic 架构中,我会将 VCU 的状态机、扭矩计算和故障降级逻辑放在 ASW 层,设计对应的 SWC 和 Runnable。

电机控制器反馈的 CAN 报文,经过 MCAL 的 CAN Driver、CanIf、PduR 和 COM,由 COM 完成信号解析,再通过 RTE 接口提供给应用软件。

控制模块通过 RTE 读取油门踏板、电机转速和故障状态,计算目标扭矩。

对于 10ms 周期控制,可以配置 TimingEvent,并将 Runnable 映射到合适的 OS Task,由 AUTOSAR OS 进行调度。

通信异常方面,COM 可以监测接收超时,CAN 网络管理模块处理相应的总线状态,DEM 管理诊断事件。ASW 根据通信有效性和故障状态执行扭矩限幅、降额或者安全停机策略。

最终计算出的目标扭矩通过 RTE 交给 COM 通信栈,经过 PduR、CanIf 和 CAN Driver 发送给电机控制器。

ASW 负责控制算法,RTE 负责标准化组件接口,BSW 负责通信、诊断等基础服务,AUTOSAR OS 负责运行调度。

博客内容均系原创,未经允许严禁转载!
您可以通过 RSS 订阅本站文章更新,订阅地址:https://blognas.hwb0307.com/feed/。什么是 RSS ?
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇