SDL3_API分类参考_传感器(CategorySensor)

2026-3-6 / 0 评论 / 4 阅读

传感器子系统(CategorySensor)

SDL 提供的传感器管理模块,可访问不同平台设备上的陀螺仪、加速度计等传感器硬件,获取设备的运动、姿态等物理数据。

基础使用前提

调用 SDL_Init() 初始化时必须传入 SDL_INIT_SENSOR 标志,SDL 会扫描系统中的传感器设备并加载对应的驱动程序,之后才能正常使用传感器相关接口。


函数

  • SDL_CloseSensor:关闭已打开的传感器设备(释放传感器资源,停止数据采集)
  • SDL_GetSensorData:获取传感器的最新数据(传入数据缓冲区,返回三轴/多轴的物理测量值)
  • SDL_GetSensorFromID:通过传感器ID获取对应的 SDL_Sensor 指针(用于后续操作该传感器)
  • SDL_GetSensorID:获取已打开传感器的唯一标识ID
  • SDL_GetSensorName:获取已打开传感器的设备名称(如 "Gyroscope"、"Accelerometer")
  • SDL_GetSensorNameForID:通过传感器ID获取设备名称
  • SDL_GetSensorNonPortableType:获取传感器的非可移植类型标识(平台相关的硬件类型编码)
  • SDL_GetSensorNonPortableTypeForID:通过传感器ID获取非可移植类型标识
  • SDL_GetSensorProperties:获取传感器的属性集合(如数据更新频率、精度等)
  • SDL_GetSensors:枚举系统中所有可用的传感器设备(返回传感器ID列表及数量)
  • SDL_GetSensorType:获取已打开传感器的标准化类型(如陀螺仪、加速度计、磁力计)
  • SDL_GetSensorTypeForID:通过传感器ID获取标准化类型
  • SDL_OpenSensor:打开指定ID的传感器设备(返回 SDL_Sensor 指针,开始采集数据)
  • SDL_UpdateSensors:强制更新所有传感器的状态(SDL 内部自动调用,一般无需手动执行)

数据类型

  • SDL_Sensor:传感器设备句柄类型(标识已打开的传感器设备)
  • SDL_SensorID:传感器唯一标识类型(区分系统中的不同传感器设备)

结构体

  • (无)

枚举

  • SDL_SensorType:传感器类型枚举(SDL_SENSOR_ACCELEROMETER 加速度计、SDL_SENSOR_GYROSCOPE 陀螺仪、SDL_SENSOR_MAGNETOMETER 磁力计等)

  • SDL_STANDARD_GRAVITY:标准重力加速度常量(值为 9.80665,用于加速度计数据的单位转换)

FreeBASIC 示例代码

' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"

' 传感器数据存储结构体
Type SensorData
    accelerometer As Single(0 To 2) ' 加速度计数据(X/Y/Z轴,单位:m/s²)
    gyroscope As Single(0 To 2)     ' 陀螺仪数据(X/Y/Z轴,单位:rad/s)
    magnetometer As Single(0 To 2)  ' 磁力计数据(X/Y/Z轴,单位:μT)
    accelUpdated As Boolean         ' 加速度计数据是否更新
    gyroUpdated As Boolean          ' 陀螺仪数据是否更新
    magUpdated As Boolean           ' 磁力计数据是否更新
End Type

Dim Shared As SensorData sensorData
Dim Shared As SDL_Sensor Ptr accelSensor = NULL
Dim Shared As SDL_Sensor Ptr gyroSensor = NULL
Dim Shared As SDL_Sensor Ptr magSensor = NULL

' 初始化传感器数据
Sub InitSensorData()
    sensorData.accelerometer(0) = 0.0 : sensorData.accelerometer(1) = 0.0 : sensorData.accelerometer(2) = 0.0
    sensorData.gyroscope(0) = 0.0 : sensorData.gyroscope(1) = 0.0 : sensorData.gyroscope(2) = 0.0
    sensorData.magnetometer(0) = 0.0 : sensorData.magnetometer(1) = 0.0 : sensorData.magnetometer(2) = 0.0
    sensorData.accelUpdated = False
    sensorData.gyroUpdated = False
    sensorData.magUpdated = False
End Sub

