sensor-sdk 0.0.50__tar.gz → 0.0.52__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {sensor_sdk-0.0.50/sensor_sdk.egg-info → sensor_sdk-0.0.52}/PKG-INFO +1 -1
  2. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/sensor_controller.py +1 -0
  3. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/sensor_data_context.py +82 -30
  4. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/sensor_profile.py +3 -1
  5. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52/sensor_sdk.egg-info}/PKG-INFO +1 -1
  6. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/setup.py +1 -1
  7. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/LICENSE.txt +0 -0
  8. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/README.md +0 -0
  9. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/__init__.py +0 -0
  10. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/bleak_host.py +0 -0
  11. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/bleak_process.py +0 -0
  12. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/gforce.py +0 -0
  13. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/sensor_data.py +0 -0
  14. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/sensor_device.py +0 -0
  15. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor/sensor_utils.py +0 -0
  16. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor_sdk.egg-info/SOURCES.txt +0 -0
  17. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor_sdk.egg-info/dependency_links.txt +0 -0
  18. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor_sdk.egg-info/requires.txt +0 -0
  19. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor_sdk.egg-info/top_level.txt +0 -0
  20. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/sensor_sdk.egg-info/zip-safe +0 -0
  21. {sensor_sdk-0.0.50 → sensor_sdk-0.0.52}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sensor-sdk
3
- Version: 0.0.50
3
+ Version: 0.0.52
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -137,6 +137,7 @@ class SensorController:
137
137
  if mac is None:
138
138
  continue
139
139
  if deviceMap.get(mac) is not None:
140
+ self._sensor_profiles[mac].BLEDevice.RSSI = serialized.get("rssi")
140
141
  devices.append(self._sensor_profiles[mac].BLEDevice)
141
142
  else:
142
143
  newSensor = SensorProfile(serialized=serialized, bleak_host=self._bleak_host)
@@ -76,7 +76,10 @@ class SensorProfileDataCtx:
76
76
 
77
77
  # Quaternion support
78
78
  self.isContainQAT6 = False
79
-
79
+ self.lastQuatData: List[float] = [0.0, 0.0, 0.0, 0.0]
80
+ self.lastEulerData: List[float] = [0.0, 0.0, 0.0]
81
+ self.lastAccData: List[float] = [0.0, 0.0, 0.0]
82
+ self.lastGyroData: List[float] = [0.0, 0.0, 0.0]
80
83
  # PPG configuration
81
84
  self.model = PPGDataMode.PPG_RAW
82
85
 
@@ -323,6 +326,7 @@ class SensorProfileDataCtx:
323
326
 
324
327
  async def initIMU(self, packageCount: int) -> int:
325
328
  IMU_TYPE_QAT6 = 0x0004
329
+ min_package_sample_count = 2
326
330
  self.isContainQAT6 = False
327
331
  config = await self.gForce.get_imu_raw_data_config()
328
332
  imu_cap = await self.gForce.get_imu_cap_data_config()
@@ -339,7 +343,7 @@ class SensorProfileDataCtx:
339
343
  data.resolutionBits = 16
340
344
  data.channelCount = 3
341
345
  data.channelMask = 255
342
- data.minPackageSampleCount = 1
346
+ data.minPackageSampleCount = min_package_sample_count
343
347
  data.packageSampleCount = config.batch_len
344
348
  data.K = config.accK
345
349
  data.clear()
@@ -352,7 +356,7 @@ class SensorProfileDataCtx:
352
356
  data.resolutionBits = 16
353
357
  data.channelCount = 3
354
358
  data.channelMask = 255
355
- data.minPackageSampleCount = 1
359
+ data.minPackageSampleCount = min_package_sample_count
356
360
  data.packageSampleCount = config.batch_len
357
361
  data.K = config.gyroK
358
362
  data.clear()
@@ -367,12 +371,26 @@ class SensorProfileDataCtx:
367
371
  data.resolutionBits = 32
368
372
  data.channelCount = 4 # w, x, y, z
369
373
  data.channelMask = 15 # 0b1111
370
- data.minPackageSampleCount = 1
374
+ data.minPackageSampleCount = min_package_sample_count
371
375
  data.packageSampleCount = config.batch_len
372
376
  data.K = 1.0 / 1073741824.0 # 1 / 2^30
373
377
  data.clear()
374
378
  self.sensorDatas[SensorDataType.DATA_TYPE_QUATERNION] = data
