standardbots 2.20241120.1__tar.gz → 2.20250128.2__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.
Potentially problematic release.
This version of standardbots might be problematic. Click here for more details.
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/PKG-INFO +9 -2
- standardbots-2.20250128.2/README.md +141 -0
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/setup.py +1 -1
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots/auto_generated/apis.py +166 -65
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots/auto_generated/models.py +1903 -466
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots.egg-info/PKG-INFO +9 -2
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots.egg-info/SOURCES.txt +6 -1
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots.egg-info/top_level.txt +1 -0
- standardbots-2.20250128.2/tests/fixtures/__init__.py +0 -0
- standardbots-2.20250128.2/tests/fixtures/client_fixt.py +25 -0
- standardbots-2.20250128.2/tests/fixtures/routines_fixt.py +48 -0
- standardbots-2.20250128.2/tests/test_apis.py +1294 -0
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/setup.cfg +0 -0
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots/__init__.py +0 -0
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots/auto_generated/__init__.py +0 -0
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots.egg-info/dependency_links.txt +0 -0
- {standardbots-2.20241120.1 → standardbots-2.20250128.2}/standardbots.egg-info/requires.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: standardbots
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.20250128.2
|
|
4
4
|
Summary: Standard Bots RO1 Robotics API
|
|
5
5
|
Home-page:
|
|
6
6
|
Author: Standard Bots Support
|
|
@@ -10,6 +10,13 @@ Requires-Python: >=3.7
|
|
|
10
10
|
Requires-Dist: setuptools>=21.0.0
|
|
11
11
|
Requires-Dist: typing_extensions>=4.3.0
|
|
12
12
|
Requires-Dist: urllib3>=1.26.7
|
|
13
|
+
Dynamic: author
|
|
14
|
+
Dynamic: author-email
|
|
15
|
+
Dynamic: description
|
|
16
|
+
Dynamic: keywords
|
|
17
|
+
Dynamic: requires-dist
|
|
18
|
+
Dynamic: requires-python
|
|
19
|
+
Dynamic: summary
|
|
13
20
|
|
|
14
21
|
Standard Bots RO1 Robotics API. # noqa: E501
|
|
15
22
|
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
You can test the API by using the playground, add your own file or use the existing python scripts.
|
|
2
|
+
When a client has an issue, and they send their code. It's helpful to test their code to see possible issues
|
|
3
|
+
|
|
4
|
+
# ENABLE API ON YOUR LOCAL MACHINE
|
|
5
|
+
|
|
6
|
+
Follow the steps here https://www.notion.so/standardbots/Using-the-REST-API-b2c778d47969444dac61483f0117acad
|
|
7
|
+
|
|
8
|
+
# CONFIG
|
|
9
|
+
|
|
10
|
+
At the top of the file, use your token
|
|
11
|
+
|
|
12
|
+
# RUN
|
|
13
|
+
|
|
14
|
+
To run a script move into the `sdks/python` folder and run `python playground/filename.py`
|
|
15
|
+
|
|
16
|
+
# To create a test build
|
|
17
|
+
|
|
18
|
+
1. Update version in `setup.py`
|
|
19
|
+
2. Run `python3 setup.py sdist bdist_wheel`
|
|
20
|
+
|
|
21
|
+
# Tests
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
To set up tests:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd sdks/python
|
|
29
|
+
|
|
30
|
+
pip install -r requirements.txt
|
|
31
|
+
pip install -r requirements-dev.txt
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Create sample data
|
|
35
|
+
|
|
36
|
+
#### Sample routine
|
|
37
|
+
|
|
38
|
+
You need to add the sample routine in [sdks/python/tests/fixtures/test_public_api_routine.json](./tests/fixtures/test_public_api_routine.json) to your target test environment (i.e. upload the routine to ).
|
|
39
|
+
|
|
40
|
+
The name of routine should be "Test Public API"
|
|
41
|
+
|
|
42
|
+
#### Sample globals
|
|
43
|
+
|
|
44
|
+
- _Variable._ Add global variable called "test_public_api_global" with any value.
|
|
45
|
+
- _Space._ Create a global space called "Test global space" of any kind.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Running
|
|
49
|
+
|
|
50
|
+
Here is a basic test command:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
SB_API_URL=http://34.162.0.32:3000
|
|
54
|
+
SB_API_TOKEN=...
|
|
55
|
+
|
|
56
|
+
python3 -m pytest ./tests --cov=standardbots --token=$SB_API_TOKEN --api-url=$SB_API_URL
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
You may also set up a `.env` file at `sdks/python/.env` with the following contents:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export SB_API_URL=http://34.162.0.32:3000
|
|
63
|
+
export SB_API_TOKEN=...
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then you can just do:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
python3 -m pytest ./tests --cov=standardbots
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Robot state and testing (Markers)
|
|
73
|
+
|
|
74
|
+
We need the bot to be in a certain state to run certain tests. For example, we need a routine to be running in order to stop the routine.
|
|
75
|
+
|
|
76
|
+
At start of testing, robot should:
|
|
77
|
+
|
|
78
|
+
- _NOT_ be e-stopped.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
The basic idea here is:
|
|
82
|
+
|
|
83
|
+
- These special tests will not be run by default.
|
|
84
|
+
- You may pass a flag (e.g. `--routine-running`) when the bot is in the correct state to run the tests.
|
|
85
|
+
- When the flag is passed:
|
|
86
|
+
1. Tests with the flag are run.
|
|
87
|
+
2. Tests without the flag are not run.
|
|
88
|
+
|
|
89
|
+
We use [pytest markers](https://docs.pytest.org/en/7.1.x/example/markers.html) to do this.
|
|
90
|
+
|
|
91
|
+
#### Routine running
|
|
92
|
+
|
|
93
|
+
The special sample routine ("Test Public API") should be running prior to running these tests. Then do:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
python3 -m pytest ./tests --cov=standardbots --routine-running
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### E-stop
|
|
100
|
+
|
|
101
|
+
No marker needed for e-stop. However, we do rely on active recovery of e-stop and getting the failure state in order to do these tests.
|
|
102
|
+
|
|
103
|
+
When e-stop test runs, cannot have bot in a failure state (pre-test will fail).
|
|
104
|
+
|
|
105
|
+
## Troubleshooting
|
|
106
|
+
|
|
107
|
+
### Tests are hanging
|
|
108
|
+
|
|
109
|
+
The first test appears to start but then nothing happens for several seconds:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
$ python3 -m pytest ./tests --cov=standardbots
|
|
113
|
+
========================================================================================================== test session starts ===========================================================================================================
|
|
114
|
+
platform linux -- Python 3.10.12, pytest-6.2.5, py-1.10.0, pluggy-0.13.0
|
|
115
|
+
rootdir: /workspaces/sb/sdks/python, configfile: pytest.ini
|
|
116
|
+
plugins: ament-pep257-0.12.11, ament-xmllint-0.12.11, launch-testing-1.0.6, launch-testing-ros-0.19.7, ament-flake8-0.12.11, ament-lint-0.12.11, ament-copyright-0.12.11, colcon-core-0.18.1, cov-6.0.0
|
|
117
|
+
collected 110 items
|
|
118
|
+
|
|
119
|
+
tests/test_apis.py
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Fixes:
|
|
123
|
+
|
|
124
|
+
- _Make sure you can log into remote control._ Ensure that botman is connected.
|
|
125
|
+
- _Ensure that the robot URL is up-to-date._ Botman url will often change when you reboot.
|
|
126
|
+
|
|
127
|
+
### Custom sensors
|
|
128
|
+
|
|
129
|
+
To test custom sensors:
|
|
130
|
+
- go to the menu on the left bottom corner;
|
|
131
|
+
- Click on 'Equipment';
|
|
132
|
+
- Add Gripper > Custom Gripper;
|
|
133
|
+
- Go to the Sensors tab and click 'Add Sensor';
|
|
134
|
+
- Keep the default values as they are (name: 'Sensor 1', kind: 'Control Box IO', sensor value: 'low');
|
|
135
|
+
- Hit 'Save' and make sure the Custom Gripper is enabled.
|
|
136
|
+
|
|
137
|
+
Then run:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
python3 -m pytest ./tests --cov=standardbots --custom-sensors
|
|
141
|
+
```
|
|
@@ -76,6 +76,55 @@ class RequestManager:
|
|
|
76
76
|
|
|
77
77
|
class Default:
|
|
78
78
|
_request_manager: RequestManager
|
|
79
|
+
class Calibration:
|
|
80
|
+
def __init__(self, request_manager: RequestManager):
|
|
81
|
+
self._request_manager = request_manager
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_active_calibration(
|
|
85
|
+
self,
|
|
86
|
+
) -> Response[
|
|
87
|
+
Union[
|
|
88
|
+
models.ActiveCalibrationResponse,
|
|
89
|
+
models.ErrorResponse,
|
|
90
|
+
None
|
|
91
|
+
],
|
|
92
|
+
models.ActiveCalibrationResponse
|
|
93
|
+
]:
|
|
94
|
+
"""
|
|
95
|
+
Get the active calibration for the robot.
|
|
96
|
+
|
|
97
|
+
"""
|
|
98
|
+
path = "/api/v1/calibration/active"
|
|
99
|
+
try:
|
|
100
|
+
response = self._request_manager.request(
|
|
101
|
+
"GET",
|
|
102
|
+
path,
|
|
103
|
+
headers=self._request_manager.json_headers(),
|
|
104
|
+
)
|
|
105
|
+
parsed = None
|
|
106
|
+
if response.status == 200:
|
|
107
|
+
parsed = models.parse_active_calibration_response(json.loads(response.data))
|
|
108
|
+
|
|
109
|
+
is_user_error = response.status >= 400 and response.status <= 500
|
|
110
|
+
is_unavailable = response.status == 503
|
|
111
|
+
if parsed is None and (is_user_error or is_unavailable):
|
|
112
|
+
parsed = models.parse_error_response(json.loads(response.data))
|
|
113
|
+
|
|
114
|
+
return Response(
|
|
115
|
+
parsed,
|
|
116
|
+
response.status,
|
|
117
|
+
response
|
|
118
|
+
)
|
|
119
|
+
except urllib3.exceptions.MaxRetryError:
|
|
120
|
+
return Response(
|
|
121
|
+
models.ErrorResponse(
|
|
122
|
+
error=models.ErrorEnum.InternalServerError,
|
|
123
|
+
message="Connection Refused"
|
|
124
|
+
),
|
|
125
|
+
503,
|
|
126
|
+
None
|
|
127
|
+
)
|
|
79
128
|
class Equipment:
|
|
80
129
|
def __init__(self, request_manager: RequestManager):
|
|
81
130
|
self._request_manager = request_manager
|
|
@@ -188,7 +237,7 @@ class Default:
|
|
|
188
237
|
return self.control_gripper(
|
|
189
238
|
body=models.GripperCommandRequest(
|
|
190
239
|
kind=models.GripperKindEnum.DhCgi,
|
|
191
|
-
|
|
240
|
+
dh_cgi=models.DHCGIGripperCommandRequest(
|
|
192
241
|
target_diameter, target_force, target_speed
|
|
193
242
|
),
|
|
194
243
|
),
|
|
@@ -382,12 +431,14 @@ class Default:
|
|
|
382
431
|
None
|
|
383
432
|
)
|
|
384
433
|
|
|
434
|
+
calibration: Calibration
|
|
385
435
|
equipment: Equipment
|
|
386
436
|
sensors: Sensors
|
|
387
437
|
space: Space
|
|
388
438
|
|
|
389
439
|
def __init__(self, request_manager: RequestManager):
|
|
390
440
|
self._request_manager = request_manager
|
|
441
|
+
self.calibration = Default.Calibration(request_manager)
|
|
391
442
|
self.equipment = Default.Equipment(request_manager)
|
|
392
443
|
self.sensors = Default.Sensors(request_manager)
|
|
393
444
|
self.space = Default.Space(request_manager)
|
|
@@ -713,7 +764,7 @@ class Camera:
|
|
|
713
764
|
None
|
|
714
765
|
]:
|
|
715
766
|
"""
|
|
716
|
-
Retrieve the latest RGB frame from the camera.
|
|
767
|
+
Retrieve the latest RGB frame from the camera. In JPEG format.
|
|
717
768
|
"""
|
|
718
769
|
path = "/api/v1/camera/frame/rgb"
|
|
719
770
|
try:
|
|
@@ -932,6 +983,113 @@ class Faults:
|
|
|
932
983
|
self._request_manager = request_manager
|
|
933
984
|
self.user_faults = Faults.UserFaults(request_manager)
|
|
934
985
|
|
|
986
|
+
class General:
|
|
987
|
+
_request_manager: RequestManager
|
|
988
|
+
class BotIdentity:
|
|
989
|
+
def __init__(self, request_manager: RequestManager):
|
|
990
|
+
self._request_manager = request_manager
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
def bot_identity(
|
|
994
|
+
self,
|
|
995
|
+
) -> Response[
|
|
996
|
+
Union[
|
|
997
|
+
models.BotIdentityData,
|
|
998
|
+
models.ErrorResponse,
|
|
999
|
+
None
|
|
1000
|
+
],
|
|
1001
|
+
models.BotIdentityData
|
|
1002
|
+
]:
|
|
1003
|
+
"""
|
|
1004
|
+
Get information about the robot's identity.
|
|
1005
|
+
"""
|
|
1006
|
+
path = "/api/v1/identity/bot_identity"
|
|
1007
|
+
try:
|
|
1008
|
+
response = self._request_manager.request(
|
|
1009
|
+
"GET",
|
|
1010
|
+
path,
|
|
1011
|
+
headers=self._request_manager.json_headers(),
|
|
1012
|
+
)
|
|
1013
|
+
parsed = None
|
|
1014
|
+
if response.status == 200:
|
|
1015
|
+
parsed = models.parse_bot_identity_data(json.loads(response.data))
|
|
1016
|
+
|
|
1017
|
+
is_user_error = response.status >= 400 and response.status <= 500
|
|
1018
|
+
is_unavailable = response.status == 503
|
|
1019
|
+
if parsed is None and (is_user_error or is_unavailable):
|
|
1020
|
+
parsed = models.parse_error_response(json.loads(response.data))
|
|
1021
|
+
|
|
1022
|
+
return Response(
|
|
1023
|
+
parsed,
|
|
1024
|
+
response.status,
|
|
1025
|
+
response
|
|
1026
|
+
)
|
|
1027
|
+
except urllib3.exceptions.MaxRetryError:
|
|
1028
|
+
return Response(
|
|
1029
|
+
models.ErrorResponse(
|
|
1030
|
+
error=models.ErrorEnum.InternalServerError,
|
|
1031
|
+
message="Connection Refused"
|
|
1032
|
+
),
|
|
1033
|
+
503,
|
|
1034
|
+
None
|
|
1035
|
+
)
|
|
1036
|
+
class Joints:
|
|
1037
|
+
def __init__(self, request_manager: RequestManager):
|
|
1038
|
+
self._request_manager = request_manager
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
def get_joints_state(
|
|
1042
|
+
self,
|
|
1043
|
+
) -> Response[
|
|
1044
|
+
Union[
|
|
1045
|
+
models.JointsStateResponse,
|
|
1046
|
+
models.ErrorResponse,
|
|
1047
|
+
None
|
|
1048
|
+
],
|
|
1049
|
+
models.JointsStateResponse
|
|
1050
|
+
]:
|
|
1051
|
+
"""
|
|
1052
|
+
Retrieves information about the state of each joint
|
|
1053
|
+
"""
|
|
1054
|
+
path = "/api/v1/joints"
|
|
1055
|
+
try:
|
|
1056
|
+
response = self._request_manager.request(
|
|
1057
|
+
"GET",
|
|
1058
|
+
path,
|
|
1059
|
+
headers=self._request_manager.json_headers(),
|
|
1060
|
+
)
|
|
1061
|
+
parsed = None
|
|
1062
|
+
if response.status == 200:
|
|
1063
|
+
parsed = models.parse_joints_state_response(json.loads(response.data))
|
|
1064
|
+
|
|
1065
|
+
is_user_error = response.status >= 400 and response.status <= 500
|
|
1066
|
+
is_unavailable = response.status == 503
|
|
1067
|
+
if parsed is None and (is_user_error or is_unavailable):
|
|
1068
|
+
parsed = models.parse_error_response(json.loads(response.data))
|
|
1069
|
+
|
|
1070
|
+
return Response(
|
|
1071
|
+
parsed,
|
|
1072
|
+
response.status,
|
|
1073
|
+
response
|
|
1074
|
+
)
|
|
1075
|
+
except urllib3.exceptions.MaxRetryError:
|
|
1076
|
+
return Response(
|
|
1077
|
+
models.ErrorResponse(
|
|
1078
|
+
error=models.ErrorEnum.InternalServerError,
|
|
1079
|
+
message="Connection Refused"
|
|
1080
|
+
),
|
|
1081
|
+
503,
|
|
1082
|
+
None
|
|
1083
|
+
)
|
|
1084
|
+
|
|
1085
|
+
bot_identity: BotIdentity
|
|
1086
|
+
joints: Joints
|
|
1087
|
+
|
|
1088
|
+
def __init__(self, request_manager: RequestManager):
|
|
1089
|
+
self._request_manager = request_manager
|
|
1090
|
+
self.bot_identity = General.BotIdentity(request_manager)
|
|
1091
|
+
self.joints = General.Joints(request_manager)
|
|
1092
|
+
|
|
935
1093
|
class ChatGPT:
|
|
936
1094
|
_request_manager: RequestManager
|
|
937
1095
|
class Data:
|
|
@@ -1136,63 +1294,6 @@ class IO:
|
|
|
1136
1294
|
self.control = IO.Control(request_manager)
|
|
1137
1295
|
self.status = IO.Status(request_manager)
|
|
1138
1296
|
|
|
1139
|
-
class General:
|
|
1140
|
-
_request_manager: RequestManager
|
|
1141
|
-
class Joints:
|
|
1142
|
-
def __init__(self, request_manager: RequestManager):
|
|
1143
|
-
self._request_manager = request_manager
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
def get_joints_state(
|
|
1147
|
-
self,
|
|
1148
|
-
) -> Response[
|
|
1149
|
-
Union[
|
|
1150
|
-
models.JointsStateResponse,
|
|
1151
|
-
models.ErrorResponse,
|
|
1152
|
-
None
|
|
1153
|
-
],
|
|
1154
|
-
models.JointsStateResponse
|
|
1155
|
-
]:
|
|
1156
|
-
"""
|
|
1157
|
-
Retrieves information about the state of each joint
|
|
1158
|
-
"""
|
|
1159
|
-
path = "/api/v1/joints"
|
|
1160
|
-
try:
|
|
1161
|
-
response = self._request_manager.request(
|
|
1162
|
-
"GET",
|
|
1163
|
-
path,
|
|
1164
|
-
headers=self._request_manager.json_headers(),
|
|
1165
|
-
)
|
|
1166
|
-
parsed = None
|
|
1167
|
-
if response.status == 200:
|
|
1168
|
-
parsed = models.parse_joints_state_response(json.loads(response.data))
|
|
1169
|
-
|
|
1170
|
-
is_user_error = response.status >= 400 and response.status <= 500
|
|
1171
|
-
is_unavailable = response.status == 503
|
|
1172
|
-
if parsed is None and (is_user_error or is_unavailable):
|
|
1173
|
-
parsed = models.parse_error_response(json.loads(response.data))
|
|
1174
|
-
|
|
1175
|
-
return Response(
|
|
1176
|
-
parsed,
|
|
1177
|
-
response.status,
|
|
1178
|
-
response
|
|
1179
|
-
)
|
|
1180
|
-
except urllib3.exceptions.MaxRetryError:
|
|
1181
|
-
return Response(
|
|
1182
|
-
models.ErrorResponse(
|
|
1183
|
-
error=models.ErrorEnum.InternalServerError,
|
|
1184
|
-
message="Connection Refused"
|
|
1185
|
-
),
|
|
1186
|
-
503,
|
|
1187
|
-
None
|
|
1188
|
-
)
|
|
1189
|
-
|
|
1190
|
-
joints: Joints
|
|
1191
|
-
|
|
1192
|
-
def __init__(self, request_manager: RequestManager):
|
|
1193
|
-
self._request_manager = request_manager
|
|
1194
|
-
self.joints = General.Joints(request_manager)
|
|
1195
|
-
|
|
1196
1297
|
class Poses:
|
|
1197
1298
|
_request_manager: RequestManager
|
|
1198
1299
|
class ConstructPose:
|
|
@@ -1662,15 +1763,15 @@ class Recovery:
|
|
|
1662
1763
|
self,
|
|
1663
1764
|
) -> Response[
|
|
1664
1765
|
Union[
|
|
1665
|
-
models.
|
|
1766
|
+
models.FailureStateResponse,
|
|
1666
1767
|
models.ErrorResponse,
|
|
1667
1768
|
models.ErrorResponse,
|
|
1668
1769
|
None
|
|
1669
1770
|
],
|
|
1670
|
-
models.
|
|
1771
|
+
models.FailureStateResponse
|
|
1671
1772
|
]:
|
|
1672
1773
|
"""
|
|
1673
|
-
|
|
1774
|
+
Attempts to recover the robot from a fault state. Inspect the response to determine if additional recovery actions are required.
|
|
1674
1775
|
|
|
1675
1776
|
"""
|
|
1676
1777
|
path = "/api/v1/recovery/recover"
|
|
@@ -1682,7 +1783,7 @@ class Recovery:
|
|
|
1682
1783
|
)
|
|
1683
1784
|
parsed = None
|
|
1684
1785
|
if response.status == 200:
|
|
1685
|
-
parsed = models.
|
|
1786
|
+
parsed = models.parse_failure_state_response(json.loads(response.data))
|
|
1686
1787
|
if response.status == 400:
|
|
1687
1788
|
parsed = models.parse_error_response(json.loads(response.data))
|
|
1688
1789
|
|
|
@@ -2493,9 +2594,9 @@ class StandardBotsRobot(Default):
|
|
|
2493
2594
|
movement: Movement
|
|
2494
2595
|
camera: Camera
|
|
2495
2596
|
faults: Faults
|
|
2597
|
+
general: General
|
|
2496
2598
|
chat_gpt: ChatGPT
|
|
2497
2599
|
io: IO
|
|
2498
|
-
general: General
|
|
2499
2600
|
poses: Poses
|
|
2500
2601
|
recovery: Recovery
|
|
2501
2602
|
ros: ROS
|
|
@@ -2517,9 +2618,9 @@ class StandardBotsRobot(Default):
|
|
|
2517
2618
|
self.movement = Movement(self._request_manager)
|
|
2518
2619
|
self.camera = Camera(self._request_manager)
|
|
2519
2620
|
self.faults = Faults(self._request_manager)
|
|
2621
|
+
self.general = General(self._request_manager)
|
|
2520
2622
|
self.chat_gpt = ChatGPT(self._request_manager)
|
|
2521
2623
|
self.io = IO(self._request_manager)
|
|
2522
|
-
self.general = General(self._request_manager)
|
|
2523
2624
|
self.poses = Poses(self._request_manager)
|
|
2524
2625
|
self.recovery = Recovery(self._request_manager)
|
|
2525
2626
|
self.ros = ROS(self._request_manager)
|