17、车载空调系统:CarHvacManager、温度控制、风量调节、分区控制、自动空调逻辑

车载空调,听起来就是个「冷热风」的事。但真要在 Android Automotive OS 上把它做好,你会发现它牵扯到硬件抽象、策略仲裁、用户预期管理,甚至还有功耗和噪音的平衡。嗯,这一章我们就把空调系统拆开揉碎,从 CarHvacManager 到自动空调逻辑,一个一个说清楚。

17.1 CarHvacManager:空调控制的总线

CarHvacManager 是车载空调控制的核心 API。它不直接操作硬件,而是通过 CarPropertyManager 的机制,把空调的每一个控制项抽象成一个 Property。

我个人习惯把 CarHvacManager 理解为「空调控制的总线」。所有的温度、风量、模式、风向,都通过这个总线来读写。你想想看,如果每个空调功能都单独写一个 AIDL 接口,那系统得多乱?

核心要点: CarHvacManager 继承自 CarPropertyManager,所有空调控制都是 Property 的 get/set 操作。

举个例子,设置驾驶位温度:

CarHvacManager hvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
if (hvacManager != null) {
    // 设置驾驶位目标温度 22.0°C
    hvacManager.setFloatProperty(
        CarHvacManager.ID_ZONED_TEMP_SETPOINT,
        VehicleAreaSeat.SEAT_ROW_1_LEFT,
        22.0f
    );
}

这里有个细节:ID_ZONED_TEMP_SETPOINT 是带分区的属性,第二个参数指定了区域。如果是全局温度控制,用 ID_TEMP_SETPOINT 就行。

我的经验: 我在项目中遇到过一个问题——有些车机把「温度设置」和「温度显示」分成了两个 Property。你设了 22°C,但显示的还是 21.5°C,因为硬件有 ±0.5°C 的精度。所以读取时一定要用 getFloatProperty,而不是缓存自己的设定值。

17.2 温度控制:不只是冷和热

温度控制看起来简单,但实际落地时有很多坑。我把它拆成三个层面:

  • 目标温度: 用户设定的期望温度,比如 22°C。这是 CarHvacManager 写入的值。
  • 实际温度: 车内传感器测得的当前温度。这个值通常来自 HVAC 的 CAN 信号,通过 CarSensorManager 或 CarHvacManager 的 Property 回调获取。
  • 出风口温度: 混合风门调节后的实际出风温度。这个一般不对用户开放,但调试时很有用。

温度控制的单位,国内常用摄氏度(°C),但有些海外车型支持华氏度(°F)。CarHvacManager 的 Property 值统一用 float,单位由 OEM 在 HAL 层定义。我个人建议 HAL 层统一用摄氏度,UI 层做转换。

注意: 温度设定值有范围限制。比如有的车只能设 16°C 到 32°C,超出范围会静默截断或返回错误。一定要先调用 getPropertyRange() 获取有效范围。

17.3 风量调节:档位与自动风量

风量调节通常有两种模式:手动档位和自动风量。

手动档位就是 1 档、2 档、3 档……直到最大。CarHvacManager 用 ID_FAN_SPEED_SETPOINT 来控制,值一般是 0 到最大档位的整数。

自动风量就复杂一些。当空调处于 AUTO 模式时,风量由系统根据温差、阳光强度、车速等因素自动计算。这时候,UI 上显示的不再是档位,而是「AUTO」字样。

我记得有一次,测试反馈说「自动模式下风量忽大忽小,体验很差」。查了半天,发现是阳光传感器的数据更新频率太低,导致系统以为车内温度变化剧烈,频繁调整风量。后来我们把阳光传感器的滤波时间常数调大了,问题就解决了。

避坑指南: 我曾经在自动风量逻辑里直接用了 PID 控制,结果风量震荡得很厉害。后来改用查表法 + 低通滤波,效果反而更好。有时候,简单的算法比复杂的更可靠。

17.4 分区控制:左冷右热不是梦

分区控制是车载空调的「高级玩法」。简单说,就是驾驶位和副驾驶位可以设置不同的温度。