375
379
 
380
+ data = SensorData()
381
+ data.deviceMac = self.deviceMac
382
+ data.dataType = DataType.NTF_EULER_DATA
383
+ data.sampleRate = config.fs
384
+ data.resolutionBits = 32 # float32
385
+ data.channelCount = 3 # pitch, roll, yaw
386
+ data.channelMask = 0b0111
387
+ data.packageIndexLength = 0
388
+ data.minPackageSampleCount = min_package_sample_count
389
+ data.packageSampleCount = config.batch_len
390
+ data.K = 1.0
391
+ data.clear()
392
+ self.sensorDatas[SensorDataType.DATA_TYPE_EULER] = data
393
+
376
394
  self.notifyDataFlag |= DataSubscription.DNF_IMU
377
395
 
378
396
  return config.channel_count
@@ -389,7 +407,7 @@ class SensorProfileDataCtx:
389
407
  data.channelCount = 3 # roll, pitch, yaw
390
408
  data.channelMask = 0b0111
391
409
  data.packageIndexLength = 0
392
- data.minPackageSampleCount = packageCount
410
+ data.minPackageSampleCount = 2
393
411
  data.packageSampleCount = 1
394
412
  data.K = 1.0
395
413
  data.clear()
@@ -409,7 +427,7 @@ class SensorProfileDataCtx:
409
427
  data.channelCount = 4 # w, x, y, z
410
428
  data.channelMask = 0b1111
411
429
  data.packageIndexLength = 0
412
- data.minPackageSampleCount = packageCount
430
+ data.minPackageSampleCount = 2
413
431
  data.packageSampleCount = 1
414
432
  data.K = 1.0
415
433
  data.clear()
@@ -427,7 +445,7 @@ class SensorProfileDataCtx:
427
445
  data.channelCount = 3 # x, y, z
428
446
  data.channelMask = 0b0111
429
447
  data.packageIndexLength = 1
430
- data.minPackageSampleCount = packageCount
448
+ data.minPackageSampleCount = 2
431
449
  data.packageSampleCount = 1
432
450
  data.K = 1.0
433
451
  data.clear()
@@ -445,7 +463,7 @@ class SensorProfileDataCtx:
445
463
  data.channelCount = 3 # x, y, z
446
464
  data.channelMask = 0b0111
447
465
  data.packageIndexLength = 1
448
- data.minPackageSampleCount = packageCount
466
+ data.minPackageSampleCount = 2
449
467
  data.packageSampleCount = 1
450
468
  data.K = 1.0
451
469
  data.clear()
@@ -479,7 +497,7 @@ class SensorProfileDataCtx:
479
497
  data.resolutionBits = 8
480
498
  data.channelCount = 1
481
499
  data.channelMask = 1
482
- data.minPackageSampleCount = 1
500
+ data.minPackageSampleCount = 2
483
501
  data.packageSampleCount = 1
484
502
  data.K = 1
485
503
  data.packageIndexLength = 2
@@ -549,7 +567,11 @@ class SensorProfileDataCtx:
549
567
  info.GyroChannelCount = 3
550
568
  info.AccSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_ACC].sampleRate
551
569
  info.GyroSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_GYRO].sampleRate
552
-
570
+ if self.isContainQAT6:
571
+ info.QuatChannelCount = 4
572
+ info.EulerChannelCount = 3
573
+ info.QuatSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_QUATERNION].sampleRate
574
+ info.EulerSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_EULER].sampleRate
553
575
 
554
576
  if self.hasEuler() and (self.init_map["NTF_GFORCE_EULER"] == "ON"):
555
577
  info.EulerChannelCount = await self.initEuler(packageCount)
@@ -686,7 +708,8 @@ class SensorProfileDataCtx:
686
708
  break
687
709
  if not sensor_utils._terminated and sensorData != None and on_data_callback != None:
688
710
  try:
689
- asyncio.get_event_loop().run_in_executor(self.dataPool, on_data_callback, sensorData)
711
+ on_data_callback(sensorData)
712
+ # asyncio.get_event_loop().run_in_executor(self.dataPool, on_data_callback, sensorData)
690
713
  except Exception as e:
691
714
  pass
692
715
 
@@ -818,16 +841,12 @@ class SensorProfileDataCtx:
818
841
  elif v == DataType.NTF_SPO2:
819
842
  self._process_spo2_data(data, buf)
820
843
  elif v == DataType.NTF_EULER_DATA:
