standardbots 2.0.1__tar.gz → 2.1.1__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.0.1 → standardbots-2.1.1}/PKG-INFO +1 -1
- {standardbots-2.0.1 → standardbots-2.1.1}/README.md +38 -22
- {standardbots-2.0.1 → standardbots-2.1.1}/setup.py +1 -1
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots/auto_generated/models.py +4 -2
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots.egg-info/PKG-INFO +1 -1
- {standardbots-2.0.1 → standardbots-2.1.1}/tests/test_apis.py +25 -28
- {standardbots-2.0.1 → standardbots-2.1.1}/setup.cfg +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots/__init__.py +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots/auto_generated/__init__.py +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots/auto_generated/apis.py +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots.egg-info/SOURCES.txt +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots.egg-info/dependency_links.txt +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots.egg-info/requires.txt +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/standardbots.egg-info/top_level.txt +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/tests/fixtures/__init__.py +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/tests/fixtures/client_fixt.py +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/tests/fixtures/robot_fixt.py +0 -0
- {standardbots-2.0.1 → standardbots-2.1.1}/tests/fixtures/routines_fixt.py +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
You can test the API by using the playground, add your own file or use the
|
|
2
|
-
When a client has an issue, and they send their code.
|
|
1
|
+
You can test the API by using the playground, add your own file or use the
|
|
2
|
+
existing python scripts. When a client has an issue, and they send their code.
|
|
3
|
+
It's helpful to test their code to see possible issues
|
|
3
4
|
|
|
4
5
|
# ENABLE API ON YOUR LOCAL MACHINE
|
|
5
6
|
|
|
6
|
-
Follow the steps here
|
|
7
|
+
Follow the steps here
|
|
8
|
+
https://www.notion.so/standardbots/Using-the-REST-API-b2c778d47969444dac61483f0117acad
|
|
7
9
|
|
|
8
10
|
# CONFIG
|
|
9
11
|
|
|
@@ -11,7 +13,8 @@ At the top of the file, use your token
|
|
|
11
13
|
|
|
12
14
|
# RUN
|
|
13
15
|
|
|
14
|
-
To run a script move into the `sdks/python` folder and run
|
|
16
|
+
To run a script move into the `sdks/python` folder and run
|
|
17
|
+
`python playground/filename.py`
|
|
15
18
|
|
|
16
19
|
# To create a test build
|
|
17
20
|
|
|
@@ -48,8 +51,8 @@ To set up tests:
|
|
|
48
51
|
cd sdks/python
|
|
49
52
|
```
|
|
50
53
|
|
|
51
|
-
Note: Make sure to select proper python interpreter.
|
|
52
|
-
|
|
54
|
+
Note: Make sure to select proper python interpreter. Sometimes there is an error
|
|
55
|
+
related to missing "dotenv" module, to solve this install it separately
|
|
53
56
|
|
|
54
57
|
```
|
|
55
58
|
python3 -m pip install python-dotenv
|
|
@@ -60,16 +63,18 @@ python3 -m pip install -r requirements-dev.txt
|
|
|
60
63
|
|
|
61
64
|
#### Sample routine
|
|
62
65
|
|
|
63
|
-
You need to add the sample routine in
|
|
66
|
+
You need to add the sample routine in
|
|
67
|
+
[sdks/python/tests/fixtures/test_public_api_routine.json](./tests/fixtures/test_public_api_routine.json)
|
|
68
|
+
to your target test environment (i.e. upload the routine to ).
|
|
64
69
|
|
|
65
70
|
The name of routine should be "Test Public API"
|
|
66
71
|
|
|
67
72
|
#### Sample globals
|
|
68
73
|
|
|
69
|
-
- _Variable._ Add global variable called "test_public_api_global" with any
|
|
74
|
+
- _Variable._ Add global variable called "test_public_api_global" with any
|
|
75
|
+
value.
|
|
70
76
|
- _Space._ Create a global space called "Test global space" of any kind.
|
|
71
77
|
|
|
72
|
-
|
|
73
78
|
## Running
|
|
74
79
|
|
|
75
80
|
Here is a basic test command:
|
|
@@ -81,7 +86,8 @@ SB_API_TOKEN=...
|
|
|
81
86
|
python3 -m pytest ./tests --cov=standardbots --token=$SB_API_TOKEN --api-url=$SB_API_URL
|
|
82
87
|
```
|
|
83
88
|
|
|
84
|
-
You may also set up a `.env` file at `sdks/python/.env` with the following
|
|
89
|
+
You may also set up a `.env` file at `sdks/python/.env` with the following
|
|
90
|
+
contents:
|
|
85
91
|
|
|
86
92
|
```bash
|
|
87
93
|
export SB_API_URL=http://34.162.0.32:3000
|
|
@@ -96,38 +102,43 @@ python3 -m pytest ./tests --cov=standardbots
|
|
|
96
102
|
|
|
97
103
|
### Robot state and testing (Markers)
|
|
98
104
|
|
|
99
|
-
We need the bot to be in a certain state to run certain tests. For example, we
|
|
105
|
+
We need the bot to be in a certain state to run certain tests. For example, we
|
|
106
|
+
need a routine to be running in order to stop the routine. Camera should be
|
|
107
|
+
disconnected by default.
|
|
100
108
|
|
|
101
109
|
At start of testing, robot should:
|
|
102
110
|
|
|
103
111
|
- _NOT_ be e-stopped.
|
|
104
112
|
|
|
105
|
-
|
|
106
113
|
The basic idea here is:
|
|
107
114
|
|
|
108
115
|
- These special tests will not be run by default.
|
|
109
|
-
- You may pass a flag (e.g. `--camera-
|
|
116
|
+
- You may pass a flag (e.g. `--camera-connected`) when the bot is in the correct
|
|
117
|
+
state to run the tests.
|
|
110
118
|
- Markers usage:
|
|
111
|
-
- When `--gripper=<type>` flag is passed(`type` is value from `GripperKindEnum`
|
|
119
|
+
- When `--gripper=<type>` flag is passed(`type` is value from `GripperKindEnum`
|
|
120
|
+
enum):
|
|
112
121
|
1. Tests expect that this specific gripper is connected
|
|
113
122
|
2. Tests without the flag are not run.
|
|
114
|
-
- When `--camera-
|
|
123
|
+
- When `--camera-connected` flag is passed:
|
|
115
124
|
1. Tests with the flag are run.
|
|
116
125
|
2. Tests without the flag are not run.
|
|
117
126
|
|
|
118
|
-
We use [pytest markers](https://docs.pytest.org/en/7.1.x/example/markers.html)
|
|
127
|
+
We use [pytest markers](https://docs.pytest.org/en/7.1.x/example/markers.html)
|
|
128
|
+
to do this.
|
|
119
129
|
|
|
120
130
|
#### Camera disconnected
|
|
121
131
|
|
|
122
132
|
The wrist camera should be disabled. Then run:
|
|
123
133
|
|
|
124
134
|
```bash
|
|
125
|
-
python3 -m pytest ./tests --cov=standardbots --camera-
|
|
135
|
+
python3 -m pytest ./tests --cov=standardbots --camera-connected
|
|
126
136
|
```
|
|
127
137
|
|
|
128
138
|
#### E-stop
|
|
129
139
|
|
|
130
|
-
No marker needed for e-stop. However, we do rely on active recovery of e-stop
|
|
140
|
+
No marker needed for e-stop. However, we do rely on active recovery of e-stop
|
|
141
|
+
and getting the failure state in order to do these tests.
|
|
131
142
|
|
|
132
143
|
When e-stop test runs, cannot have bot in a failure state (pre-test will fail).
|
|
133
144
|
|
|
@@ -151,16 +162,19 @@ tests/test_apis.py
|
|
|
151
162
|
Fixes:
|
|
152
163
|
|
|
153
164
|
- _Make sure you can log into remote control._ Ensure that botman is connected.
|
|
154
|
-
- _Ensure that the robot URL is up-to-date._ Botman url will often change when
|
|
165
|
+
- _Ensure that the robot URL is up-to-date._ Botman url will often change when
|
|
166
|
+
you reboot.
|
|
155
167
|
|
|
156
168
|
### Custom sensors
|
|
157
169
|
|
|
158
170
|
To test custom sensors:
|
|
171
|
+
|
|
159
172
|
- go to the menu on the left bottom corner;
|
|
160
173
|
- Click on 'Equipment';
|
|
161
174
|
- Add Gripper > Custom Gripper;
|
|
162
175
|
- Go to the Sensors tab and click 'Add Sensor';
|
|
163
|
-
- Keep the default values as they are (name: 'Sensor 1', kind: 'Control Box IO',
|
|
176
|
+
- Keep the default values as they are (name: 'Sensor 1', kind: 'Control Box IO',
|
|
177
|
+
sensor value: 'low');
|
|
164
178
|
- Hit 'Save' and make sure the Custom Gripper is enabled.
|
|
165
179
|
|
|
166
180
|
Then run:
|
|
@@ -173,11 +187,13 @@ python3 -m pytest ./tests --cov=standardbots --gripper=custom_sensors
|
|
|
173
187
|
|
|
174
188
|
> See command: `botctl publicapi test:setup-bot`.
|
|
175
189
|
|
|
176
|
-
We now have a common robot database state that can be used for testing. While
|
|
190
|
+
We now have a common robot database state that can be used for testing. While
|
|
191
|
+
this isn't necessary for use, it does provide a common state for testing.
|
|
177
192
|
|
|
178
193
|
### How to create a new backup
|
|
179
194
|
|
|
180
|
-
In the place where you are running the stack and want to create the backup (e.g.
|
|
195
|
+
In the place where you are running the stack and want to create the backup (e.g.
|
|
196
|
+
on the control box):
|
|
181
197
|
|
|
182
198
|
```bash
|
|
183
199
|
DB_USER=sb
|
|
@@ -2478,6 +2478,8 @@ class RecorderStatus(Enum):
|
|
|
2478
2478
|
"""Enum Error = `error`"""
|
|
2479
2479
|
Complete = "complete"
|
|
2480
2480
|
"""Enum Complete = `complete`"""
|
|
2481
|
+
Initializing = "initializing"
|
|
2482
|
+
"""Enum Initializing = `initializing`"""
|
|
2481
2483
|
|
|
2482
2484
|
def parse_recorder_status(data: object) -> RecorderStatus:
|
|
2483
2485
|
return RecorderStatus(data)
|
|
@@ -6445,7 +6447,7 @@ class RecorderBotDetails:
|
|
|
6445
6447
|
if value is None:
|
|
6446
6448
|
return [True, ""]
|
|
6447
6449
|
|
|
6448
|
-
if not ((isinstance(value, str) and RecorderStatus in ['not_recording', 'recording', 'error', 'complete']) or isinstance(value, RecorderStatus)):
|
|
6450
|
+
if not ((isinstance(value, str) and RecorderStatus in ['not_recording', 'recording', 'error', 'complete', 'initializing']) or isinstance(value, RecorderStatus)):
|
|
6449
6451
|
return [False, "status must be of type RecorderStatus for RecorderBotDetails, got " + type(value).__name__]
|
|
6450
6452
|
|
|
6451
6453
|
return [True, ""]
|
|
@@ -8780,7 +8782,7 @@ class RecorderState:
|
|
|
8780
8782
|
if value is None:
|
|
8781
8783
|
return [True, ""]
|
|
8782
8784
|
|
|
8783
|
-
if not ((isinstance(value, str) and RecorderStatus in ['not_recording', 'recording', 'error', 'complete']) or isinstance(value, RecorderStatus)):
|
|
8785
|
+
if not ((isinstance(value, str) and RecorderStatus in ['not_recording', 'recording', 'error', 'complete', 'initializing']) or isinstance(value, RecorderStatus)):
|
|
8784
8786
|
return [False, "status must be of type RecorderStatus for RecorderState, got " + type(value).__name__]
|
|
8785
8787
|
|
|
8786
8788
|
return [True, ""]
|
|
@@ -285,17 +285,17 @@ class TestGetEquipment:
|
|
|
285
285
|
assert isinstance(res.data, models.GetEquipmentConfigResponse)
|
|
286
286
|
assert res.data.equipment is not None
|
|
287
287
|
assert isinstance(res.data.equipment, list)
|
|
288
|
-
|
|
289
|
-
|
|
288
|
+
if len(res.data.equipment) > 0:
|
|
289
|
+
assert isinstance(res.data.equipment[0], models.EquipmentConfig)
|
|
290
290
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
291
|
+
equipment = res.data.equipment[0]
|
|
292
|
+
assert equipment.id is not None
|
|
293
|
+
assert equipment.kind is not None
|
|
294
|
+
assert equipment.is_enabled is not None
|
|
295
|
+
assert equipment.config is not None
|
|
296
296
|
|
|
297
|
-
|
|
298
|
-
|
|
297
|
+
# Can be parsed as JSON
|
|
298
|
+
assert json.loads(equipment.config) is not None
|
|
299
299
|
|
|
300
300
|
|
|
301
301
|
class TestGetEquipmentEndEffectorConfiguration:
|
|
@@ -991,12 +991,12 @@ class TestPostMovementBrakesEmergencyStop:
|
|
|
991
991
|
break
|
|
992
992
|
assert data.failure.kind == "EStopTriggered"
|
|
993
993
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
994
|
+
# ######################################
|
|
995
|
+
# Recover from e-stop
|
|
996
|
+
# ######################################
|
|
997
997
|
|
|
998
|
-
|
|
999
|
-
|
|
998
|
+
with client.connection():
|
|
999
|
+
res_status = client.recovery.recover.recover()
|
|
1000
1000
|
|
|
1001
1001
|
def test_estop_sim(self, client_sim: StandardBotsRobot) -> None:
|
|
1002
1002
|
"""Basic test: sim mode
|
|
@@ -1324,7 +1324,7 @@ class TestPostMovementPositionArm:
|
|
|
1324
1324
|
z=0.707,
|
|
1325
1325
|
w=0.707,
|
|
1326
1326
|
)
|
|
1327
|
-
initial_tooltip_position = models.Position(x=0.0, y=0.3687, z=1.
|
|
1327
|
+
initial_tooltip_position = models.Position(x=0.0, y=0.3687, z=1.3618)
|
|
1328
1328
|
target_tooltip_position = models.Position(x=0.1, y=0.4, z=1.3)
|
|
1329
1329
|
pose_body = models.ArmPositionUpdateRequest(
|
|
1330
1330
|
kind=models.ArmPositionUpdateRequestKindEnum.TooltipPosition,
|
|
@@ -1627,7 +1627,6 @@ class TestGetRecoveryStatus:
|
|
|
1627
1627
|
class TestGetCameraStreamRGB:
|
|
1628
1628
|
"""Tests: [GET] `/api/v1/camera/stream/rgb`"""
|
|
1629
1629
|
|
|
1630
|
-
@pytest.mark.camera_disconnected
|
|
1631
1630
|
def test_camera_stream_rgb_camera_disconnected(
|
|
1632
1631
|
self, client_live: StandardBotsRobot
|
|
1633
1632
|
) -> None:
|
|
@@ -1639,6 +1638,7 @@ class TestGetCameraStreamRGB:
|
|
|
1639
1638
|
assert res.isNotOk()
|
|
1640
1639
|
assert res.status == 503
|
|
1641
1640
|
|
|
1641
|
+
@pytest.mark.camera_connected
|
|
1642
1642
|
def test_basic(self, client_live: StandardBotsRobot) -> None:
|
|
1643
1643
|
"""Basic test to get camera steam RGB"""
|
|
1644
1644
|
client = client_live
|
|
@@ -1674,7 +1674,6 @@ class TestGetCameraStreamRGB:
|
|
|
1674
1674
|
class TestPostCameraSettings:
|
|
1675
1675
|
"""Tests: [POST] `/api/v1/camera/settings`"""
|
|
1676
1676
|
|
|
1677
|
-
@pytest.mark.camera_disconnected
|
|
1678
1677
|
def test_post_camera_settings_camera_disconnected(
|
|
1679
1678
|
self, client_live: StandardBotsRobot
|
|
1680
1679
|
) -> None:
|
|
@@ -1694,6 +1693,7 @@ class TestPostCameraSettings:
|
|
|
1694
1693
|
assert res.isNotOk()
|
|
1695
1694
|
assert res.status == 503
|
|
1696
1695
|
|
|
1696
|
+
@pytest.mark.camera_connected
|
|
1697
1697
|
def test_post_camera_settings(self, client_live: StandardBotsRobot) -> None:
|
|
1698
1698
|
"""Basic test to update settings"""
|
|
1699
1699
|
client = client_live
|
|
@@ -1715,7 +1715,6 @@ class TestPostCameraSettings:
|
|
|
1715
1715
|
class TestGetCameraFrameRGB:
|
|
1716
1716
|
"""Tests: [GET] `/api/v1/camera/frame/rgb`"""
|
|
1717
1717
|
|
|
1718
|
-
@pytest.mark.camera_disconnected
|
|
1719
1718
|
def test_strem_rgb_camera_disconnected(
|
|
1720
1719
|
self, client_live: StandardBotsRobot
|
|
1721
1720
|
) -> None:
|
|
@@ -1737,6 +1736,7 @@ class TestGetCameraFrameRGB:
|
|
|
1737
1736
|
assert res.isNotOk()
|
|
1738
1737
|
assert res.status == 503
|
|
1739
1738
|
|
|
1739
|
+
@pytest.mark.camera_connected
|
|
1740
1740
|
def test_get_color_frame_invalid_payload(
|
|
1741
1741
|
self, client_live: StandardBotsRobot
|
|
1742
1742
|
) -> None:
|
|
@@ -1749,6 +1749,7 @@ class TestGetCameraFrameRGB:
|
|
|
1749
1749
|
assert res.status == 400
|
|
1750
1750
|
assert res.data.error == models.ErrorEnum.RequestFailedValidation
|
|
1751
1751
|
|
|
1752
|
+
@pytest.mark.camera_connected
|
|
1752
1753
|
def test_get_color_frame(self, client_live: StandardBotsRobot) -> None:
|
|
1753
1754
|
"""Test get color frame"""
|
|
1754
1755
|
client = client_live
|
|
@@ -1778,7 +1779,6 @@ class TestGetCameraFrameRGB:
|
|
|
1778
1779
|
class TestGetCameraIntrinsicsRGB:
|
|
1779
1780
|
"""Tests: [GET] `/api/v1/camera/intrinsics/rgb`"""
|
|
1780
1781
|
|
|
1781
|
-
@pytest.mark.camera_disconnected
|
|
1782
1782
|
def test_get_camera_intrinsics_camera_disconnected(
|
|
1783
1783
|
self, client_live: StandardBotsRobot
|
|
1784
1784
|
) -> None:
|
|
@@ -1789,6 +1789,7 @@ class TestGetCameraIntrinsicsRGB:
|
|
|
1789
1789
|
assert res.isNotOk()
|
|
1790
1790
|
assert res.status == 503
|
|
1791
1791
|
|
|
1792
|
+
@pytest.mark.camera_connected
|
|
1792
1793
|
def test_get_camera_intrinsics(self, client_live: StandardBotsRobot) -> None:
|
|
1793
1794
|
"""Test to get camera intrinsics"""
|
|
1794
1795
|
|
|
@@ -1804,7 +1805,6 @@ class TestGetCameraIntrinsicsRGB:
|
|
|
1804
1805
|
class TestGetCameraStatus:
|
|
1805
1806
|
"""Tests: [GET] `/api/v1/camera/status`"""
|
|
1806
1807
|
|
|
1807
|
-
@pytest.mark.camera_disconnected
|
|
1808
1808
|
def test_get_camera_status_camera_disconnected(
|
|
1809
1809
|
self, client_live: StandardBotsRobot
|
|
1810
1810
|
) -> None:
|
|
@@ -1817,6 +1817,7 @@ class TestGetCameraStatus:
|
|
|
1817
1817
|
assert isinstance(res.data, models.CameraStatus)
|
|
1818
1818
|
assert not res.data.connected
|
|
1819
1819
|
|
|
1820
|
+
@pytest.mark.camera_connected
|
|
1820
1821
|
def test_get_camera_status(self, client_live: StandardBotsRobot) -> None:
|
|
1821
1822
|
"""Test to get camera status"""
|
|
1822
1823
|
|
|
@@ -1832,6 +1833,7 @@ class TestGetCameraStatus:
|
|
|
1832
1833
|
class TestGetConnectedCameras:
|
|
1833
1834
|
"""Tests: [GET] `/api/v1/cameras/connected`"""
|
|
1834
1835
|
|
|
1836
|
+
@pytest.mark.camera_connected
|
|
1835
1837
|
def test_get_connected_cameras(self, client_live: StandardBotsRobot) -> None:
|
|
1836
1838
|
"""Test case when camera is disconnected"""
|
|
1837
1839
|
|
|
@@ -2684,9 +2686,7 @@ class TestPostPosesJointPose:
|
|
|
2684
2686
|
client = client_live
|
|
2685
2687
|
with client.connection():
|
|
2686
2688
|
body = models.JointPoseRequest(
|
|
2687
|
-
pose=models.JointAngles(
|
|
2688
|
-
j0=20.0, j1=-30.0, j2=71.0, j3=-130.0, j4=-43.0, j5=60.0
|
|
2689
|
-
)
|
|
2689
|
+
pose=models.JointAngles(j0=1.0, j1=-1.0, j2=1.0, j3=1.0, j4=1.0, j5=1.0)
|
|
2690
2690
|
)
|
|
2691
2691
|
res = client.poses.construct_pose.joint_pose(body)
|
|
2692
2692
|
assert not res.isNotOk()
|
|
@@ -3322,10 +3322,7 @@ class TestPostMovementPositionArmControlled:
|
|
|
3322
3322
|
assert heartbeat_data.event is not None
|
|
3323
3323
|
assert heartbeat_data.event.kind == models.ArmPositionUpdateKindEnum.Failure
|
|
3324
3324
|
assert heartbeat_data.event.failure is not None
|
|
3325
|
-
assert
|
|
3326
|
-
heartbeat_data.event.failure.reason
|
|
3327
|
-
== "Failed to generate a motion plan"
|
|
3328
|
-
)
|
|
3325
|
+
assert heartbeat_data.event.failure.reason == "Error while running motion"
|
|
3329
3326
|
|
|
3330
3327
|
def test_move_then_stop_heartbeat(
|
|
3331
3328
|
self,
|
|
@@ -3393,7 +3390,7 @@ class TestPostMovementPositionArmControlled:
|
|
|
3393
3390
|
)
|
|
3394
3391
|
|
|
3395
3392
|
assert movement_started > 0, "Movement never started"
|
|
3396
|
-
time.sleep(
|
|
3393
|
+
time.sleep(3)
|
|
3397
3394
|
|
|
3398
3395
|
# Check that the arm has stopped
|
|
3399
3396
|
res = client.recovery.recover.get_status()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|