Skip to content

Commit 29f02eb

Browse files
Merge pull request #25 from UniversalRobots/update-from-internal-repo
Update from internal repo
2 parents b23ae7a + f201dcb commit 29f02eb

File tree

10 files changed

+157
-42
lines changed

10 files changed

+157
-42
lines changed

.devcontainer/Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM python:3
2+
3+
# Install python development requirements
4+
COPY requirements-dev.txt /tmp/requirements-dev.txt
5+
RUN pip install --no-cache-dir -r /tmp/requirements-dev.txt
6+
7+
# Install maven and clean up
8+
RUN apt-get update \
9+
&& apt-get install -y maven \
10+
&& apt-get clean \
11+
&& rm -rf /var/lib/apt/lists/*
12+
13+
# set the working directory
14+
WORKDIR /workspace
15+
16+
# Add normal user. USER_UID, and USER_GID are passed from local environment by devcontainer.json.
17+
# Otherwise all files are created with root privileges.
18+
ARG USER_UID
19+
ARG USER_GID
20+
21+
RUN groupadd --gid $USER_GID devuser \
22+
&& useradd --uid $USER_UID --gid $USER_GID --create-home --shell /bin/bash devuser
23+
24+
USER devuser

.devcontainer/devcontainer.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "Python 3 & Maven Dev Container",
3+
"build": {
4+
"dockerfile": "Dockerfile",
5+
"args": {
6+
"USER_UID": "${localEnv:UID:1000}",
7+
"USER_GID": "${localEnv:GID:1000}"
8+
}
9+
},
10+
"customizations": {
11+
"vscode": {
12+
"extensions": [
13+
"ms-python.python"
14+
],
15+
"settings": {
16+
"python.formatting.provider": "black"
17+
}
18+
}
19+
},
20+
"runArgs": [
21+
"--add-host=controller:host-gateway"
22+
]
23+
}

.devcontainer/requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
black

README.md

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# RTDE client library - Python
22
Library implements API for Universal Robots RTDE realtime interface.
33

4-
Full RTDE description is available on [Universal Robots support site](https://www.universal-robots.com/support/)
4+
Full RTDE description is available on [Universal Robots documentation site](https://docs.universal-robots.com/tutorials/communication-protocol-tutorials/rtde-guide.html)
55
# Project structure
66
## rtde
77
RTDE core library
@@ -22,18 +22,24 @@ Copy rtde_control_loop.urp to the robot. Start python script before starting pro
2222
- example_plotting.py - example for using csv_reader, and plotting selected data.
2323

2424
### Running examples
25-
It's recommended to run examples in [virtual environment](https://docs.python.org/3/library/venv.html).
26-
Some require additional libraries.
27-
```
25+
It's recommended to run examples in [virtual environment](https://docs.python.org/3/library/venv.html) or [devcontainer](#using-devcontainer).
26+
```bash
27+
# Example for recording realtime data from the robot
28+
# NOTE: RTDE interface has to be enabled in the robot security settings
29+
cd examples
2830
python record.py -h
2931
python record.py --host 192.168.0.1 --frequency 10
3032
```
31-
# Using robot simulator in Docker
32-
RTDE can connect from host system to controller running in Docker
33+
# Using robot simulator in a Docker
34+
RTDE can connect from host system or [devcontainer](#using-devcontainer) to controller running in a Docker
3335
when RTDE port 30004 is forwarded.
34-
1. Get latest ursim docker image: docker pull universalrobots/ursim_e-series
35-
2. Run docker container: docker run --rm -dit -p 30004:30004 -p 5900:5900 -p 6080:6080 universalrobots/ursim_e-series
36-
3. open vnc client in browser, and confirm safet: http://localhost:6080/vnc.html?host=docker_ip&port=6080
36+
```bash
37+
# 1. Get latest ursim docker image
38+
docker pull universalrobots/ursim_e-series
39+
# 2. Run docker container:
40+
docker run --rm -dit -p 30004:30004 -p 5900:5900 -p 6080:6080 universalrobots/ursim_e-series
41+
# 3. open vnc client in browser, and confirm safety: http://localhost:6080/vnc.html?host=docker_ip&port=6080
42+
```
3743

3844
More information about ursim docker image is available on [Dockerhub](https://hub.docker.com/r/universalrobots/ursim_e-series)
3945

@@ -49,43 +55,64 @@ when RTDE port 30004 is forwarded.
4955
Leave host, and guest IP fields blank.
5056

5157
# Using rtde library
52-
Copy rtde folder python project
58+
Copy rtde folder to python project or install with
59+
```bash
60+
pip install .
61+
# or use pre-built package from github
62+
pip install ./rtde-<version>-release.zip
63+
pip install https://github.com/UniversalRobots/RTDE_Python_Client_Library/releases/download/[version]/rtde-[version]-release.zip
64+
```
65+
5366
Library is compatible with Python 2.7+, and Python 3.6+
5467

5568
# Build release package
56-
```
69+
```bash
5770
mvn package
5871
```
59-
## Using with virtual environment
72+
## Using pre-built package with virtual environment
6073
Create virtual environment, and install wheel package
6174

6275
### Linux & MacOS
63-
```
76+
```bash
6477
python -m venv venv
6578
source venv/bin/activate
6679
pip install wheel
67-
```
68-
Install rtde package
69-
```
80+
# Install pre-built rtde package
7081
pip install target/rtde-<version>-release.zip
7182
```
7283

7384
### Windows PowerShell
7485
If Python3 is not installed, then just run python3 from powershell. Microsoft store will launch the installation.
7586

7687
Permission to run scripts in console is needed to activate virtual envrionment.
77-
```
88+
```PowerShell
7889
set-executionpolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
7990
python -m venv venv
8091
venv/Scripts/Activate.ps1
8192
pip install wheel
82-
```
83-
Install rtde package
84-
```
93+
# Install pre-built rtde package
8594
pip install target/rtde-<version>-release.zip
8695
```
8796

97+
## Using devcontainer
98+
Open project in VSCode and select to "reopen in devcontainer".
99+
Execute build command from terminal
100+
101+
Running record.py against simulator:
102+
```bash
103+
# first start simulator exposing RTDE port 30004
104+
# docker run --rm -dit -p 30004:30004 -p 5900:5900 -p 6080:6080 universalrobots/ursim_e-series
105+
106+
# in devcontainer terminal type
107+
cd examples
108+
./record.py --host controller --frequency 10 --verbose
109+
```
110+
88111
# Contributor guidelines
89112
Code is formatted with [black](https://github.com/psf/black).
90113
Run code formatter before submitting pull request.
91114

115+
```bash
116+
# open project in devcontainer
117+
python -m black .
118+
```

examples/record.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,6 @@
5555
help="data output file to write to (robot_data.csv)",
5656
)
5757
parser.add_argument("--verbose", help="increase output verbosity", action="store_true")
58-
parser.add_argument(
59-
"--buffered",
60-
help="Use buffered receive which doesn't skip data",
61-
action="store_true",
62-
)
6358
parser.add_argument(
6459
"--binary", help="save the data in binary format", action="store_true"
6560
)
@@ -114,10 +109,7 @@
114109
if args.samples > 0 and i >= args.samples:
115110
keep_running = False
116111
try:
117-
if args.buffered:
118-
state = con.receive_buffered(args.binary)
119-
else:
120-
state = con.receive(args.binary)
112+
state = con.receive_buffered(args.binary)
121113
if state is not None:
122114
writer.writerow(state)
123115
i += 1

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<modelVersion>4.0.0</modelVersion>
77
<groupId>com.ur.rtde.client</groupId>
88
<artifactId>rtde</artifactId>
9-
<version>2.7.2</version>
9+
<version>2.7.12</version>
1010
<packaging>pom</packaging>
1111

1212
<properties>

rtde/csv_binary_writer.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,12 @@ def writeheader(self):
108108
headerStr += self.__header_names[i]
109109

110110
headerStr += "\n"
111-
self.__file.write(struct.pack(str(len(headerStr)) + "s", headerStr if sys.version_info[0] < 3 else headerStr.encode("utf-8")))
111+
self.__file.write(
112+
struct.pack(
113+
str(len(headerStr)) + "s",
114+
headerStr if sys.version_info[0] < 3 else headerStr.encode("utf-8"),
115+
)
116+
)
112117

113118
# Header types
114119
typeStr = str("")
@@ -119,7 +124,12 @@ def writeheader(self):
119124
typeStr += self.getType(self.__types[i])
120125

121126
typeStr += "\n"
122-
self.__file.write(struct.pack(str(len(typeStr)) + "s", typeStr if sys.version_info[0] < 3 else typeStr.encode("utf-8")))
127+
self.__file.write(
128+
struct.pack(
129+
str(len(typeStr)) + "s",
130+
typeStr if sys.version_info[0] < 3 else typeStr.encode("utf-8"),
131+
)
132+
)
123133

124134
def packToBinary(self, vtype, value):
125135
print(vtype)

rtde/rtde.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(self, hostname, port=30004):
8383
self.__input_config = {}
8484
self.__skipped_package_count = 0
8585
self.__protocolVersion = RTDE_PROTOCOL_VERSION_1
86+
self.__warning_counter = {}
8687

8788
def connect(self):
8889
if self.__sock:
@@ -206,9 +207,9 @@ def send(self, input_data):
206207
return self.__sendall(Command.RTDE_DATA_PACKAGE, config.pack(input_data))
207208

208209
def receive(self, binary=False):
209-
"""Recieve the latest data package.
210-
If muliple packages has been received, older ones are discarded
211-
and only the newest one will be returned. Will block untill a package
210+
"""Receive the latest data package.
211+
If multiple packages has been received, older ones are discarded
212+
and only the newest one will be returned. Will block until a package
212213
is received or the connection is lost
213214
"""
214215
if self.__output_config is None:
@@ -218,8 +219,8 @@ def receive(self, binary=False):
218219
return self.__recv(Command.RTDE_DATA_PACKAGE, binary)
219220

220221
def receive_buffered(self, binary=False, buffer_limit=None):
221-
"""Recieve the next data package.
222-
If muliple packages has been received they are buffered and will
222+
"""Receive the next data package.
223+
If multiple packages has been received they are buffered and will
223224
be returned on subsequent calls to this function.
224225
Returns None if no data is available.
225226
"""
@@ -301,6 +302,9 @@ def has_data(self):
301302
return len(readable) != 0
302303

303304
def __recv(self, command, binary=False):
305+
306+
previous_skipped_package_count = self.__skipped_package_count
307+
304308
while self.is_connected():
305309
try:
306310
self.__recv_to_buffer(DEFAULT_TIMEOUT)
@@ -321,16 +325,44 @@ def __recv(self, command, binary=False):
321325
if len(self.__buf) >= 3 and command == Command.RTDE_DATA_PACKAGE:
322326
next_packet_header = serialize.ControlHeader.unpack(self.__buf)
323327
if next_packet_header.command == command:
324-
_log.debug("skipping package(1)")
325328
self.__skipped_package_count += 1
326329
continue
327330
if packet_header.command == command:
331+
if (
332+
self.__skipped_package_count
333+
> previous_skipped_package_count
334+
):
335+
_log.debug(
336+
"Total number of skipped packages increased to {}".format(
337+
self.__skipped_package_count
338+
)
339+
)
340+
341+
if self.__warning_counter:
342+
for warn in self.__warning_counter:
343+
_log.debug(
344+
"A total of {} packets with command {} received, before expected command.".format(
345+
self.__warning_counter[warn], warn
346+
)
347+
)
348+
self.__warning_counter.clear()
349+
328350
if binary:
329351
return packet[1:]
330352

331353
return data
332354
else:
333-
_log.debug("skipping package(2)")
355+
if not packet_header.command in self.__warning_counter:
356+
_log.debug(
357+
"Packet with command {} doesn't match the expected command {}. It will be skipped.".format(
358+
packet_header.command, command
359+
)
360+
)
361+
self.__warning_counter[packet_header.command] = 1
362+
else:
363+
self.__warning_counter[packet_header.command] = (
364+
self.__warning_counter[packet_header.command] + 1
365+
)
334366
else:
335367
break
336368
raise RTDEException(" _recv() Connection lost ")

rtde/serialize.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2323

2424
import struct
25+
import sys
2526

2627

2728
class ControlHeader(object):
@@ -167,8 +168,13 @@ class DataConfig(object):
167168
@staticmethod
168169
def unpack_recipe(buf):
169170
rmd = DataConfig()
170-
rmd.id = struct.unpack_from(">B", buf)[0]
171-
rmd.types = buf.decode("utf-8")[1:].split(",")
171+
python_version = sys.version_info
172+
if python_version.major == 2:
173+
rmd.id = struct.unpack_from(">B", buf)[0]
174+
rmd.types = buf.decode("utf-8")[1:].split(",")
175+
else:
176+
rmd.id = buf[0]
177+
rmd.types = buf[1:].decode("utf-8").split(",")
172178
rmd.fmt = ">B"
173179
for i in rmd.types:
174180
if i == "INT32":

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@
2626
setup(
2727
name="UrRtde",
2828
packages=["rtde"],
29-
version="2.7.2",
29+
version="2.7.12",
3030
description="Real-Time Data Exchange (RTDE) python client + examples",
3131
)

0 commit comments

Comments
 (0)