821
-
822
844
  self._process_gforce_float_data(data, buf, SensorDataType.DATA_TYPE_EULER, 3)
823
845
  elif v == DataType.NTF_QUATERNION:
824
-
825
846
  self._process_gforce_float_data(data, buf, SensorDataType.DATA_TYPE_GFORCE_QUAT, 4)
826
847
  elif v == DataType.NTF_ACC:
827
-
828
848
  self._process_gforce_int_data(data, buf, SensorDataType.DATA_TYPE_ACC, 3)
829
849
  elif v == DataType.NTF_GYRO:
830
-
831
850
  self._process_gforce_int_data(data, buf, SensorDataType.DATA_TYPE_GYRO, 3)
832
851
 
833
852
  def _process_gforce_float_data(self, data: bytes, buf: Queue[SensorData],
@@ -838,9 +857,9 @@ class SensorProfileDataCtx:
838
857
 
839
858
  EXPECTED_SIZE = HEADER_SIZE + channel_count * FLOAT_SIZE
840
859
 
841
- print(f"[DataTask] 异常: len(data){len(data)} ")
842
-
860
+
843
861
  if len(data) != EXPECTED_SIZE:
862
+ print(f"[DataTask] 异常: len(data){len(data)} ")
844
863
  return
845
864
 
846
865
  sensor_data = self.sensorDatas[data_type_index]
@@ -927,8 +946,8 @@ class SensorProfileDataCtx:
927
946
  sample.isLost = False
928
947
  sensor_data.channelSamples[ch].append(sample)
929
948
 
930
- type_name = "ACC" if data[0] & 0x7F == DataType.NTF_ACC else "GYRO"
931
- print(f"[{type_name}] pkgIdx={pkg_index} x={channel_values[0]} y={channel_values[1]} z={channel_values[2]}")
949
+ # type_name = "ACC" if data[0] & 0x7F == DataType.NTF_ACC else "GYRO"
950
+ # print(f"[{type_name}] pkgIdx={pkg_index} x={channel_values[0]} y={channel_values[1]} z={channel_values[2]}")
932
951
 
933
952
  sensor_data.lastPackageCounter += 1
934
953
  self.sendSensorData(sensor_data, buf)
@@ -988,17 +1007,20 @@ class SensorProfileDataCtx:
988
1007
  sensor_data_acc = self.sensorDatas[SensorDataType.DATA_TYPE_ACC]
989
1008
  sensor_data_gyro = self.sensorDatas[SensorDataType.DATA_TYPE_GYRO]
990
1009
  sensor_data_quat = None
1010
+ sensor_data_euler = None
991
1011
 
992
1012
  sensor_datas = [sensor_data_acc, sensor_data_gyro]
993
1013
  if self.isContainQAT6:
994
1014
  sensor_data_quat = self.sensorDatas[SensorDataType.DATA_TYPE_QUATERNION]
1015
+ sensor_data_euler = self.sensorDatas[SensorDataType.DATA_TYPE_EULER]
995
1016
  sensor_datas.append(sensor_data_quat)
1017
+ sensor_datas.append(sensor_data_euler)
996
1018
 
997
- if self._check_read_imu_samples(data, sensor_datas, sensor_data_quat, on_error_callback):
1019
+ if self._check_read_imu_samples(data, sensor_datas, sensor_data_quat, sensor_data_euler, on_error_callback):
998
1020
  for sensor_data in sensor_datas:
999
1021
  self.sendSensorData(sensor_data, buf)
1000
1022
 
1001
- def _check_read_imu_samples(self, data: bytes, sensor_datas: List[SensorData], sensor_data_quat, on_error_callback=None):
1023
+ def _check_read_imu_samples(self, data: bytes, sensor_datas: List[SensorData], sensor_data_quat, sensor_data_euler,on_error_callback=None):
1002
1024
  if not self._is_data_transfering or not sensor_datas:
1003
1025
  return False
1004
1026
 
@@ -1079,7 +1101,7 @@ class SensorProfileDataCtx:
1079
1101
  for sensor_data in sensor_datas:
1080
1102
  sensor_data.lastPackageIndex = newPackageIndex
1081
1103
 
1082
- if not self._read_imu_frame_samples(data, sensor_datas, sensor_data_quat, offset, 0):
1104
+ if not self._read_imu_frame_samples(data, sensor_datas, sensor_data_quat, sensor_data_euler, offset, 0):
1083
1105
  return False
1084
1106
 
1085
1107
  for sensor_data in sensor_datas:
@@ -1107,6 +1129,7 @@ class SensorProfileDataCtx:
1107
1129
  data: bytes,
1108
1130
  sensor_datas: List[SensorData],
1109
1131
  sensor_data_quat: SensorData,
1132
+ sensor_data_euler: SensorData,
1110
1133
  dataOffset: int,
1111
1134
  lostSampleCount: int,
1112
1135
  ) -> bool:
