Skip to content

Commit 6add9d0

Browse files
authored
Merge pull request #146 from cogip/145-add-sc-servo-driver-and-usage-example
Add SC Servo driver and usage example feature
2 parents 805ab5f + d38d99e commit 6add9d0

19 files changed

+1768
-25
lines changed

cogip/scservo_sdk/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env python
2+
3+
from .port_handler import *
4+
from .protocol_packet_handler import *
5+
from .group_sync_write import *
6+
from .group_sync_read import *
7+
from .sms_sts import *
8+
from .scscl import *
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/usr/bin/env python
2+
3+
from .scservo_def import *
4+
5+
class GroupSyncRead:
6+
def __init__(self, ph, start_address, data_length):
7+
self.ph = ph
8+
self.start_address = start_address
9+
self.data_length = data_length
10+
11+
self.last_result = False
12+
self.is_param_changed = False
13+
self.param = []
14+
self.data_dict = {}
15+
16+
self.clearParam()
17+
18+
def makeParam(self):
19+
if not self.data_dict: # len(self.data_dict.keys()) == 0:
20+
return
21+
22+
self.param = []
23+
24+
for scs_id in self.data_dict:
25+
self.param.append(scs_id)
26+
27+
def addParam(self, scs_id):
28+
if scs_id in self.data_dict: # scs_id already exist
29+
return False
30+
31+
self.data_dict[scs_id] = [] # [0] * self.data_length
32+
33+
self.is_param_changed = True
34+
return True
35+
36+
def removeParam(self, scs_id):
37+
if scs_id not in self.data_dict: # NOT exist
38+
return
39+
40+
del self.data_dict[scs_id]
41+
42+
self.is_param_changed = True
43+
44+
def clearParam(self):
45+
self.data_dict.clear()
46+
47+
def txPacket(self):
48+
if len(self.data_dict.keys()) == 0:
49+
50+
return COMM_NOT_AVAILABLE
51+
52+
if self.is_param_changed is True or not self.param:
53+
self.makeParam()
54+
55+
return self.ph.syncReadTx(self.start_address, self.data_length, self.param, len(self.data_dict.keys()))
56+
57+
def rxPacket(self):
58+
self.last_result = True
59+
60+
result = COMM_RX_FAIL
61+
62+
if len(self.data_dict.keys()) == 0:
63+
return COMM_NOT_AVAILABLE
64+
65+
result, rxpacket = self.ph.syncReadRx(self.data_length, len(self.data_dict.keys()))
66+
# print(rxpacket)
67+
if len(rxpacket) >= (self.data_length+6):
68+
for scs_id in self.data_dict:
69+
self.data_dict[scs_id], result = self.readRx(rxpacket, scs_id, self.data_length)
70+
if result != COMM_SUCCESS:
71+
self.last_result = False
72+
# print(scs_id)
73+
else:
74+
self.last_result = False
75+
# print(self.last_result)
76+
return result
77+
78+
def txRxPacket(self):
79+
result = self.txPacket()
80+
if result != COMM_SUCCESS:
81+
return result
82+
83+
return self.rxPacket()
84+
85+
def readRx(self, rxpacket, scs_id, data_length):
86+
# print(scs_id)
87+
# print(rxpacket)
88+
data = []
89+
rx_length = len(rxpacket)
90+
# print(rx_length)
91+
rx_index = 0;
92+
while (rx_index+6+data_length) <= rx_length:
93+
headpacket = [0x00, 0x00, 0x00]
94+
while rx_index < rx_length:
95+
headpacket[2] = headpacket[1];
96+
headpacket[1] = headpacket[0];
97+
headpacket[0] = rxpacket[rx_index];
98+
rx_index += 1
99+
if (headpacket[2] == 0xFF) and (headpacket[1] == 0xFF) and headpacket[0] == scs_id:
100+
# print(rx_index)
101+
break
102+
# print(rx_index+3+data_length)
103+
if (rx_index+3+data_length) > rx_length:
104+
break;
105+
if rxpacket[rx_index] != (data_length+2):
106+
rx_index += 1
107+
# print(rx_index)
108+
continue
109+
rx_index += 1
110+
Error = rxpacket[rx_index]
111+
rx_index += 1
112+
calSum = scs_id + (data_length+2) + Error
113+
data = [Error]
114+
data.extend(rxpacket[rx_index : rx_index+data_length])
115+
for i in range(0, data_length):
116+
calSum += rxpacket[rx_index]
117+
rx_index += 1
118+
calSum = ~calSum & 0xFF
119+
# print(calSum)
120+
if calSum != rxpacket[rx_index]:
121+
return None, COMM_RX_CORRUPT
122+
return data, COMM_SUCCESS
123+
# print(rx_index)
124+
return None, COMM_RX_CORRUPT
125+
126+
def isAvailable(self, scs_id, address, data_length):
127+
#if self.last_result is False or scs_id not in self.data_dict:
128+
if scs_id not in self.data_dict:
129+
return False, 0
130+
131+
if (address < self.start_address) or (self.start_address + self.data_length - data_length < address):
132+
return False, 0
133+
if not self.data_dict[scs_id]:
134+
return False, 0
135+
if len(self.data_dict[scs_id])<(data_length+1):
136+
return False, 0
137+
return True, self.data_dict[scs_id][0]
138+
139+
def getData(self, scs_id, address, data_length):
140+
if data_length == 1:
141+
return self.data_dict[scs_id][address-self.start_address+1]
142+
elif data_length == 2:
143+
return self.ph.scs_makeword(self.data_dict[scs_id][address-self.start_address+1],
144+
self.data_dict[scs_id][address-self.start_address+2])
145+
elif data_length == 4:
146+
return self.ph.scs_makedword(self.ph.scs_makeword(self.data_dict[scs_id][address-self.start_address+1],
147+
self.data_dict[scs_id][address-self.start_address+2]),
148+
self.ph.scs_makeword(self.data_dict[scs_id][address-self.start_address+3],
149+
self.data_dict[scs_id][address-self.start_address+4]))
150+
else:
151+
return 0
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python
2+
3+
from .scservo_def import *
4+
5+
class GroupSyncWrite:
6+
def __init__(self, ph, start_address, data_length):
7+
self.ph = ph
8+
self.start_address = start_address
9+
self.data_length = data_length
10+
11+
self.is_param_changed = False
12+
self.param = []
13+
self.data_dict = {}
14+
15+
self.clearParam()
16+
17+
def makeParam(self):
18+
if not self.data_dict:
19+
return
20+
21+
self.param = []
22+
23+
for scs_id in self.data_dict:
24+
if not self.data_dict[scs_id]:
25+
return
26+
27+
self.param.append(scs_id)
28+
self.param.extend(self.data_dict[scs_id])
29+
30+
def addParam(self, scs_id, data):
31+
if scs_id in self.data_dict: # scs_id already exist
32+
return False
33+
34+
if len(data) > self.data_length: # input data is longer than set
35+
return False
36+
37+
self.data_dict[scs_id] = data
38+
39+
self.is_param_changed = True
40+
return True
41+
42+
def removeParam(self, scs_id):
43+
if scs_id not in self.data_dict: # NOT exist
44+
return
45+
46+
del self.data_dict[scs_id]
47+
48+
self.is_param_changed = True
49+
50+
def changeParam(self, scs_id, data):
51+
if scs_id not in self.data_dict: # NOT exist
52+
return False
53+
54+
if len(data) > self.data_length: # input data is longer than set
55+
return False
56+
57+
self.data_dict[scs_id] = data
58+
59+
self.is_param_changed = True
60+
return True
61+
62+
def clearParam(self):
63+
self.data_dict.clear()
64+
65+
def txPacket(self):
66+
if len(self.data_dict.keys()) == 0:
67+
return COMM_NOT_AVAILABLE
68+
69+
if self.is_param_changed is True or not self.param:
70+
self.makeParam()
71+
72+
return self.ph.syncWriteTxOnly(self.start_address, self.data_length, self.param,
73+
len(self.data_dict.keys()) * (1 + self.data_length))

