传感器子系统(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
核心知识点补充
-
传感器数据单位说明: 传感器类型 原始数据单位 常用转换 说明 加速度计 m/s² ÷9.80665 转换为重力加速度(G) 陀螺仪 rad/s ×(180/π) 转换为度/秒(°/s) 磁力计 μT(微特斯拉) - 直接表示磁场强度 -
数据处理注意事项:
- 加速度计数据包含重力分量(静止时Z轴约为9.8 m/s²),需通过滤波算法分离运动加速度和重力;
- 陀螺仪数据存在漂移,需结合加速度计/磁力计使用卡尔曼滤波、互补滤波等算法校准;
- 传感器数据更新频率较高(通常 50~200Hz),建议在独立线程中读取,避免阻塞主线程。
-
跨平台支持:
- 移动平台(Android/iOS)全面支持加速度计、陀螺仪、磁力计;
- 桌面平台(Windows/macOS)仅部分设备(如笔记本、游戏手柄)支持传感器;
- 游戏手柄的传感器可通过
SDL_GamepadHasSensor/SDL_GetGamepadSensorData接口访问。
总结
- 核心特性:
- SDL 统一封装了不同平台的传感器接口,无需关注底层驱动和数据格式差异;
- 支持加速度计、陀螺仪、磁力计等主流传感器类型,数据单位标准化;
SDL_STANDARD_GRAVITY宏提供标准重力加速度,方便单位转换;
- 使用建议:
- 初始化时必须传入
SDL_INIT_SENSOR标志,否则传感器接口无法使用; - 读取数据前需检查传感器是否成功打开,避免空指针访问;
- 传感器数据需做滤波/校准处理,提升数据稳定性和准确性;
- 初始化时必须传入
- 关键接口:
- 设备枚举:
SDL_GetSensors获取所有传感器ID; - 设备操作:
SDL_OpenSensor/SDL_CloseSensor打开/关闭传感器; - 数据读取:
SDL_GetSensorData获取最新传感器数据。
- 设备枚举:
评论一下?