@@ -1134,10 +1157,11 @@ class SensorProfileDataCtx:
1134
1157
  sampleIndex = lastSampleIndex + sampleOffset
1135
1158
 
1136
1159
  if lostSampleCount > 0:
1137
- self._append_imu_vector_sample(sensor_data_acc, sampleIndex, [0, 0, 0], True)
1138
- self._append_imu_vector_sample(sensor_data_gyro, sampleIndex, [0, 0, 0], True)
1160
+ self._append_imu_vector_sample(sensor_data_acc, sampleIndex, self.lastAccData, True)
1161
+ self._append_imu_vector_sample(sensor_data_gyro, sampleIndex, self.lastGyroData, True)
1139
1162
  if sensor_data_quat is not None:
1140
- self._append_imu_quaternion_sample(sensor_data_quat, sampleIndex, [0, 0, 0], True)
1163
+ self._append_imu_quaternion_sample(sensor_data_quat, sensor_data_euler, sampleIndex, self.lastQuatData, True)
1164
+
1141
1165
  continue
1142
1166
 
1143
1167
  accRaw = [
@@ -1145,15 +1169,17 @@ class SensorProfileDataCtx:
1145
1169
  struct.unpack_from("<h", data, offset + 2)[0],
1146
1170
  struct.unpack_from("<h", data, offset + 4)[0],
1147
1171
  ]
1172
+ self.lastAccData = accRaw.copy()
1148
1173
  gyroOffset = offset + 6
1149
1174
  gyroRaw = [
1150
1175
  struct.unpack_from("<h", data, gyroOffset)[0],
1151
1176
  struct.unpack_from("<h", data, gyroOffset + 2)[0],
1152
1177
  struct.unpack_from("<h", data, gyroOffset + 4)[0],
1153
1178
  ]
1179
+ self.lastGyroData = gyroRaw.copy()
1154
1180
 
1155
- self._append_imu_vector_sample(sensor_data_acc, sampleIndex, accRaw, False)
1156
- self._append_imu_vector_sample(sensor_data_gyro, sampleIndex, gyroRaw, False)
1181
+ self._append_imu_vector_sample(sensor_data_acc, sampleIndex, self.lastAccData, False)
1182
+ self._append_imu_vector_sample(sensor_data_gyro, sampleIndex, self.lastGyroData, False)
1157
1183
 
1158
1184
  if sensor_data_quat is not None:
1159
1185
  quatOffset = offset + 12
@@ -1162,7 +1188,7 @@ class SensorProfileDataCtx:
1162
1188
  struct.unpack_from("<i", data, quatOffset + 4)[0],
1163
1189
  struct.unpack_from("<i", data, quatOffset + 8)[0],
1164
1190
  ]
1165
- self._append_imu_quaternion_sample(sensor_data_quat, sampleIndex, quatRaw, False)
1191
+ self._append_imu_quaternion_sample(sensor_data_quat, sensor_data_euler, sampleIndex, quatRaw, False)
1166
1192
 
1167
1193
  offset += frameSize
1168
1194
 