' 枚举并打开可用传感器
Function OpenAvailableSensors() As Boolean
    Dim As Integer sensorCount = SDL_GetSensors(0, NULL)
    If (sensorCount = 0) Then
        SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "系统未检测到任何传感器设备")
        Return False
    End If

    ' 分配内存存储传感器ID
    Dim As SDL_SensorID Ptr sensorIDs = Callocate(sensorCount * SizeOf(SDL_SensorID))
    If (sensorIDs = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "分配传感器ID内存失败")
        Return False
    End If

    ' 获取所有传感器ID
    sensorCount = SDL_GetSensors(sensorCount, sensorIDs)
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "检测到 %d 个传感器设备", sensorCount)

    ' 遍历传感器,打开需要的类型
    For i As Integer = 0 To sensorCount - 1
        Dim As SDL_SensorType type = SDL_GetSensorTypeForID(sensorIDs[i])
        Dim As ZString Ptr name = SDL_GetSensorNameForID(sensorIDs[i])

        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "传感器 %d:名称=%s,类型=%d", i, name, type)

        ' 打开对应类型的传感器
        Select Case type
            Case SDL_SENSOR_ACCELEROMETER
                If (accelSensor = NULL) Then
                    accelSensor = SDL_OpenSensor(sensorIDs[i])
                    If (accelSensor <> NULL) Then
                        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "成功打开加速度计传感器")
                    Else
                        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "打开加速度计失败:%s", SDL_GetError())
                    End If
                End If
            Case SDL_SENSOR_GYROSCOPE
                If (gyroSensor = NULL) Then
                    gyroSensor = SDL_OpenSensor(sensorIDs[i])
                    If (gyroSensor <> NULL) Then
                        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "成功打开陀螺仪传感器")
                    Else
                        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "打开陀螺仪失败:%s", SDL_GetError())
                    End If
                End If
            Case SDL_SENSOR_MAGNETOMETER
                If (magSensor = NULL) Then
                    magSensor = SDL_OpenSensor(sensorIDs[i])
                    If (magSensor <> NULL) Then
                        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "成功打开磁力计传感器")
                    Else
                        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "打开磁力计失败:%s", SDL_GetError())
                    End If
                End If
        End Select

        If (name <> NULL) Then SDL_free(name)
    Next

    Deallocate(sensorIDs)

    ' 检查是否至少打开了一个传感器
    Return (accelSensor <> NULL) Or (gyroSensor <> NULL) Or (magSensor <> NULL)
End Function

' 读取传感器数据
Sub ReadSensorData()
    ' 读取加速度计数据(原始值单位为 m/s²,已包含重力)
    If (accelSensor <> NULL) Then
        Dim As Single data(0 To 2)
        If (SDL_GetSensorData(accelSensor, @data[0], 3, 0) = 0) Then
            sensorData.accelerometer(0) = data(0)
            sensorData.accelerometer(1) = data(1)
            sensorData.accelerometer(2) = data(2)
            sensorData.accelUpdated = True
        End If
    End If

    ' 读取陀螺仪数据(原始值单位为 rad/s)
    If (gyroSensor <> NULL) Then
        Dim As Single data(0 To 2)
        If (SDL_GetSensorData(gyroSensor, @data[0], 3, 0) = 0) Then
            sensorData.gyroscope(0) = data(0)
            sensorData.gyroscope(1) = data(1)
            sensorData.gyroscope(2) = data(2)
            sensorData.gyroUpdated = True
        End If
    End If

    ' 读取磁力计数据(原始值单位为 μT)
    If (magSensor <> NULL) Then
        Dim As Single data(0 To 2)
        If (SDL_GetSensorData(magSensor, @data[0], 3, 0) = 0) Then
            sensorData.magnetometer(0) = data(0)
            sensorData.magnetometer(1) = data(1)
            sensorData.magnetometer(2) = data(2)
            sensorData.magUpdated = True
        End If
    End If
End Sub

' 打印传感器数据(每秒打印一次)
Sub PrintSensorData(ByVal frameCount As Integer)
    Static As Integer lastPrintFrame = 0
    If (frameCount - lastPrintFrame < 60) Then Return ' 约60FPS,每秒打印一次

    lastPrintFrame = frameCount

    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "==== 传感器数据 ====")

    If (sensorData.accelUpdated) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
            "加速度计 (m/s²):X=%.2f, Y=%.2f, Z=%.2f | 重力分量:%.2fG", _
            sensorData.accelerometer(0), sensorData.accelerometer(1), sensorData.accelerometer(2), _
            Sqr(sensorData.accelerometer(0)^2 + sensorData.accelerometer(1)^2 + sensorData.accelerometer(2)^2) / SDL_STANDARD_GRAVITY)
        sensorData.accelUpdated = False
    End If

    If (sensorData.gyroUpdated) Then
        ' 转换为度/秒(rad/s × (180/π))
        Dim As Single gyroX = sensorData.gyroscope(0) * (180 / 3.14159265)
        Dim As Single gyroY = sensorData.gyroscope(1) * (180 / 3.14159265)
        Dim As Single gyroZ = sensorData.gyroscope(2) * (180 / 3.14159265)

        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
            "陀螺仪 (°/s):X=%.2f, Y=%.2f, Z=%.2f", gyroX, gyroY, gyroZ)
        sensorData.gyroUpdated = False
    End If

    If (sensorData.magUpdated) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
            "磁力计 (μT):X=%.2f, Y=%.2f, Z=%.2f | 磁场强度:%.2fμT", _
            sensorData.magnetometer(0), sensorData.magnetometer(1), sensorData.magnetometer(2), _
            Sqr(sensorData.magnetometer(0)^2 + sensorData.magnetometer(1)^2 + sensorData.magnetometer(2)^2))
        sensorData.magUpdated = False
    End If
End Sub

' 主程序
Dim As SDL_Window Ptr window = NULL
Dim As SDL_Event evt
Dim As Boolean quit = False
Dim As Integer frameCount = 0

' 1. 初始化 SDL(必须包含 SENSOR 标志)
If (SDL_Init(SDL_INIT_VIDEO Or SDL_INIT_SENSOR) < 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
    End 1
End If

' 2. 创建窗口
window = SDL_CreateWindow("SDL 传感器数据读取示例", _
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
    800, 600, SDL_WINDOW_SHOWN)
If (window = NULL) Then
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError())
    SDL_Quit()
    End 1
End If

' 3. 初始化传感器数据并打开可用传感器
InitSensorData()
If (Not OpenAvailableSensors()) Then
    SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "未打开任何传感器,程序仍会运行但无数据输出")
End If

SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== SDL 传感器示例 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "提示:移动设备查看传感器数据变化 | ESC:退出")

' 4. 主循环
While (Not quit)
    frameCount += 1

    ' 处理事件队列
    While (SDL_PollEvent(@evt))
        Select Case evt.type
            Case SDL_QUITEVENT
                quit = True

            Case SDL_EVENT_KEY_DOWN
                If (evt.key.scancode = SDL_SCANCODE_ESCAPE) Then
                    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按下 ESC,退出程序")
                    quit = True
                End If
        End Select
    Wend

    ' 读取传感器数据
    ReadSensorData()

    ' 定期打印传感器数据
    PrintSensorData(frameCount)

    SDL_Delay(16) ' 约60FPS
Wend

' 5. 清理资源
If (accelSensor <> NULL) Then SDL_CloseSensor(accelSensor)
If (gyroSensor <> NULL) Then SDL_CloseSensor(gyroSensor)
If (magSensor <> NULL) Then SDL_CloseSensor(magSensor)

SDL_DestroyWindow(window)
SDL_Quit()

SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出")
End 0

核心知识点补充

  1. 传感器数据单位说明 传感器类型 原始数据单位 常用转换 说明
    加速度计 m/s² ÷9.80665 转换为重力加速度(G)
    陀螺仪 rad/s ×(180/π) 转换为度/秒(°/s)
    磁力计 μT(微特斯拉) - 直接表示磁场强度
  2. 数据处理注意事项

    • 加速度计数据包含重力分量(静止时Z轴约为9.8 m/s²),需通过滤波算法分离运动加速度和重力;
    • 陀螺仪数据存在漂移,需结合加速度计/磁力计使用卡尔曼滤波、互补滤波等算法校准;
    • 传感器数据更新频率较高(通常 50~200Hz),建议在独立线程中读取,避免阻塞主线程。
  3. 跨平台支持

    • 移动平台(Android/iOS)全面支持加速度计、陀螺仪、磁力计;
    • 桌面平台(Windows/macOS)仅部分设备(如笔记本、游戏手柄)支持传感器;
    • 游戏手柄的传感器可通过 SDL_GamepadHasSensor/SDL_GetGamepadSensorData 接口访问。

总结

  1. 核心特性
    • SDL 统一封装了不同平台的传感器接口,无需关注底层驱动和数据格式差异;
    • 支持加速度计、陀螺仪、磁力计等主流传感器类型,数据单位标准化;
    • SDL_STANDARD_GRAVITY 宏提供标准重力加速度,方便单位转换;
  2. 使用建议
    • 初始化时必须传入 SDL_INIT_SENSOR 标志,否则传感器接口无法使用;
    • 读取数据前需检查传感器是否成功打开,避免空指针访问;
    • 传感器数据需做滤波/校准处理,提升数据稳定性和准确性;
  3. 关键接口
    • 设备枚举:SDL_GetSensors 获取所有传感器ID;
    • 设备操作:SDL_OpenSensor/SDL_CloseSensor 打开/关闭传感器;
    • 数据读取:SDL_GetSensorData 获取最新传感器数据。

评论一下?

OωO
取消