robotology / wearables

Data collection framework for wearable sensors
BSD 3-Clause "New" or "Revised" License
19 stars 11 forks source link

Problem in opening and publishing data on a wearable port using python bindings #190

Closed lrapetti closed 1 year ago

lrapetti commented 1 year ago

With @Zweisteine96 we tried to use the python bindings (that were added with https://github.com/robotology/wearables/pull/162) in order to open a wearable data port and publish some data.

This is the script we are using

import yarp
import wearables.bindings as wearables
import time

# create the yarp network 
network = yarp.Network()
network.init()

port = wearables.msg.BufferedPortWearableData()
port.open("/foo2")

time.sleep(1)

data = port.prepare()
data.producerName = "myWearableDevice"

time.sleep(1)

# here we create a PoseSensorData message, and try to update the value of the position x
myPoseSensorData = wearables.msg.PoseSensorData()
myPoseSensorData.position.x = 1.0
print(myPoseSensorData.position.x) #this returns the expected value

# here we want to add myPoseSensorData to the data.poseSensors dictionary
poseSensors = data.poseSensors
poseSensors.update({"firstTracker":myPoseSensorData})

# If we try to print the value from the dictionary here it returns an error (see below)
# print(data.poseSensors["firstTracker"].position.x)

while True:
  print(data)
  port.write()

  time.sleep(1)

But what happen is that:

lrapetti commented 1 year ago

Maybe @traversaro or @GiulioRomualdi that have more experience on bindings generation and usage might help?

traversaro commented 1 year ago

Indeed, this is quite counterintuitive, but I guess it is how pybind11 works, see https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html :

In this case, properties can be read and written in their entirety. However, an append operation involving such a list type has no effect:

So, we cannot append to the poseSensors attribute, but only substitute it. Accounting for this, and for the element type of the poseSensors map is the PoseSensors, not PoseSensorsData (see https://github.com/robotology/wearables/blob/v1.7.1/msgs/thrift/WearableData.thrift#L183), a working variant of your script is:

import yarp
import wearables.bindings as wearables
import time

# create the yarp network 
network = yarp.Network()
network.init()

port = wearables.msg.BufferedPortWearableData()
port.open("/foo2")

time.sleep(1)

data = port.prepare()
data.producerName = "myWearableDevice"

time.sleep(1)

# here we create a PoseSensorData message, and try to update the value of the position x
myPoseSensorData = wearables.msg.PoseSensorData()
myPoseSensorData.position.x = 1.0
print(myPoseSensorData.position.x) #this returns the expected value
myPoseSensor = wearables.msg.PoseSensor()
myPoseSensor.data = myPoseSensorData

# here we want to add myPoseSensor to the data.poseSensors dictionary
originalPoseSensors = data.poseSensors
originalPoseSensors.update({"firstTracker": myPoseSensor})
data.poseSensors = originalPoseSensors

print(data)

# If we try to print the value from the dictionary here it returns an error (see below)
print(data.poseSensors["firstTracker"].data.position.x)

while True:
  print(data)
  port.write()

  time.sleep(1)

To make the code more user-friendly I do not know if it is helpful to use PYBIND11_MAKE_OPAQUE, as I never tried it.

Tested with:

(wearables190) traversaro@IITICUBLAP257:~/wearables190$ mamba list
List of packages in environment: "/home/traversaro/mambaforge/envs/wearables190"

  Name                       Version       Build                Channel
─────────────────────────────────────────────────────────────────────────────
  _libgcc_mutex              0.1           conda_forge          conda-forge
  _openmp_mutex              4.5           2_gnu                conda-forge
  ace                        7.1.0         hcb278e6_0           conda-forge
  alsa-lib                   1.2.8         h166bdaf_0           conda-forge
  ampl-mp                    3.1.0         h2cc385e_1006        conda-forge
  aom                        3.5.0         h27087fc_0           conda-forge
  assimp                     5.2.5         hf40c2ba_0           conda-forge
  attr                       2.5.1         h166bdaf_1           conda-forge
  boost-cpp                  1.78.0        h6582d0a_3           conda-forge
  bzip2                      1.0.8         h7f98852_4           conda-forge
  c-ares                     1.19.1        hd590300_0           conda-forge
  ca-certificates            2023.5.7      hbcca054_0           conda-forge
  cairo                      1.16.0        hbbf8b49_1016        conda-forge
  dav1d                      1.2.1         hd590300_0           conda-forge
  dbus                       1.13.6        h5008d03_3           conda-forge
  eigen                      3.4.0         h4bd325d_0           conda-forge
  expat                      2.5.0         hcb278e6_1           conda-forge
  ffmpeg                     6.0.0         gpl_hdbbbd96_103     conda-forge
  font-ttf-dejavu-sans-mono  2.37          hab24e00_0           conda-forge
  font-ttf-inconsolata       3.000         h77eed37_0           conda-forge
  font-ttf-source-code-pro   2.038         h77eed37_0           conda-forge
  font-ttf-ubuntu            0.83          hab24e00_0           conda-forge
  fontconfig                 2.14.2        h14ed4e7_0           conda-forge
  fonts-conda-ecosystem      1             0                    conda-forge
  fonts-conda-forge          1             0                    conda-forge
  freeglut                   3.2.2         hac7e632_2           conda-forge
  freetype                   2.12.1        hca18f0e_1           conda-forge
  fribidi                    1.0.10        h36c2ea0_0           conda-forge
  gettext                    0.21.1        h27087fc_0           conda-forge
  glfw                       3.3.8         hd590300_1           conda-forge
  glib                       2.76.3        hfc55251_0           conda-forge
  glib-tools                 2.76.3        hfc55251_0           conda-forge
  gmp                        6.2.1         h58526e2_0           conda-forge
  gnutls                     3.7.8         hf3e180e_0           conda-forge
  graphite2                  1.3.13        h58526e2_1001        conda-forge
  gst-plugins-base           1.22.3        h938bd60_1           conda-forge
  gstreamer                  1.22.3        h977cf35_1           conda-forge
  harfbuzz                   7.3.0         hdb3a94d_0           conda-forge
  hdf5                       1.14.1        nompi_h4f84152_100   conda-forge
  icu                        72.1          hcb278e6_0           conda-forge
  idyntree                   9.1.0         py310hcc9ab6b_1      conda-forge
  ipopt                      3.14.12       hf9e1ecf_0           conda-forge
  irrlicht                   1.8.5         h3749e40_3           conda-forge
  jasper                     4.0.0         h32699f2_1           conda-forge
  keyutils                   1.6.1         h166bdaf_0           conda-forge
  krb5                       1.20.1        h81ceb04_0           conda-forge
  lame                       3.100         h166bdaf_1003        conda-forge
  ld_impl_linux-64           2.40          h41732ed_0           conda-forge
  lerc                       4.0.0         h27087fc_0           conda-forge
  libabseil                  20230125.2    cxx17_h59595ed_2     conda-forge
  libaec                     1.0.6         hcb278e6_1           conda-forge
  libass                     0.17.1        hc9aadba_0           conda-forge
  libblas                    3.9.0         17_linux64_openblas  conda-forge
  libcap                     2.67          he9d0100_0           conda-forge
  libcblas                   3.9.0         17_linux64_openblas  conda-forge
  libclang                   15.0.7        default_h7634d5b_2   conda-forge
  libclang13                 15.0.7        default_h9986a30_2   conda-forge
  libcups                    2.3.3         h36d4200_3           conda-forge
  libcurl                    8.1.2         h409715c_0           conda-forge
  libdeflate                 1.18          h0b41bf4_0           conda-forge
  libdrm                     2.4.114       h166bdaf_0           conda-forge
  libedit                    3.1.20191231  he28a2e2_2           conda-forge
  libev                      4.33          h516909a_1           conda-forge
  libevent                   2.1.12        hf998b51_1           conda-forge
  libexpat                   2.5.0         hcb278e6_1           conda-forge
  libffi                     3.4.2         h7f98852_5           conda-forge
  libflac                    1.4.3         h59595ed_0           conda-forge
  libgcc-ng                  13.1.0        he5830b7_0           conda-forge
  libgcrypt                  1.10.1        h166bdaf_0           conda-forge
  libgfortran-ng             13.1.0        h69a702a_0           conda-forge
  libgfortran5               13.1.0        h15d22d2_0           conda-forge
  libglib                    2.76.3        hebfc3b9_0           conda-forge
  libglu                     9.0.0         hac7e632_1002        conda-forge
  libgomp                    13.1.0        he5830b7_0           conda-forge
  libgpg-error               1.47          h71f35ed_0           conda-forge
  libi2c                     4.3           hcb278e6_2           conda-forge
  libiconv                   1.17          h166bdaf_0           conda-forge
  libidn2                    2.3.4         h166bdaf_0           conda-forge
  libjpeg-turbo              2.1.5.1       h0b41bf4_0           conda-forge
  liblapack                  3.9.0         17_linux64_openblas  conda-forge
  liblapacke                 3.9.0         17_linux64_openblas  conda-forge
  libllvm15                  15.0.7        h5cf9203_2           conda-forge
  libmatio                   1.5.23        hde58830_3           conda-forge
  libmatio-cpp               0.2.2         h002c22a_0           conda-forge
  libnghttp2                 1.52.0        h61bc06f_0           conda-forge
  libnsl                     2.0.0         h7f98852_0           conda-forge
  libogg                     1.3.4         h7f98852_1           conda-forge
  libopenblas                0.3.23        pthreads_h80387f5_0  conda-forge
  libopencv                  4.7.0         py38h16dcf2c_5       conda-forge
  libopus                    1.3.1         h7f98852_1           conda-forge
  libosqp                    0.6.3         h59595ed_0           conda-forge
  libpciaccess               0.17          h166bdaf_0           conda-forge
  libpng                     1.6.39        h753d276_0           conda-forge
  libpq                      15.3          hbcd7760_1           conda-forge
  libprotobuf                4.23.2        hd1fb520_5           conda-forge
  libqdldl                   0.1.5         h27087fc_1           conda-forge
  librobometry               1.2.1         hc5a7426_1           conda-forge
  libsndfile                 1.2.0         hb75c966_0           conda-forge
  libsqlite                  3.42.0        h2797004_0           conda-forge
  libssh2                    1.11.0        h0841786_0           conda-forge
  libstdcxx-ng               13.1.0        hfd8a6a1_0           conda-forge
  libsystemd0                253           h8c4010b_1           conda-forge
  libtasn1                   4.19.0        h166bdaf_0           conda-forge
  libtiff                    4.5.1         h8b53f26_0           conda-forge
  libunistring               0.9.10        h7f98852_0           conda-forge
  libuuid                    2.38.1        h0b41bf4_0           conda-forge
  libva                      2.18.0        h0b41bf4_0           conda-forge
  libvorbis                  1.3.7         h9c3ff4c_0           conda-forge
  libvpx                     1.13.0        hcb278e6_0           conda-forge
  libwebp-base               1.3.0         h0b41bf4_0           conda-forge
  libxcb                     1.15          h0b41bf4_0           conda-forge
  libxkbcommon               1.5.0         h5d7e998_3           conda-forge
  libxml2                    2.11.4        h0d562d8_0           conda-forge
  libzlib                    1.2.13        hd590300_5           conda-forge
  lz4-c                      1.9.4         hcb278e6_0           conda-forge
  metis                      5.1.0         h58526e2_1006        conda-forge
  mpg123                     1.31.3        hcb278e6_0           conda-forge
  mumps-include              5.2.1         ha770c72_11          conda-forge
  mumps-seq                  5.2.1         h2104b81_11          conda-forge
  mysql-common               8.0.33        hf1915f5_0           conda-forge
  mysql-libs                 8.0.33        hca2cd23_0           conda-forge
  ncurses                    6.4           hcb278e6_0           conda-forge
  nettle                     3.8.1         hc379101_1           conda-forge
  nspr                       4.35          h27087fc_0           conda-forge
  nss                        3.89          he45b914_0           conda-forge
  numpy                      1.25.0        py310ha4c1d20_0      conda-forge
  openh264                   2.3.1         hcb278e6_2           conda-forge
  openssl                    3.1.1         hd590300_1           conda-forge
  osqp-eigen                 0.8.0         hdd734ac_1           conda-forge
  p11-kit                    0.24.1        hc5aa10d_0           conda-forge
  pcre2                      10.40         hc3806b6_0           conda-forge
  pip                        23.1.2        pyhd8ed1ab_0         conda-forge
  pixman                     0.40.0        h36c2ea0_0           conda-forge
  portaudio                  19.6.0        h583fa2b_7           conda-forge
  pthread-stubs              0.4           h36c2ea0_1001        conda-forge
  pulseaudio-client          16.1          hb77b528_4           conda-forge
  pybind11-abi               4             hd8ed1ab_3           conda-forge
  python                     3.10.12       hd12c33a_0_cpython   conda-forge
  python_abi                 3.10          3_cp310              conda-forge
  qt-main                    5.15.8        h01ceb2d_13          conda-forge
  readline                   8.2           h8228510_1           conda-forge
  robot-testing-framework    2.0.1         hcb278e6_1           conda-forge
  scotch                     6.0.9         hb2e6521_2           conda-forge
  sdl                        1.2.64        h293081c_0           conda-forge
  sdl2                       2.26.5        h949db6a_0           conda-forge
  setuptools                 68.0.0        pyhd8ed1ab_0         conda-forge
  soxr                       0.1.3         h0b41bf4_3           conda-forge
  svt-av1                    1.6.0         h59595ed_0           conda-forge
  tinyxml                    2.6.2         h4bd325d_2           conda-forge
  tk                         8.6.12        h27826a3_0           conda-forge
  tzdata                     2023c         h71feb2d_0           conda-forge
  unixodbc                   2.3.10        h583eb01_0           conda-forge
  visit_struct               1.0.0.1       hcb278e6_2           conda-forge
  wearables                  1.7.1         py310h64a2142_88     robotology
  wheel                      0.40.0        pyhd8ed1ab_0         conda-forge
  x264                       1!164.3095    h166bdaf_2           conda-forge
  x265                       3.5           h924138e_3           conda-forge
  xcb-util                   0.4.0         hd590300_1           conda-forge
  xcb-util-image             0.4.0         h8ee46fc_1           conda-forge
  xcb-util-keysyms           0.4.0         h8ee46fc_1           conda-forge
  xcb-util-renderutil        0.3.9         hd590300_1           conda-forge
  xcb-util-wm                0.4.1         h8ee46fc_1           conda-forge
  xkeyboard-config           2.39          hd590300_0           conda-forge
  xorg-fixesproto            5.0           h7f98852_1002        conda-forge
  xorg-inputproto            2.3.2         h7f98852_1002        conda-forge
  xorg-kbproto               1.0.7         h7f98852_1002        conda-forge
  xorg-libice                1.1.1         hd590300_0           conda-forge
  xorg-libsm                 1.2.4         h7391055_0           conda-forge
  xorg-libx11                1.8.6         h8ee46fc_0           conda-forge
  xorg-libxau                1.0.11        hd590300_0           conda-forge
  xorg-libxcursor            1.2.0         h0b41bf4_1           conda-forge
  xorg-libxdmcp              1.1.3         h7f98852_0           conda-forge
  xorg-libxext               1.3.4         h0b41bf4_2           conda-forge
  xorg-libxfixes             5.0.3         h7f98852_1004        conda-forge
  xorg-libxi                 1.7.10        h7f98852_0           conda-forge
  xorg-libxinerama           1.1.5         h27087fc_0           conda-forge
  xorg-libxrandr             1.5.2         h7f98852_1           conda-forge
  xorg-libxrender            0.9.10        h7f98852_1003        conda-forge
  xorg-randrproto            1.5.0         h7f98852_1001        conda-forge
  xorg-renderproto           0.11.1        h7f98852_1002        conda-forge
  xorg-xextproto             7.3.0         h0b41bf4_1003        conda-forge
  xorg-xf86vidmodeproto      2.3.1         h7f98852_1002        conda-forge
  xorg-xproto                7.0.31        h7f98852_1007        conda-forge
  xz                         5.2.6         h166bdaf_0           conda-forge
  yarp                       3.8.1         ha770c72_0           conda-forge
  yarp-cxx                   3.8.1         h245b40a_0           conda-forge
  yarp-python                3.8.1         py310h6c2f4e2_0      conda-forge
  ycm-cmake-modules          0.15.3        h59595ed_0           conda-forge
  zlib                       1.2.13        hd590300_5           conda-forge
  zstd                       1.5.2         h3eb15da_6           conda-forge
lrapetti commented 1 year ago

Thanks a lot @traversaro! The example you provided is working for me and I see the following print of data:

myWearableDevice () () () () () () () () ((firstTracker ("" 0 0.0 0.0 0.0 0.0 1.0 0.0 0.0))) () () () () () () ()

Still I am not able to read the port from yarp

$ yarp read ... /foo2
\[INFO] |yarp.os.Port|/tmp/port/1| Port /tmp/port/1 active at tcp://10.0.2.116:10003/
[INFO] |yarp.os.impl.PortCoreInputUnit|/tmp/port/1| Receiving input from /foo2 to /tmp/port/1 using tcp

this was happening also with my previous script, it was not publishing even the empty message.

traversaro commented 1 year ago

Working version:

import yarp
import wearables.bindings as wearables
import time

# create the yarp network 
network = yarp.Network()
network.init()

port = wearables.msg.BufferedPortWearableData()
port.open("/foo2")

time.sleep(1)

data = port.prepare()
data.producerName = "myWearableDevice"

time.sleep(1)

# here we create a PoseSensorData message, and try to update the value of the position x
myPoseSensorData = wearables.msg.PoseSensorData()
myPoseSensorData.position.x = 1.0
print(myPoseSensorData.position.x) #this returns the expected value
myPoseSensor = wearables.msg.PoseSensor()
myPoseSensor.data = myPoseSensorData

# here we want to add myPoseSensor to the data.poseSensors dictionary
originalPoseSensors = data.poseSensors
originalPoseSensors.update({"firstTracker": myPoseSensor})
data.poseSensors = originalPoseSensors

print(data)

# If we try to print the value from the dictionary here it returns an error (see below)
print(data.poseSensors["firstTracker"].data.position.x)

dataToSend = data

while True:
  newData = port.prepare()
  newData = dataToSend
  print(dataToSend)
  print(newData)
  port.write()

  time.sleep(1)

Output:

(wearables190) traversaro@IITICUBLAP257:~/wearables190$ yarp read ... /foo2
[INFO] |yarp.os.Port|/tmp/port/1| Port /tmp/port/1 active at tcp://172.23.21.248:10003/
[INFO] |yarp.os.impl.PortCoreInputUnit|/tmp/port/1| Receiving input from /foo2 to /tmp/port/1 using tcp
myWearableDevice () () () () () () () () ((firstTracker ("" 0 0.0 0.0 0.0 0.0 1.0 0.0 0.0))) () () () () () () ()
myWearableDevice () () () () () () () () ((firstTracker ("" 0 0.0 0.0 0.0 0.0 1.0 0.0 0.0))) () () () () () () ()
myWearableDevice () () () () () () () () ((firstTracker ("" 0 0.0 0.0 0.0 0.0 1.0 0.0 0.0))) () () () () () () ()
myWearableDevice () () () () () () () () ((firstTracker ("" 0 0.0 0.0 0.0 0.0 1.0 0.0 0.0))) () () () () () () ()
^CInterrupting...
[INFO] |yarp.os.impl.PortCoreInputUnit|/tmp/port/1| Removing input from /foo2 to /tmp/port/1
lrapetti commented 1 year ago

Thanks @traversaro, I am now able to read data from the port, what was missingwas to capp port.prepare() in the loop.

Here, for reference, is the final test script I was using for testing:

import yarp
import wearables.bindings as wearables
import time

# create the yarp network 
network = yarp.Network()
network.init()

# create a buffered wearable data port
port = wearables.msg.BufferedPortWearableData()
port.open("/foo")

time.sleep(0.2)

# prepare data
dataToSend = port.prepare()
dataToSend.producerName = "myWearableDevice"

time.sleep(0.2)

# prepare a pose sensor data
myPoseSensor = wearables.msg.PoseSensor()
myPoseSensor.data = wearables.msg.PoseSensorData()
myPoseSensor.info.name = "myWearableDevice::Pose::FirstTracker"
myPoseSensor.info.status = wearables.msg.OK

# add the pose sensor data to the data.poseSensors dictionary
originalPoseSensors = dataToSend.poseSensors
dataToSend.poseSensors.update({"FristTracker": myPoseSensor})
dataToSend.poseSensors = originalPoseSensors

count = 0

while True:
  # update data 
  count = count + 1
  dataToSend.poseSensors["FristTracker"].data.position.x = count

  data = port.prepare()
  data = dataToSend

  print(data)

  port.write()

  time.sleep(0.05)

cc @Zweisteine96 I think this will be useful for your use case.