@@ -1191,6 +1217,7 @@ class SensorProfileDataCtx:
1191
1217
  def _append_imu_quaternion_sample(
1192
1218
  self,
1193
1219
  sensor_data_quat: SensorData,
1220
+ sensor_data_euler: SensorData,
1194
1221
  sampleIndex: int,
1195
1222
  rawValues: List[int],
1196
1223
  isLost: bool,
@@ -1200,16 +1227,25 @@ class SensorProfileDataCtx:
1200
1227
 
1201
1228
  raw = [0, 0, 0, 0]
1202
1229
  value = [0.0, 0.0, 0.0, 0.0]
1230
+ euler = [0.0, 0.0, 0.0]
1203
1231
 
1204
1232
  if not isLost:
1205
1233
  raw[1] = rawValues[0]
1206
1234
  raw[2] = rawValues[1]
1207
1235
  raw[3] = rawValues[2]
1236
+
1208
1237
  value[1] = raw[1] / scale
1209
1238
  value[2] = raw[2] / scale
1210
1239
  value[3] = raw[3] / scale
1211
1240
  value[0] = math.sqrt(max(0.0, 1.0 - value[1] ** 2 - value[2] ** 2 - value[3] ** 2))
1212
1241
 
1242
+ euler[0] = math.atan2(2 * (value[0] * value[1] + value[2] * value[3]), 1 - 2 * (value[1] ** 2 + value[2] ** 2)) * 180 / math.pi
1243
+ euler[1] = math.asin(max(-1.0, min(1.0, 2 * (value[0] * value[2] - value[3] * value[1])))) * 180 / math.pi
1244
+ euler[2] = math.atan2(2 * (value[0] * value[3] + value[1] * value[2]), 1 - 2 * (value[2] ** 2 + value[3] ** 2)) * 180 / math.pi
1245
+
1246
+ self.lastQuatData = value.copy()
1247
+ self.lastEulerData = euler.copy()
1248
+
1213
1249
  for channelIndex in range(sensor_data_quat.channelCount):
1214
1250
  if (sensor_data_quat.channelMask & (1 << channelIndex)) == 0:
1215
1251
  continue
@@ -1219,12 +1255,27 @@ class SensorProfileDataCtx:
1219
1255
  sample.sampleIndex = sampleIndex
1220
1256
  sample.timeStampInMs = sampleIndex * sampleInterval
1221
1257
  sample.rawData = raw[channelIndex]
1222
- sample.data = value[channelIndex]
1258
+ sample.data = self.lastQuatData[channelIndex]
1223
1259
  sample.impedance = 0.0
1224
1260
  sample.saturation = 0.0
1225
1261
  sample.isLost = isLost
1226
1262
  sensor_data_quat.channelSamples[channelIndex].append(sample)
1227
1263
 
1264
+ for channelIndex in range(sensor_data_euler.channelCount):
1265
+ if (sensor_data_euler.channelMask & (1 << channelIndex)) == 0:
1266
+ continue
1267
+
1268
+ sample = Sample()
1269
+ sample.channelIndex = channelIndex
1270
+ sample.sampleIndex = sampleIndex
1271
+ sample.timeStampInMs = sampleIndex * sampleInterval
1272
+ sample.rawData = raw[channelIndex]
1273
+ sample.data = self.lastEulerData[channelIndex]
1274
+ sample.impedance = 0.0
1275
+ sample.saturation = 0.0
1276
+ sample.isLost = isLost
1277
+ sensor_data_euler.channelSamples[channelIndex].append(sample)
1278
+
1228
1279
  def checkReadSamples(self, data: bytes, sensorData: SensorData, dataOffset: int, dataGap: int, on_error_callback=None):
1229
1280
  offset = 1
1230
1281
 
@@ -1489,7 +1540,8 @@ class SensorProfileDataCtx:
1489
1540
  break
1490
1541
  if not sensor_utils._terminated and sensorData != None and on_data_callback != None:
1491
1542
  try:
1492
- asyncio.get_event_loop().run_in_executor(self.dataPool, on_data_callback, sensorData)
1543
+ on_data_callback(sensorData)
1544
+ # asyncio.get_event_loop().run_in_executor(self.dataPool, on_data_callback, sensorData)
1493
1545
  except Exception as e:
1494
1546
  raise RuntimeError("Data callback %s fail: %s" % (self._device_info.DeviceName, e))
1495
1547
 
@@ -127,7 +127,9 @@ class SensorProfile:
127
127
  new_state = _STATE_NAME_MAP.get(state_name, self._device_state)
128
128
  self._set_device_state(new_state)
129
129
  elif msg_type == "power_changed":
130
- self._power = msg.get("power", -1)
130
+ power = msg.get("power", -1)
131
+ if power < self._power or self._power == -1:
132
+ self._power = power
131
133
  if self._on_power_changed is not None:
132
134
  try:
133
135
  self._on_power_changed(self, self._power)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sensor-sdk
3
- Version: 0.0.50
3
+ Version: 0.0.52
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, "README.md"), "r", encoding="utf-8") as f
8
8
 
9
9
  setup(
10
10
  name="sensor-sdk",
11
- version="0.0.50",
11
+ version="0.0.52",
12
12
  description="Python sdk for Synchroni",
13
13
  long_description=long_description,
14
14
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes