Joint-python-library 0.0.6__tar.gz → 0.0.8__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 (22) hide show
  1. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/Joint_python_library.egg-info/PKG-INFO +1 -1
  2. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/PKG-INFO +1 -1
  3. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/acrome_joint/Slave_Device.py +109 -1
  4. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/acrome_joint/joint.py +115 -3
  5. joint_python_library-0.0.8/gui/joint_device.py +14 -0
  6. joint_python_library-0.0.8/gui/limits.py +18 -0
  7. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/gui/main.py +1 -0
  8. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/setup.py +1 -1
  9. joint_python_library-0.0.6/gui/joint_device.py +0 -6
  10. joint_python_library-0.0.6/gui/limits.py +0 -17
  11. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/Joint_python_library.egg-info/SOURCES.txt +0 -0
  12. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/Joint_python_library.egg-info/dependency_links.txt +0 -0
  13. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/Joint_python_library.egg-info/entry_points.txt +0 -0
  14. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/Joint_python_library.egg-info/requires.txt +0 -0
  15. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/Joint_python_library.egg-info/top_level.txt +0 -0
  16. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/LICENSE +0 -0
  17. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/README.md +0 -0
  18. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/acrome_joint/__init__.py +0 -0
  19. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/acrome_joint/serial_port.py +0 -0
  20. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/gui/__init__.py +0 -0
  21. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/gui/ramp_trajectory.py +0 -0
  22. {joint_python_library-0.0.6 → joint_python_library-0.0.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Joint-python-library
3
- Version: 0.0.6
3
+ Version: 0.0.8
4
4
  Summary: Python library for interfacing with Acrome Robotic Arm Joint BLDC Motor Controllers. This Python library provides an easy-to-use interface for communication and control of BLDC motor controllers used in Acrome robotic arm joints. It is designed to simplify the integration of Acrome’s robotic joint actuators into custom applications, allowing developers and researchers to focus on building advanced robotic systems without dealing with low-level communication details.
5
5
  Home-page: https://github.com/Acrome-Smart-Motion-Devices/python-library-new
6
6
  Author: BeratComputer
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Joint-python-library
3
- Version: 0.0.6
3
+ Version: 0.0.8
4
4
  Summary: Python library for interfacing with Acrome Robotic Arm Joint BLDC Motor Controllers. This Python library provides an easy-to-use interface for communication and control of BLDC motor controllers used in Acrome robotic arm joints. It is designed to simplify the integration of Acrome’s robotic joint actuators into custom applications, allowing developers and researchers to focus on building advanced robotic systems without dealing with low-level communication details.
5
5
  Home-page: https://github.com/Acrome-Smart-Motion-Devices/python-library-new
6
6
  Author: BeratComputer
@@ -10,6 +10,7 @@ HEADER, ID, DEVICE_FAMILY, PACKAGE_SIZE, COMMAND, STATUS, .............. DATA ..
10
10
  '''
11
11
 
12
12
  PING_PACKAGE_SIZE = 10
13
+ BROADCAST_ID = 255
13
14
 
14
15
  #Classical Device Indexes
15
16
  Index_Device_Classical = enum.IntEnum('Index', [
@@ -86,7 +87,9 @@ class Slave_Device():
86
87
  SERIAL_HEADER = 0x55
87
88
  _BROADCAST_ID = 0xFF
88
89
 
89
- _BATCH_ID = 254
90
+ # NEW: device_family → variables (Data_ list) kaydı
91
+ _vars_registry = {} # { device_family:int : [Data_, Data_, ...] }
92
+
90
93
  def __init__(self, id, device_family, variables, port:SerialPort):
91
94
  self._port = port
92
95
  self._header = self.SERIAL_HEADER
@@ -97,6 +100,7 @@ class Slave_Device():
97
100
  self.__post_sleep = 0.01
98
101
  self.__device_init_sleep = 3
99
102
  self.write_ack_enable = False
103
+ Slave_Device._vars_registry.setdefault(device_family, variables)
100
104
 
101
105
  def enable_get_ack(self):
102
106
  self.write_ack_enable = True
@@ -312,3 +316,107 @@ class Data_():
312
316
 
313
317
  def type(self) -> str:
314
318
  return self.__type
319
+
320
+
321
+
322
+ def write_sync_to_many(
323
+ port: SerialPort,
324
+ device_family: int,
325
+ index: int,
326
+ *id_value_pairs,
327
+ expect_ack: bool = False
328
+ ) -> bool:
329
+ """
330
+ Aynı değişken index'ini birden fazla cihaza WRITE_SYNC ile yazar.
331
+ Değer tipi, device_family'nin kayıtlı değişken tablosundan otomatik çekilir.
332
+
333
+ Args:
334
+ port (SerialPort): paylaşılan seri port
335
+ device_family (int): ürün ailesi (ör. Joint için 0xDA)
336
+ index (int | enum.IntEnum): yazılacak değişken indeksi
337
+ *id_value_pairs: [id, value] çiftleri (list/tuple), örn: [0, 123], [1, -45], ...
338
+ expect_ack (bool): ACK beklenip beklenmeyeceği
339
+
340
+ Returns:
341
+ bool: True = yazdı (veya ACK doğrulandı); False = ACK bekleniyorsa doğrulanamadı
342
+ """
343
+ import struct
344
+ from crccheck.crc import Crc32Mpeg2 as CRC32
345
+
346
+ # Sabitler
347
+ HEADER = Slave_Device.SERIAL_HEADER
348
+ BATCH_ID = Slave_Device._BROADCAST_ID
349
+ PING_PACKAGE_SIZE = 10
350
+ WRITE_SYNC = int(Device_Commands.WRITE_SYNC)
351
+ STATUS = 0
352
+
353
+ # Registry ve tip çözümü
354
+ reg = Slave_Device._vars_registry.get(device_family)
355
+ if reg is None:
356
+ raise RuntimeError(
357
+ f"Device family 0x{device_family:02X} için değişken tablosu bulunamadı. "
358
+ "Bu family’den en az bir cihaz instance'ı oluşturulmuş olmalı."
359
+ )
360
+
361
+ idx_int = int(index)
362
+ try:
363
+ var_type = reg[idx_int].type() # 'f', 'i', 'B', ...
364
+ except Exception as e:
365
+ raise ValueError(f"Geçersiz index: {index} (family=0x{device_family:02X}).") from e
366
+
367
+ # id_value_pairs doğrula ve düzle
368
+ flat = []
369
+ for pair in id_value_pairs:
370
+ if (not isinstance(pair, (list, tuple))) or len(pair) != 2:
371
+ raise ValueError(f"{pair} geçersiz. [ID, value] olmalı.")
372
+ dev_id, val = pair
373
+ if not (0 <= int(dev_id) <= 254):
374
+ raise ValueError(f"ID {dev_id} geçersiz (0..254).")
375
+ # 'val' tipi Data_.type() ile belirlenecek; pack sırasında kontrol olur
376
+ flat.extend([int(dev_id), val])
377
+
378
+ count = len(flat) // 2
379
+ if count == 0:
380
+ raise ValueError("En az bir [ID, value] çifti gerekli.")
381
+
382
+ val_size = struct.calcsize('<' + var_type)
383
+
384
+ # Paket boyutu
385
+ # payload = index(1B) + her cihaz için (ID:1B + value:val_size)
386
+ payload_size = 1 + count * (1 + val_size)
387
+ package_size = PING_PACKAGE_SIZE + payload_size
388
+
389
+ # Format: header, BATCH_ID, family, size, cmd, status, index, (id, value)*N, crc
390
+ fmt = '<BBBBBB' + 'B' + ('B' + var_type) * count
391
+ data_no_crc = struct.pack(
392
+ fmt,
393
+ HEADER,
394
+ BATCH_ID,
395
+ device_family,
396
+ package_size,
397
+ WRITE_SYNC,
398
+ STATUS,
399
+ idx_int,
400
+ *flat
401
+ )
402
+ pkt = data_no_crc + struct.pack('<I', CRC32.calc(data_no_crc))
403
+
404
+ # Gönder
405
+ port._write_bus(pkt)
406
+
407
+ if not expect_ack:
408
+ return True
409
+
410
+ # Basit ACK okuma (PING_PACKAGE_SIZE kadar)
411
+ ack = port._read_bus(size=PING_PACKAGE_SIZE)
412
+ if not ack or len(ack) != PING_PACKAGE_SIZE:
413
+ return False
414
+
415
+ # CRC kontrolü
416
+ try:
417
+ data_part = ack[:-4]
418
+ crc_part = ack[-4:]
419
+ ok = (CRC32.calc(data_part) == struct.unpack('<I', crc_part)[0])
420
+ return bool(ok)
421
+ except Exception:
422
+ return False
@@ -12,7 +12,8 @@ from acrome_joint.Slave_Device import *
12
12
 
13
13
 
14
14
  # enter here for extra commands:
15
- #class Device_ExtraCommands(enum.IntEnum):
15
+ class Device_ExtraCommands(enum.IntEnum):
16
+ PROTOCOL_RESET_ABSOLUTE_ENCODER = 0x11
16
17
  # .......... start with 11
17
18
  # .......... end of extra commmands max: 39
18
19
 
@@ -143,7 +144,7 @@ class Joint(Slave_Device):
143
144
  Data_(Index_Joint.current_Id, 'f'),
144
145
  Data_(Index_Joint.current_Iq, 'f'),
145
146
  Data_(Index_Joint.current_velocity, 'f'),
146
- Data_(Index_Joint.current_position, 'i'),
147
+ Data_(Index_Joint.current_position, 'f'),
147
148
  Data_(Index_Joint.current_electrical_degree, 'f'),
148
149
  Data_(Index_Joint.current_electrical_radian, 'f'),
149
150
  Data_(Index_Joint.setpoint_current, 'f'),
@@ -282,7 +283,17 @@ class Joint(Slave_Device):
282
283
  return super().set_variables(*idx_val_pairs, ack=ack)
283
284
 
284
285
 
286
+ def get_currentStatus_parameters(self):
287
+ classic_package = [
288
+ Index_Joint.Enable,
289
+ Index_Joint.current_Id, Index_Joint.current_Iq,
290
+ Index_Joint.current_velocity, Index_Joint.current_position,
291
+ Index_Joint.Temprature_read,
292
+ Index_Joint.setpoint_current, Index_Joint.setpoint_velocity, Index_Joint.setpoint_position
293
+ ]
294
+ return self.get_variables(*classic_package)
285
295
 
296
+
286
297
  def get_FOC_parameters(self, package_number:int):
287
298
  if package_number >= 4:
288
299
  raise "invalid package number ex: 0, 1, 2"
@@ -323,4 +334,105 @@ class Joint(Slave_Device):
323
334
 
324
335
  elif package_number == 3:
325
336
  return self.get_variables(*classic_package)
326
-
337
+
338
+ def reset_absolute_encoder(self):
339
+ self._pure_command_send(Device_ExtraCommands.PROTOCOL_RESET_ABSOLUTE_ENCODER)
340
+
341
+
342
+ def set_joint_variables_sync(port: SerialPort, parameter_idx, *idx_val_pairs):
343
+ """
344
+ Sync Write paketi oluşturur ve gönderir.
345
+
346
+ Args:
347
+ port: SerialPort nesnesi.
348
+ parameter_idx: Index_Joint enum değeri (örn: Index_Joint.Enable).
349
+ idx_val_pairs: [DeviceID, Value] listeleri. Örn: [0, True], [1, True]
350
+ """
351
+
352
+ # 1. Port Kontrolü
353
+ if port is None:
354
+ raise ValueError("Port tanımlı değil.")
355
+
356
+ # 2. Referans Cihaz Oluşturma
357
+ # Data_ yapısındaki .type() ve .size() metotlarına erişmek için.
358
+ try:
359
+ ref_device = Joint(0, port)
360
+ except Exception as e:
361
+ raise ValueError(f"Referans Joint nesnesi oluşturulamadı: {e}")
362
+
363
+ # 3. Parametre Bilgilerini Çekme
364
+ try:
365
+ var_desc = ref_device._vars[parameter_idx]
366
+ except IndexError:
367
+ raise ValueError(f"Bilinmeyen parametre indeksi: {parameter_idx}")
368
+ except AttributeError:
369
+ raise ValueError("Joint nesnesinde '_vars' listesi bulunamadı.")
370
+
371
+ # --- DÜZELTME BURADA ---
372
+ # .type ve .size muhtemelen metot olduğu için () ile çağırıyoruz.
373
+ val_fmt = var_desc.type() # 'f', 'B', 'I' vb. döndürür
374
+ val_size = var_desc.size() # 4, 1 vb. int döndürür
375
+
376
+ # 4. Veri Çiftlerini Doğrulama
377
+ pairs = []
378
+ for p in idx_val_pairs:
379
+ if not hasattr(p, '__len__') or len(p) != 2:
380
+ raise ValueError(f"Hatalı veri çifti: {p}. Format [ID, Value] olmalı.")
381
+
382
+ dev_id, value = p[0], p[1]
383
+
384
+ # ID Kontrolü
385
+ if not (0 <= int(dev_id) <= 254):
386
+ raise ValueError(f"Device ID aralık dışı (0..254): {dev_id}")
387
+
388
+ pairs.append((int(dev_id), value))
389
+
390
+ if not pairs:
391
+ raise ValueError("Gönderilecek veri çifti bulunamadı.")
392
+
393
+ # 5. Paket Boyutlarını Hesaplama
394
+ # Payload: [PARAM_IDX] + ([ID] + [VALUE]) * N
395
+ # Artık val_size bir int olduğu için toplama işlemi çalışacaktır.
396
+ payload_size = 1 + len(pairs) * (1 + val_size)
397
+
398
+ length_field = payload_size + Joint._PACKAGE_ESSENTIAL_SIZE + 4 # 4 byte CRC ekle
399
+
400
+ # 6. Struct Formatını Hazırlama
401
+ # Header(6 byte) + ParamIdx(1 byte) + (DevID(1 byte) + Value(N byte)) * Adet
402
+ fmt = '<BBBBBB' + 'B' + ''.join(['B' + val_fmt for _ in pairs])
403
+
404
+ # 7. Paket İçeriği (Header, ID, Family, Length, Command...)
405
+ HEADER_BYTE = 0x55
406
+ BROADCAST_ID = 0xFF
407
+ CMD_WRITE_SYNC = Device_Commands.WRITE_SYNC
408
+ device_family = Joint._PRODUCT_TYPE
409
+
410
+ flat = [
411
+ HEADER_BYTE, # Header
412
+ BROADCAST_ID, # Broadcast ID (0xFF)
413
+ device_family, # Device Family
414
+ length_field, # Length
415
+ CMD_WRITE_SYNC, # Command
416
+ 0x00, # Status
417
+ int(parameter_idx), # Parametre ID
418
+ ]
419
+
420
+ # Değerleri ekle
421
+ for dev_id, value in pairs:
422
+ flat.append(dev_id)
423
+ flat.append(value)
424
+
425
+ # 8. Paketleme
426
+ try:
427
+ pkt_wo_crc = struct.pack(fmt, *flat)
428
+ except struct.error as e:
429
+ # Genellikle float yerine int veya tam tersi gelince oluşur
430
+ raise ValueError(f"Struct paketleme hatası (Veri tipi uyumsuzluğu): {e}")
431
+
432
+ # 9. CRC32
433
+ crc_val = CRC32.calc(pkt_wo_crc)
434
+ pkt = pkt_wo_crc + struct.pack('<I', crc_val)
435
+
436
+ # 10. Gönder
437
+ written = port._write_bus(pkt)
438
+ return written
@@ -0,0 +1,14 @@
1
+ from acrome_joint.joint import*
2
+
3
+ keyword_for_usb = "USB-SERIAL"
4
+ altarnate_keyword_for_usb = "USB-Enhanced-SERIAL"
5
+ if(not USB_serial_port(keyword_for_usb)):
6
+ if(not USB_serial_port(altarnate_keyword_for_usb)):
7
+ raise Exception("No USB serial port found. Please check your connections.")
8
+ else:
9
+ keyword_for_usb = altarnate_keyword_for_usb
10
+
11
+ port = SerialPort(USB_serial_port(keyword_for_usb), baudrate=921600, timeout=0.1)
12
+
13
+
14
+ Device = Joint(1, port)
@@ -0,0 +1,18 @@
1
+
2
+ # SPEED = RPM, ACC= RPM/s
3
+ ENCODER_CPR = 16384
4
+
5
+ MOTOR_VEL_MAX = 3000.0 # in rpm
6
+ MOTOR_ACC_MAX = 3000.0
7
+
8
+ ENC_TO_RPM_CONSTANT = ENCODER_CPR / 60
9
+
10
+ MOTOR_VEL_MAX_IN_ENC_TYPE = MOTOR_VEL_MAX * ENC_TO_RPM_CONSTANT
11
+ MOTOR_ACC_MAX_IN_ENC_TYPE = MOTOR_ACC_MAX * ENC_TO_RPM_CONSTANT
12
+
13
+ def rpm_to_tick_per_second(rpm:float):
14
+ return rpm*ENCODER_CPR/60
15
+
16
+ def tick_per_second_to_rpm(tick_per_second:float):
17
+ return tick_per_second*60/ENCODER_CPR
18
+
@@ -546,6 +546,7 @@ class OperationTab(QtWidgets.QWidget):
546
546
  continue
547
547
  try:
548
548
  idx = Index_Joint[nm]
549
+ print(f"Pulling {nm} (Index {idx})")
549
550
  out[nm] = Device.get_variables(idx)[0]
550
551
  except Exception:
551
552
  out[nm] = ""
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="Joint-python-library",
8
- version="0.0.6",
8
+ version="0.0.8",
9
9
  author="BeratComputer",
10
10
  author_email="beratdogan@acrome.net",
11
11
  description="Python library for interfacing with Acrome Robotic Arm Joint BLDC Motor Controllers. This Python library provides an easy-to-use interface for communication and control of BLDC motor controllers used in Acrome robotic arm joints. It is designed to simplify the integration of Acrome’s robotic joint actuators into custom applications, allowing developers and researchers to focus on building advanced robotic systems without dealing with low-level communication details.",
@@ -1,6 +0,0 @@
1
- from acrome_joint.joint import*
2
-
3
- keyword_for_usb = "USB-SERIAL"
4
- port = SerialPort(USB_serial_port(keyword_for_usb), baudrate=921600, timeout=0.01)
5
-
6
- Device = Joint(0, port)
@@ -1,17 +0,0 @@
1
-
2
- # SPEED = RPM, ACC= RPM/s
3
- ENCODER_CPR = 4096
4
-
5
- MOTOR_VEL_MAX = 150.0 # in rpm
6
- MOTOR_ACC_MAX = 500.0
7
-
8
-
9
- MOTOR_VEL_MAX_IN_ENC_TYPE = MOTOR_VEL_MAX * 68.2666
10
- MOTOR_ACC_MAX_IN_ENC_TYPE = MOTOR_ACC_MAX * 68.2666
11
-
12
- def rpm_to_tick_per_second(rpm:float):
13
- return rpm*ENCODER_CPR/60
14
-
15
- def tick_per_second_to_rpm(tick_per_second:float):
16
- return tick_per_second*60/ENCODER_CPR
17
-