robocad-py 1.0.2.7__tar.gz → 1.1.1.0__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.
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/CHANGELOG.md +4 -1
- robocad_py-1.1.1.0/MANIFEST.in +2 -0
- {robocad-py-1.0.2.7/robocad_py.egg-info → robocad_py-1.1.1.0}/PKG-INFO +18 -3
- robocad_py-1.1.1.0/robocad/algaritm.py +188 -0
- robocad_py-1.1.1.0/robocad/internal/algaritm_internal.py +385 -0
- {robocad-py-1.0.2.7/robocad/internal/studica → robocad_py-1.1.1.0/robocad/internal/common}/connection.py +37 -29
- {robocad-py-1.0.2.7/robocad/internal/studica → robocad_py-1.1.1.0/robocad/internal/common}/connection_base.py +3 -5
- robocad_py-1.1.1.0/robocad/internal/common/connection_real.py +84 -0
- robocad_py-1.1.1.0/robocad/internal/common/connection_sim.py +49 -0
- robocad_py-1.1.1.0/robocad/internal/common/lidar.py +342 -0
- robocad_py-1.1.1.0/robocad/internal/common/robot.py +47 -0
- robocad_py-1.1.1.0/robocad/internal/common/robot_configuration.py +34 -0
- robocad_py-1.1.1.0/robocad/internal/common/shared.py +42 -0
- robocad_py-1.1.1.0/robocad/internal/common/updaters.py +43 -0
- robocad_py-1.1.1.0/robocad/internal/studica_internal.py +446 -0
- robocad_py-1.1.1.0/robocad/shufflecad.py +449 -0
- robocad_py-1.1.1.0/robocad/studica.py +132 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0/robocad_py.egg-info}/PKG-INFO +18 -3
- robocad_py-1.1.1.0/robocad_py.egg-info/SOURCES.txt +25 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/setup.py +2 -2
- robocad-py-1.0.2.7/MANIFEST.in +0 -3
- robocad-py-1.0.2.7/robocad/common.py +0 -20
- robocad-py-1.0.2.7/robocad/internal/logger.py +0 -18
- robocad-py-1.0.2.7/robocad/internal/studica/COM.py +0 -133
- robocad-py-1.0.2.7/robocad/internal/studica/SPI.py +0 -111
- robocad-py-1.0.2.7/robocad/internal/studica/__init__.py +0 -0
- robocad-py-1.0.2.7/robocad/internal/studica/connection_real.py +0 -55
- robocad-py-1.0.2.7/robocad/internal/studica/connection_sim.py +0 -106
- robocad-py-1.0.2.7/robocad/internal/studica/shared.py +0 -137
- robocad-py-1.0.2.7/robocad/shufflecad/__init__.py +0 -0
- robocad-py-1.0.2.7/robocad/shufflecad/connections.py +0 -357
- robocad-py-1.0.2.7/robocad/shufflecad/shufflecad.py +0 -40
- robocad-py-1.0.2.7/robocad/shufflecad/shufflecad_holder.py +0 -80
- robocad-py-1.0.2.7/robocad/studica.py +0 -158
- robocad-py-1.0.2.7/robocad/vex.py +0 -76
- robocad-py-1.0.2.7/robocad_py.egg-info/SOURCES.txt +0 -27
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/LICENSE +0 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/robocad/__init__.py +0 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/robocad/internal/__init__.py +0 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/robocad_py.egg-info/dependency_links.txt +0 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/robocad_py.egg-info/requires.txt +0 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/robocad_py.egg-info/top_level.txt +0 -0
- {robocad-py-1.0.2.7 → robocad_py-1.1.1.0}/setup.cfg +0 -0
|
@@ -1,18 +1,30 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: robocad-py
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.1.0
|
|
4
4
|
Summary: python lib for real and virtual robots
|
|
5
5
|
Home-page: https://github.com/Soft-V/robocad-py
|
|
6
6
|
Author: Airat Abdrakov
|
|
7
7
|
Author-email: softvery@yandex.ru
|
|
8
8
|
License: MIT
|
|
9
|
-
Keywords: simulator,robotics,robot,3d,raspberry,control
|
|
9
|
+
Keywords: simulator,robotics,robot,3d,raspberry,control,robocad
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
11
|
Classifier: Intended Audience :: Education
|
|
12
12
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
15
|
License-File: LICENSE
|
|
16
|
+
Requires-Dist: numpy
|
|
17
|
+
Requires-Dist: funcad
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: keywords
|
|
24
|
+
Dynamic: license
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
Dynamic: requires-dist
|
|
27
|
+
Dynamic: summary
|
|
16
28
|
|
|
17
29
|
Python library for real and virtual robots
|
|
18
30
|
|
|
@@ -41,3 +53,6 @@ Python library for real and virtual robots
|
|
|
41
53
|
|
|
42
54
|
## 0.0.1.1
|
|
43
55
|
- Library fully changed according to the new requirements
|
|
56
|
+
|
|
57
|
+
## 1.0.3.0
|
|
58
|
+
- Fully rewritten
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import signal
|
|
2
|
+
|
|
3
|
+
from .internal.common.robot import Robot
|
|
4
|
+
from .internal.common.robot_configuration import DefaultAlgaritmConfiguration
|
|
5
|
+
from .internal.algaritm_internal import AlgaritmInternal
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RobotAlgaritm(Robot):
|
|
9
|
+
def __init__(self, is_real_robot: bool = True, conf: DefaultAlgaritmConfiguration = None):
|
|
10
|
+
if conf is None: conf = DefaultAlgaritmConfiguration()
|
|
11
|
+
|
|
12
|
+
super().__init__(is_real_robot, conf)
|
|
13
|
+
self.__algaritm_internal = AlgaritmInternal(self, conf)
|
|
14
|
+
self.__reseted_yaw_val = 0.0
|
|
15
|
+
|
|
16
|
+
signal.signal(signal.SIGTERM, self.handler)
|
|
17
|
+
signal.signal(signal.SIGINT, self.handler)
|
|
18
|
+
|
|
19
|
+
def stop(self):
|
|
20
|
+
self.__algaritm_internal.stop()
|
|
21
|
+
self.write_log("Program stopped")
|
|
22
|
+
|
|
23
|
+
def handler(self, signum, _):
|
|
24
|
+
self.write_log("Program stopped from handler")
|
|
25
|
+
self.write_log('Signal handler called with signal' + str(signum))
|
|
26
|
+
self.stop()
|
|
27
|
+
raise SystemExit("Exited")
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def motor_speed_0(self):
|
|
31
|
+
return self.__algaritm_internal.speed_motor_0
|
|
32
|
+
|
|
33
|
+
@motor_speed_0.setter
|
|
34
|
+
def motor_speed_0(self, value):
|
|
35
|
+
self.__algaritm_internal.speed_motor_0 = value
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def motor_speed_1(self):
|
|
39
|
+
return self.__algaritm_internal.speed_motor_1
|
|
40
|
+
|
|
41
|
+
@motor_speed_1.setter
|
|
42
|
+
def motor_speed_1(self, value):
|
|
43
|
+
self.__algaritm_internal.speed_motor_1 = value
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def motor_speed_2(self):
|
|
47
|
+
return self.__algaritm_internal.speed_motor_2
|
|
48
|
+
|
|
49
|
+
@motor_speed_2.setter
|
|
50
|
+
def motor_speed_2(self, value):
|
|
51
|
+
self.__algaritm_internal.speed_motor_2 = value
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def motor_speed_3(self):
|
|
55
|
+
return self.__algaritm_internal.speed_motor_3
|
|
56
|
+
|
|
57
|
+
@motor_speed_3.setter
|
|
58
|
+
def motor_speed_3(self, value):
|
|
59
|
+
self.__algaritm_internal.speed_motor_3 = value
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def motor_enc_0(self):
|
|
63
|
+
return self.__algaritm_internal.enc_motor_0
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def motor_enc_1(self):
|
|
67
|
+
return self.__algaritm_internal.enc_motor_1
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def motor_enc_2(self):
|
|
71
|
+
return self.__algaritm_internal.enc_motor_2
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def motor_enc_3(self):
|
|
75
|
+
return self.__algaritm_internal.enc_motor_3
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def yaw(self):
|
|
79
|
+
return self.__algaritm_internal.yaw
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def pitch(self):
|
|
83
|
+
return self.__algaritm_internal.pitch
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def roll(self):
|
|
87
|
+
return self.__algaritm_internal.roll
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def us_1(self):
|
|
91
|
+
return self.__algaritm_internal.ultrasound_1
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def us_2(self):
|
|
95
|
+
return self.__algaritm_internal.ultrasound_2
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def us_3(self):
|
|
99
|
+
return self.__algaritm_internal.ultrasound_3
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def us_4(self):
|
|
103
|
+
return self.__algaritm_internal.ultrasound_4
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def analog_1(self):
|
|
107
|
+
return self.__algaritm_internal.analog_1
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def analog_2(self):
|
|
111
|
+
return self.__algaritm_internal.analog_2
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def analog_3(self):
|
|
115
|
+
return self.__algaritm_internal.analog_3
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def analog_4(self):
|
|
119
|
+
return self.__algaritm_internal.analog_4
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def analog_5(self):
|
|
123
|
+
return self.__algaritm_internal.analog_5
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def analog_6(self):
|
|
127
|
+
return self.__algaritm_internal.analog_6
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def analog_7(self):
|
|
131
|
+
return self.__algaritm_internal.analog_7
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def analog_8(self):
|
|
135
|
+
return self.__algaritm_internal.analog_8
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def additional_servo_1(self):
|
|
139
|
+
return self.__algaritm_internal.additional_servo_1
|
|
140
|
+
|
|
141
|
+
@additional_servo_1.setter
|
|
142
|
+
def additional_servo_1(self, value):
|
|
143
|
+
self.__algaritm_internal.additional_servo_1 = value
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def additional_servo_2(self):
|
|
147
|
+
return self.__algaritm_internal.additional_servo_2
|
|
148
|
+
|
|
149
|
+
@additional_servo_2.setter
|
|
150
|
+
def additional_servo_2(self, value):
|
|
151
|
+
self.__algaritm_internal.additional_servo_2 = value
|
|
152
|
+
|
|
153
|
+
def set_pid_settings(self, use_pid, p, i, d):
|
|
154
|
+
self.__algaritm_internal.use_pid = use_pid
|
|
155
|
+
self.__algaritm_internal.p_pid = p
|
|
156
|
+
self.__algaritm_internal.i_pid = i
|
|
157
|
+
self.__algaritm_internal.d_pid = d
|
|
158
|
+
|
|
159
|
+
# num 1 or 2
|
|
160
|
+
def step_motor_move(self, num, steps: int, steps_per_second: int, direction: bool):
|
|
161
|
+
self.__algaritm_internal.step_motor_move(num, steps, steps_per_second, direction)
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def is_step_1_busy(self):
|
|
165
|
+
return self.__algaritm_internal.is_step_1_busy
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def is_step_2_busy(self):
|
|
169
|
+
return self.__algaritm_internal.is_step_2_busy
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def titan_limits(self) -> list:
|
|
173
|
+
return [self.__algaritm_internal.limit_h_0, self.__algaritm_internal.limit_l_0,
|
|
174
|
+
self.__algaritm_internal.limit_h_1, self.__algaritm_internal.limit_l_1,
|
|
175
|
+
self.__algaritm_internal.limit_h_2, self.__algaritm_internal.limit_l_2,
|
|
176
|
+
self.__algaritm_internal.limit_h_3, self.__algaritm_internal.limit_l_3]
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def camera_image(self):
|
|
180
|
+
return self.__algaritm_internal.get_camera()
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def lidar_data(self):
|
|
184
|
+
return self.__algaritm_internal.get_lidar()
|
|
185
|
+
|
|
186
|
+
# port is from 1 to 8 included
|
|
187
|
+
def set_angle_servo(self, value: float, port: int):
|
|
188
|
+
self.__algaritm_internal.set_servo_angle(value, port - 1)
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import struct
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
import numpy
|
|
6
|
+
from threading import Thread
|
|
7
|
+
|
|
8
|
+
from funcad.funcad import Funcad
|
|
9
|
+
|
|
10
|
+
from .common.shared import LibHolder
|
|
11
|
+
from .common.robot import Robot
|
|
12
|
+
from .common.connection_base import ConnectionBase
|
|
13
|
+
from .common.connection_sim import ConnectionSim
|
|
14
|
+
from .common.connection_real import ConnectionReal
|
|
15
|
+
from .common.updaters import RepkaUpdater
|
|
16
|
+
from .common.robot_configuration import DefaultAlgaritmConfiguration
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AlgaritmInternal:
|
|
20
|
+
def __init__(self, robot: Robot, conf: DefaultAlgaritmConfiguration):
|
|
21
|
+
self.__robot = robot
|
|
22
|
+
|
|
23
|
+
# from Titan
|
|
24
|
+
self.speed_motor_0: float = 0.0
|
|
25
|
+
self.speed_motor_1: float = 0.0
|
|
26
|
+
self.speed_motor_2: float = 0.0
|
|
27
|
+
self.speed_motor_3: float = 0.0
|
|
28
|
+
self.enc_motor_0: int = 0
|
|
29
|
+
self.enc_motor_1: int = 0
|
|
30
|
+
self.enc_motor_2: int = 0
|
|
31
|
+
self.enc_motor_3: int = 0
|
|
32
|
+
self.limit_l_0: bool = False
|
|
33
|
+
self.limit_h_0: bool = False
|
|
34
|
+
self.limit_l_1: bool = False
|
|
35
|
+
self.limit_h_1: bool = False
|
|
36
|
+
self.limit_l_2: bool = False
|
|
37
|
+
self.limit_h_2: bool = False
|
|
38
|
+
self.limit_l_3: bool = False
|
|
39
|
+
self.limit_h_3: bool = False
|
|
40
|
+
self.additional_servo_1: float = 0.0
|
|
41
|
+
self.additional_servo_2: float = 0.0
|
|
42
|
+
self.is_step_1_busy: bool = False
|
|
43
|
+
self.is_step_2_busy: bool = False
|
|
44
|
+
self.step_motor_1_steps: int = 0
|
|
45
|
+
self.step_motor_2_steps: int = 0
|
|
46
|
+
self.step_motor_1_steps_per_s: int = 0
|
|
47
|
+
self.step_motor_2_steps_per_s: int = 0
|
|
48
|
+
self.step_motor_1_direction: bool = False
|
|
49
|
+
self.step_motor_2_direction: bool = False
|
|
50
|
+
self.use_pid: bool = False
|
|
51
|
+
self.p_pid: float = 0.14
|
|
52
|
+
self.i_pid: float = 0.1
|
|
53
|
+
self.d_pid: float = 0.0
|
|
54
|
+
|
|
55
|
+
# from vmx
|
|
56
|
+
self.yaw: float = 0
|
|
57
|
+
self.yaw_unlim: float = 0
|
|
58
|
+
self.pitch: float = 0
|
|
59
|
+
self.pitch_unlim: float = 0
|
|
60
|
+
self.roll: float = 0
|
|
61
|
+
self.roll_unlim: float = 0
|
|
62
|
+
self.ultrasound_1: float = 0
|
|
63
|
+
self.ultrasound_2: float = 0
|
|
64
|
+
self.ultrasound_3: float = 0
|
|
65
|
+
self.ultrasound_4: float = 0
|
|
66
|
+
self.analog_1: int = 0
|
|
67
|
+
self.analog_2: int = 0
|
|
68
|
+
self.analog_3: int = 0
|
|
69
|
+
self.analog_4: int = 0
|
|
70
|
+
self.analog_5: int = 0
|
|
71
|
+
self.analog_6: int = 0
|
|
72
|
+
self.analog_7: int = 0
|
|
73
|
+
self.analog_8: int = 0
|
|
74
|
+
|
|
75
|
+
self.servo_angles: list = [0.0] * 8
|
|
76
|
+
|
|
77
|
+
self.__connection: ConnectionBase = None
|
|
78
|
+
if not self.__robot.on_real_robot:
|
|
79
|
+
pass
|
|
80
|
+
# self.__connection = ConnectionSim(self.__robot)
|
|
81
|
+
# self.__robocad_conn = RobocadConnection()
|
|
82
|
+
# self.__robocad_conn.start(self.__connection, self.__robot, self)
|
|
83
|
+
else:
|
|
84
|
+
updater = RepkaUpdater(self.__robot)
|
|
85
|
+
self.__connection = ConnectionReal(self.__robot, updater, conf)
|
|
86
|
+
self.__titan = TitanCOM()
|
|
87
|
+
self.__titan.start_com(self.__connection, self.__robot, self, conf)
|
|
88
|
+
self.__vmx = VMXSPI()
|
|
89
|
+
self.__vmx.start_spi(self.__connection, self.__robot, self, conf)
|
|
90
|
+
|
|
91
|
+
def stop(self):
|
|
92
|
+
self.__connection.stop()
|
|
93
|
+
if not self.__robot.on_real_robot:
|
|
94
|
+
pass
|
|
95
|
+
# if self.__robocad_conn is not None:
|
|
96
|
+
# self.__robocad_conn.stop()
|
|
97
|
+
else:
|
|
98
|
+
if self.__titan is not None:
|
|
99
|
+
self.__titan.stop()
|
|
100
|
+
if self.__vmx is not None:
|
|
101
|
+
self.__vmx.stop()
|
|
102
|
+
|
|
103
|
+
def get_camera(self):
|
|
104
|
+
return self.__connection.get_camera()
|
|
105
|
+
|
|
106
|
+
def get_lidar(self):
|
|
107
|
+
return self.__connection.get_lidar()
|
|
108
|
+
|
|
109
|
+
def set_servo_angle(self, angle: float, pin: int):
|
|
110
|
+
self.servo_angles[pin] = angle
|
|
111
|
+
|
|
112
|
+
def step_motor_move(self, num, steps: int, steps_per_second: int, direction: bool):
|
|
113
|
+
if num == 1:
|
|
114
|
+
self.step_motor_1_steps = steps
|
|
115
|
+
self.step_motor_1_steps_per_s = steps_per_second
|
|
116
|
+
self.step_motor_1_direction = direction
|
|
117
|
+
elif num == 2:
|
|
118
|
+
self.step_motor_2_steps = steps
|
|
119
|
+
self.step_motor_2_steps_per_s = steps_per_second
|
|
120
|
+
self.step_motor_2_direction = direction
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class TitanCOM:
|
|
124
|
+
def __init__(self):
|
|
125
|
+
self.__th: Thread = None
|
|
126
|
+
self.__stop_th: bool = False
|
|
127
|
+
|
|
128
|
+
def start_com(self, connection: ConnectionReal, robot: Robot, robot_internal: AlgaritmInternal, conf: DefaultAlgaritmConfiguration) -> None:
|
|
129
|
+
self.__connection: ConnectionReal = connection
|
|
130
|
+
self.__robot: Robot = robot
|
|
131
|
+
self.__robot_internal: AlgaritmInternal = robot_internal
|
|
132
|
+
self.__conf: DefaultAlgaritmConfiguration = conf
|
|
133
|
+
|
|
134
|
+
self.__stop_th: bool = False
|
|
135
|
+
self.__th: Thread = Thread(target=self.com_loop)
|
|
136
|
+
self.__th.daemon = True
|
|
137
|
+
self.__th.start()
|
|
138
|
+
|
|
139
|
+
def stop(self):
|
|
140
|
+
self.__stop_th = True
|
|
141
|
+
if self.__th is not None:
|
|
142
|
+
self.__th.join()
|
|
143
|
+
|
|
144
|
+
def com_loop(self) -> None:
|
|
145
|
+
try:
|
|
146
|
+
com_result = self.__connection.com_ini(self.__conf.titan_port, self.__conf.titan_baud)
|
|
147
|
+
if com_result != 0:
|
|
148
|
+
self.__robot.write_log("Failed to open COM")
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
start_time: int = round(time.time() * 10000)
|
|
152
|
+
send_count_time: float = time.time()
|
|
153
|
+
comm_counter = 0
|
|
154
|
+
while not self.__stop_th:
|
|
155
|
+
tx_time: float = round(time.time() * 10000)
|
|
156
|
+
tx_data = self.set_up_tx_data()
|
|
157
|
+
self.__robot.robot_info.tx_com_time_dev = round(time.time() * 10000) - tx_time
|
|
158
|
+
|
|
159
|
+
rx_data: bytearray = self.__connection.com_rw(tx_data)
|
|
160
|
+
|
|
161
|
+
rx_time: float = round(time.time() * 10000)
|
|
162
|
+
self.set_up_rx_data(rx_data)
|
|
163
|
+
self.__robot.robot_info.rx_com_time_dev = round(time.time() * 10000) - rx_time
|
|
164
|
+
|
|
165
|
+
comm_counter += 1
|
|
166
|
+
if time.time() - send_count_time > 1:
|
|
167
|
+
send_count_time = time.time()
|
|
168
|
+
self.__robot.robot_info.com_count_dev = comm_counter
|
|
169
|
+
comm_counter = 0
|
|
170
|
+
|
|
171
|
+
time.sleep(0.001)
|
|
172
|
+
self.__robot.robot_info.com_time_dev = round(time.time() * 10000) - start_time
|
|
173
|
+
start_time = round(time.time() * 10000)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
self.__connection.com_stop()
|
|
176
|
+
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
177
|
+
file_name = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
|
178
|
+
self.__robot.write_log(" ".join(map(str, [exc_type, file_name, exc_tb.tb_lineno])))
|
|
179
|
+
self.__robot.write_log(str(e))
|
|
180
|
+
|
|
181
|
+
def set_up_rx_data(self, data: bytearray) -> None:
|
|
182
|
+
if data[0] == 1:
|
|
183
|
+
if data[40] == 222:
|
|
184
|
+
self.__robot_internal.enc_motor_0 = ((data[4] & 0xff) << 24) | ((data[3] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[1] & 0xff)
|
|
185
|
+
self.__robot_internal.enc_motor_1 = ((data[8] & 0xff) << 24) | ((data[7] & 0xff) << 16) | ((data[6] & 0xff) << 8) | (data[5] & 0xff)
|
|
186
|
+
self.__robot_internal.enc_motor_2 = ((data[12] & 0xff) << 24) | ((data[11] & 0xff) << 16) | ((data[10] & 0xff) << 8) | (data[9] & 0xff)
|
|
187
|
+
self.__robot_internal.enc_motor_3 = ((data[16] & 0xff) << 24) | ((data[15] & 0xff) << 16) | ((data[14] & 0xff) << 8) | (data[13] & 0xff)
|
|
188
|
+
|
|
189
|
+
self.__robot_internal.limit_l_0 = Funcad.access_bit(data[17], 0)
|
|
190
|
+
self.__robot_internal.limit_h_0 = Funcad.access_bit(data[17], 1)
|
|
191
|
+
self.__robot_internal.limit_l_1 = Funcad.access_bit(data[17], 2)
|
|
192
|
+
self.__robot_internal.limit_h_1 = Funcad.access_bit(data[17], 3)
|
|
193
|
+
self.__robot_internal.limit_l_2 = Funcad.access_bit(data[17], 4)
|
|
194
|
+
self.__robot_internal.limit_h_2 = Funcad.access_bit(data[17], 5)
|
|
195
|
+
self.__robot_internal.limit_l_3 = Funcad.access_bit(data[17], 6)
|
|
196
|
+
self.__robot_internal.limit_h_3 = Funcad.access_bit(data[17], 7)
|
|
197
|
+
|
|
198
|
+
self.__robot_internal.is_step_1_busy = (data[18] != 0)
|
|
199
|
+
self.__robot_internal.is_step_2_busy = (data[19] != 0)
|
|
200
|
+
else:
|
|
201
|
+
self.__robot.write_log("received wrong data " + " ".join(map(str, data)))
|
|
202
|
+
|
|
203
|
+
def set_up_tx_data(self) -> bytearray:
|
|
204
|
+
tx_data: bytearray = bytearray([0] * 48)
|
|
205
|
+
tx_data[0] = 1
|
|
206
|
+
|
|
207
|
+
tx_data[1] = int(numpy.clip(self.__robot_internal.speed_motor_0, -100, 100)).to_bytes(1, 'big', signed = True)[0]
|
|
208
|
+
tx_data[2] = int(numpy.clip(self.__robot_internal.speed_motor_1, -100, 100)).to_bytes(1, 'big', signed = True)[0]
|
|
209
|
+
tx_data[3] = int(numpy.clip(self.__robot_internal.speed_motor_2, -100, 100)).to_bytes(1, 'big', signed = True)[0]
|
|
210
|
+
tx_data[4] = int(numpy.clip(self.__robot_internal.speed_motor_3, -100, 100)).to_bytes(1, 'big', signed = True)[0]
|
|
211
|
+
|
|
212
|
+
# for ProgramIsRunning and directions
|
|
213
|
+
tx_data[5] = int('11' +
|
|
214
|
+
("1" if self.__robot_internal.step_motor_1_direction else "0") +
|
|
215
|
+
("1" if self.__robot_internal.step_motor_2_direction else "0") +
|
|
216
|
+
("1" if self.__robot_internal.use_pid else "0") + '001', 2)
|
|
217
|
+
|
|
218
|
+
tx_data[6] = int(self.__robot_internal.additional_servo_1)
|
|
219
|
+
tx_data[7] = int(self.__robot_internal.additional_servo_2)
|
|
220
|
+
|
|
221
|
+
step1_steps: bytearray = Funcad.int_to_4_bytes(abs(self.__robot_internal.step_motor_1_steps))
|
|
222
|
+
tx_data[8] = step1_steps[0]
|
|
223
|
+
tx_data[9] = step1_steps[1]
|
|
224
|
+
tx_data[10] = step1_steps[2]
|
|
225
|
+
tx_data[11] = step1_steps[3]
|
|
226
|
+
step2_steps: bytearray = Funcad.int_to_4_bytes(abs(self.__robot_internal.step_motor_2_steps))
|
|
227
|
+
tx_data[12] = step2_steps[0]
|
|
228
|
+
tx_data[13] = step2_steps[1]
|
|
229
|
+
tx_data[14] = step2_steps[2]
|
|
230
|
+
tx_data[15] = step2_steps[3]
|
|
231
|
+
|
|
232
|
+
step1_steps_ps: bytearray = Funcad.int_to_4_bytes(abs(self.__robot_internal.step_motor_1_steps_per_s))
|
|
233
|
+
tx_data[16] = step1_steps_ps[0]
|
|
234
|
+
tx_data[17] = step1_steps_ps[1]
|
|
235
|
+
tx_data[18] = step1_steps_ps[2]
|
|
236
|
+
tx_data[19] = step1_steps_ps[3]
|
|
237
|
+
step2_steps_ps: bytearray = Funcad.int_to_4_bytes(abs(self.__robot_internal.step_motor_2_steps_per_s))
|
|
238
|
+
tx_data[20] = step2_steps_ps[0]
|
|
239
|
+
tx_data[21] = step2_steps_ps[1]
|
|
240
|
+
tx_data[22] = step2_steps_ps[2]
|
|
241
|
+
tx_data[23] = step2_steps_ps[3]
|
|
242
|
+
|
|
243
|
+
packed_p = struct.pack('<f', self.__robot_internal.p_pid)
|
|
244
|
+
tx_data[24] = packed_p[0]
|
|
245
|
+
tx_data[25] = packed_p[1]
|
|
246
|
+
tx_data[26] = packed_p[2]
|
|
247
|
+
tx_data[27] = packed_p[3]
|
|
248
|
+
packed_i = struct.pack('<f', self.__robot_internal.i_pid)
|
|
249
|
+
tx_data[28] = packed_i[0]
|
|
250
|
+
tx_data[29] = packed_i[1]
|
|
251
|
+
tx_data[30] = packed_i[2]
|
|
252
|
+
tx_data[31] = packed_i[3]
|
|
253
|
+
packed_d = struct.pack('<f', self.__robot_internal.d_pid)
|
|
254
|
+
tx_data[32] = packed_d[0]
|
|
255
|
+
tx_data[33] = packed_d[1]
|
|
256
|
+
tx_data[34] = packed_d[2]
|
|
257
|
+
tx_data[35] = packed_d[3]
|
|
258
|
+
|
|
259
|
+
tx_data[40] = 222
|
|
260
|
+
|
|
261
|
+
return tx_data
|
|
262
|
+
|
|
263
|
+
class VMXSPI:
|
|
264
|
+
def __init__(self):
|
|
265
|
+
self.__th: Thread = None
|
|
266
|
+
self.__stop_th: bool = False
|
|
267
|
+
|
|
268
|
+
def start_spi(self, connection: ConnectionReal, robot: Robot, robot_internal: AlgaritmInternal, conf: DefaultAlgaritmConfiguration) -> None:
|
|
269
|
+
self.__connection: ConnectionReal = connection
|
|
270
|
+
self.__robot: Robot = robot
|
|
271
|
+
self.__robot_internal: AlgaritmInternal = robot_internal
|
|
272
|
+
self.__conf: DefaultAlgaritmConfiguration = conf
|
|
273
|
+
|
|
274
|
+
self.__toggler: int = 0
|
|
275
|
+
self.__stop_th: bool = False
|
|
276
|
+
self.__th: Thread = Thread(target=self.spi_loop)
|
|
277
|
+
self.__th.daemon = True
|
|
278
|
+
self.__th.start()
|
|
279
|
+
|
|
280
|
+
def stop(self):
|
|
281
|
+
self.__stop_th = True
|
|
282
|
+
if self.__th is not None:
|
|
283
|
+
self.__th.join()
|
|
284
|
+
|
|
285
|
+
def spi_loop(self) -> None:
|
|
286
|
+
try:
|
|
287
|
+
spi_result = self.__connection.spi_ini(self.__conf.vmx_port, self.__conf.vmx_ch, self.__conf.vmx_speed, self.__conf.vmx_mode)
|
|
288
|
+
if spi_result != 0:
|
|
289
|
+
self.__robot.write_log("Failed to open SPI")
|
|
290
|
+
return
|
|
291
|
+
|
|
292
|
+
start_time: float = round(time.time() * 10000)
|
|
293
|
+
send_count_time: float = time.time()
|
|
294
|
+
comm_counter = 0
|
|
295
|
+
while not self.__stop_th:
|
|
296
|
+
tx_time: float = round(time.time() * 10000)
|
|
297
|
+
tx_list = self.set_up_tx_data()
|
|
298
|
+
self.__robot.robot_info.tx_spi_time_dev = round(time.time() * 10000) - tx_time
|
|
299
|
+
|
|
300
|
+
rx_list: bytearray = self.__connection.spi_rw(tx_list)
|
|
301
|
+
|
|
302
|
+
rx_time: float = round(time.time() * 10000)
|
|
303
|
+
self.set_up_rx_data(rx_list)
|
|
304
|
+
self.__robot.robot_info.rx_spi_time_dev = round(time.time() * 10000) - rx_time
|
|
305
|
+
|
|
306
|
+
comm_counter += 1
|
|
307
|
+
if time.time() - send_count_time > 1:
|
|
308
|
+
send_count_time = time.time()
|
|
309
|
+
self.__robot.robot_info.spi_count_dev = comm_counter
|
|
310
|
+
comm_counter = 0
|
|
311
|
+
|
|
312
|
+
time.sleep(0.002)
|
|
313
|
+
self.__robot.robot_info.spi_time_dev = round(time.time() * 10000) - start_time
|
|
314
|
+
start_time = round(time.time() * 10000)
|
|
315
|
+
except (Exception, EOFError) as e:
|
|
316
|
+
self.__connection.spi_stop()
|
|
317
|
+
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
318
|
+
file_name = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
|
319
|
+
self.__robot.write_log(" ".join(map(str, [exc_type, file_name, exc_tb.tb_lineno])))
|
|
320
|
+
self.__robot.write_log(str(e))
|
|
321
|
+
|
|
322
|
+
def set_up_rx_data(self, data: bytearray) -> None:
|
|
323
|
+
if data[0] == 1:
|
|
324
|
+
self.__robot_internal.analog_1 = (data[2] & 0xff) << 8 | (data[1] & 0xff)
|
|
325
|
+
self.__robot_internal.analog_2 = (data[4] & 0xff) << 8 | (data[3] & 0xff)
|
|
326
|
+
self.__robot_internal.analog_3 = (data[6] & 0xff) << 8 | (data[5] & 0xff)
|
|
327
|
+
self.__robot_internal.analog_4 = (data[8] & 0xff) << 8 | (data[7] & 0xff)
|
|
328
|
+
self.__robot_internal.analog_5 = (data[10] & 0xff) << 8 | (data[9] & 0xff)
|
|
329
|
+
self.__robot_internal.analog_6 = (data[12] & 0xff) << 8 | (data[11] & 0xff)
|
|
330
|
+
self.__robot_internal.analog_7 = (data[14] & 0xff) << 8 | (data[13] & 0xff)
|
|
331
|
+
elif data[0] == 2:
|
|
332
|
+
self.__robot_internal.analog_8 = (data[2] & 0xff) << 8 | (data[1] & 0xff)
|
|
333
|
+
|
|
334
|
+
us1_ui: int = (data[4] & 0xff) << 8 | (data[3] & 0xff)
|
|
335
|
+
self.__robot_internal.ultrasound_1 = us1_ui / 100
|
|
336
|
+
us2_ui: int = (data[6] & 0xff) << 8 | (data[5] & 0xff)
|
|
337
|
+
self.__robot_internal.ultrasound_2 = us2_ui / 100
|
|
338
|
+
us3_ui: int = (data[8] & 0xff) << 8 | (data[7] & 0xff)
|
|
339
|
+
self.__robot_internal.ultrasound_3 = us3_ui / 100
|
|
340
|
+
us4_ui: int = (data[10] & 0xff) << 8 | (data[9] & 0xff)
|
|
341
|
+
self.__robot_internal.ultrasound_4 = us4_ui / 100
|
|
342
|
+
elif data[0] == 3:
|
|
343
|
+
yaw_ui: int = (data[2] & 0xff) << 8 | (data[1] & 0xff)
|
|
344
|
+
new_yaw = (yaw_ui / 100) * (1 if Funcad.access_bit(data[7], 1) else -1)
|
|
345
|
+
self.__robot_internal.yaw_unlim += self.calc_angle_unlim(new_yaw, self.__robot_internal.yaw)
|
|
346
|
+
self.__robot_internal.yaw = new_yaw
|
|
347
|
+
|
|
348
|
+
pitch_ui: int = (data[4] & 0xff) << 8 | (data[3] & 0xff)
|
|
349
|
+
new_pitch = (pitch_ui / 100) * (1 if Funcad.access_bit(data[7], 2) else -1)
|
|
350
|
+
self.__robot_internal.pitch_unlim += self.calc_angle_unlim(new_pitch, self.__robot_internal.pitch)
|
|
351
|
+
self.__robot_internal.pitch = new_pitch
|
|
352
|
+
|
|
353
|
+
roll_ui: int = (data[6] & 0xff) << 8 | (data[5] & 0xff)
|
|
354
|
+
new_roll = (roll_ui / 100) * (1 if Funcad.access_bit(data[7], 3) else -1)
|
|
355
|
+
self.__robot_internal.roll_unlim += self.calc_angle_unlim(new_roll, self.__robot_internal.roll)
|
|
356
|
+
self.__robot_internal.roll = new_roll
|
|
357
|
+
|
|
358
|
+
power: float = ((data[8] & 0xff) << 8 | (data[7] & 0xff)) / 100
|
|
359
|
+
self.__robot.power = power
|
|
360
|
+
|
|
361
|
+
def set_up_tx_data(self) -> bytearray:
|
|
362
|
+
tx_list: bytearray = bytearray([0x00] * 16)
|
|
363
|
+
|
|
364
|
+
if self.__toggler == 0:
|
|
365
|
+
tx_list[0] = 1
|
|
366
|
+
|
|
367
|
+
tx_list[1] = int(self.__robot_internal.servo_angles[0])
|
|
368
|
+
tx_list[2] = int(self.__robot_internal.servo_angles[1])
|
|
369
|
+
tx_list[3] = int(self.__robot_internal.servo_angles[2])
|
|
370
|
+
tx_list[4] = int(self.__robot_internal.servo_angles[3])
|
|
371
|
+
tx_list[5] = int(self.__robot_internal.servo_angles[4])
|
|
372
|
+
tx_list[6] = int(self.__robot_internal.servo_angles[5])
|
|
373
|
+
tx_list[7] = int(self.__robot_internal.servo_angles[6])
|
|
374
|
+
tx_list[8] = int(self.__robot_internal.servo_angles[7])
|
|
375
|
+
return tx_list
|
|
376
|
+
|
|
377
|
+
def calc_angle_unlim(self, new_angle: float, old_angle: float) -> float:
|
|
378
|
+
delta_angle = new_angle - old_angle
|
|
379
|
+
if delta_angle < -180:
|
|
380
|
+
delta_angle = 180 - old_angle
|
|
381
|
+
delta_angle += 180 + new_angle
|
|
382
|
+
elif delta_angle > 180:
|
|
383
|
+
delta_angle = (180 + old_angle) * -1
|
|
384
|
+
delta_angle += (180 - new_angle) * -1
|
|
385
|
+
return delta_angle
|