CarHvacManager 通过 VehicleAreaSeat 来区分区域:

  • SEAT_ROW_1_LEFT:驾驶位
  • SEAT_ROW_1_RIGHT:副驾驶位
  • SEAT_ROW_2_LEFT:后排左侧
  • SEAT_ROW_2_RIGHT:后排右侧
  • SEAT_ROW_2_CENTER:后排中间

分区控制的硬件基础是「双区风门」或「多区风门」。每个区域有独立的混合风门和温度传感器。如果硬件只支持单区,那设置分区温度时,系统会忽略区域参数,统一用一个温度。

怎么判断当前车辆支持几个分区?用 getAreaIds() 方法:

int[] areaIds = hvacManager.getAreaIds(CarHvacManager.ID_ZONED_TEMP_SETPOINT);
// areaIds 的长度就是分区数量
我的建议: 分区控制一定要做「同步/独立」切换。用户按一下「SYNC」按钮,所有分区温度跟随驾驶位。再按一下,恢复独立控制。这个交互逻辑在大多数车型上都是标配。

17.5 自动空调逻辑:从设定到舒适

自动空调的核心逻辑,说白了就是一句话:根据当前环境,自动调节温度、风量、模式、风向,让车内尽快达到并维持用户设定的舒适温度。

但实现起来,要考虑的因素很多:

输入因素 说明
车内温度 来自车内温度传感器,通常有多个
车外温度 来自车外温度传感器,影响制冷/制热策略
阳光强度 来自阳光传感器,影响制冷需求
车速 车速高时,风量可以适当降低(撞风效应)
湿度 部分高端车型有湿度传感器,用于防雾
乘客数量 通过座椅传感器判断,影响热负荷

自动空调的决策流程,我画了一张图:

自动空调控制逻辑流程图 车内温度传感器 车外温度传感器 阳光/湿度传感器 车速/乘客信息 计算温差:目标温度 - 实际温度 策略判断:制冷/制热/除湿/通风 设定目标温度 调节风量档位 切换出风模式 控制内外循环

自动空调的算法,各家 OEM 都有自己的标定数据。但大体逻辑是:

  1. 计算温差: 目标温度 - 实际温度。温差越大,需要的制冷/制热能力越强。
  2. 确定模式: 温差为正且较大时,制热模式;温差为负且较大时,制冷模式;温差较小时,通风模式。
  3. 调节风量: 根据温差绝对值查表得到基础风量,再根据阳光强度、车速做修正。
  4. 控制风门: 混合风门的位置决定了出风口温度,这个由 PID 或查表算法控制。
  5. 循环切换: 制冷时默认内循环,制热时默认外循环(防止车窗起雾)。
注意: 自动空调逻辑不要写死在 App 里。我见过一些项目把 PID 参数写在 Java 代码中,结果换一个车型就要改代码重编。正确的做法是把标定参数放在 XML 或 JSON 配置文件中,通过 CarService 加载。

17.6 避坑与最佳实践

最后,分享几个我在车载空调开发中踩过的坑:

  • Property 的同步问题: CarHvacManager 的 set 操作是异步的,不要 set 完立刻 get,可能还是旧值。用回调或轮询来确认。
  • 分区控制的 UI 反馈: 如果硬件不支持分区,但 UI 显示了两个温度调节滑块,用户会困惑。一定要根据 getAreaIds() 动态显示/隐藏分区控件。
  • 自动空调的退出条件: 用户手动调节了风量或模式,自动空调应该退出 AUTO 模式,但保留温度设定。这个逻辑很多初稿都漏了。
  • 功耗与噪音: 空调压缩机是高压部件,频繁启停会影响寿命和 NVH。自动逻辑里要加最小运行时间和最小停机时间的保护。
我的经验: 我曾经在调试自动空调时,发现风量总是比预期大。后来发现是阳光传感器的值被错误地当成了「阳光强度百分比」,而实际值是「阳光强度 W/m²」。单位搞错,整个标定表都废了。所以,一定要确认 HAL 层每个 Property 的物理单位和取值范围。

车载空调系统,说难不难,说简单也不简单。它不像多媒体那样「能出声就行」,也不像导航那样「能定位就行」。空调直接关系到乘客的舒适感,做得好是「润物细无声」,做不好就是「夏天热死、冬天冷死」。嗯,这一章的内容就到这里,希望对你有所帮助。


公众号:蓝海资料掘金营,微信deep3321