cogip/scservo_sdk/port_handler.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/env python
2+
3+
import time
4+
import serial
5+
import sys
6+
import platform
7+
8+
DEFAULT_BAUDRATE = 1000000
9+
LATENCY_TIMER = 50
10+
11+
class PortHandler(object):
12+
def __init__(self, port_name):
13+
self.is_open = False
14+
self.baudrate = DEFAULT_BAUDRATE
15+
self.packet_start_time = 0.0
16+
self.packet_timeout = 0.0
17+
self.tx_time_per_byte = 0.0
18+
19+
self.is_using = False
20+
self.port_name = port_name
21+
self.ser = None
22+
23+
def openPort(self):
24+
return self.setBaudRate(self.baudrate)
25+
26+
def closePort(self):
27+
self.ser.close()
28+
self.is_open = False
29+
30+
def clearPort(self):
31+
self.ser.flush()
32+
33+
def setPortName(self, port_name):
34+
self.port_name = port_name
35+
36+
def getPortName(self):
37+
return self.port_name
38+
39+
def setBaudRate(self, baudrate):
40+
baud = self.getCFlagBaud(baudrate)
41+
42+
if baud <= 0:
43+
# self.setupPort(38400)
44+
# self.baudrate = baudrate
45+
return False # TODO: setCustomBaudrate(baudrate)
46+
else:
47+
self.baudrate = baudrate
48+
return self.setupPort(baud)
49+
50+
def getBaudRate(self):
51+
return self.baudrate
52+
53+
def getBytesAvailable(self):
54+
return self.ser.in_waiting
55+
56+
def readPort(self, length):
57+
if (sys.version_info > (3, 0)):
58+
ret = self.ser.read(length)
59+
return ret
60+
else:
61+
return [ord(ch) for ch in self.ser.read(length)]
62+
63+
def writePort(self, packet):
64+
return self.ser.write(packet)
65+
66+
def setPacketTimeout(self, packet_length):
67+
self.packet_start_time = self.getCurrentTime()
68+
self.packet_timeout = (self.tx_time_per_byte * packet_length) + (self.tx_time_per_byte * 3.0) + LATENCY_TIMER
69+
70+
def setPacketTimeoutMillis(self, msec):
71+
self.packet_start_time = self.getCurrentTime()
72+
self.packet_timeout = msec
73+
74+
def isPacketTimeout(self):
75+
if self.getTimeSinceStart() > self.packet_timeout:
76+
self.packet_timeout = 0
77+
return True
78+
79+
return False
80+
81+
def getCurrentTime(self):
82+
return round(time.time() * 1000000000) / 1000000.0
83+
84+
def getTimeSinceStart(self):
85+
time_since = self.getCurrentTime() - self.packet_start_time
86+
if time_since < 0.0:
87+
self.packet_start_time = self.getCurrentTime()
88+
89+
return time_since
90+
91+
def setupPort(self, cflag_baud):
92+
if self.is_open:
93+
self.closePort()
94+
95+
self.ser = serial.Serial(
96+
port=self.port_name,
97+
baudrate=self.baudrate,
98+
# parity = serial.PARITY_ODD,
99+
# stopbits = serial.STOPBITS_TWO,
100+
bytesize=serial.EIGHTBITS,
101+
timeout=0
102+
)
103+
104+
self.is_open = True
105+
106+
self.ser.reset_input_buffer()
107+
108+
self.tx_time_per_byte = (1000.0 / self.baudrate) * 10.0
109+
110+
return True
111+
112+
def getCFlagBaud(self, baudrate):
113+
if baudrate in [4800, 9600, 14400, 19200, 38400, 57600, 115200, 128000, 250000, 500000, 921600, 1000000]:
114+
return baudrate
115+
else:
116+
return -1

0 commit comments

Comments
 (0)