Skip to content

Commit

Permalink
Merge pull request #1 from jhu-saw/rc-1.2.0
Browse files Browse the repository at this point in the history
1.2.0
  • Loading branch information
adeguet1 authored Jan 2, 2024
2 parents 266a42c + 1380fc3 commit 0ac8a87
Show file tree
Hide file tree
Showing 10 changed files with 639 additions and 138 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
Change log
==========


1.2.0 (2024-01-02)
==================

* API changes:
* In JSON configuration file, `data` has been replaced by `read-commands`
* Deprecated features:
* `.rosintall` has been removed, migrated to `vcs`
* New features:
* Added support for void and write events
* Added void and write commands
* Added snippet of code for C#/Unity
* Bug fixes:
* Fixed CMake to use new cisst CMake macros, compiles with catkin and colcon

1.1.0 (2021-04-08)
==================

Expand Down
17 changes: 14 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#
# (C) Copyright 2019 Johns Hopkins University (JHU), All Rights
# Reserved.
# (C) Copyright 2019-2024 Johns Hopkins University (JHU), All Rights Reserved.
#
# --- begin cisst license - do not edit ---
#
Expand All @@ -10,6 +9,18 @@
#
# --- end cisst license ---

cmake_minimum_required (VERSION 2.8)
cmake_minimum_required(VERSION 3.10)
project (sawSocketStreamerAll VERSION 1.2.0)

find_package (cisst REQUIRED)
include (${CISST_USE_FILE})
cisst_cpack_settings (
VENDOR "JHU"
MAINTAINER "[email protected]")

add_subdirectory (components)

include (CPack)
cpack_add_component (sawSocketStreamer)
cpack_add_component (sawSocketStreamer-dev
DEPENDS sawSocketStreamer)
106 changes: 76 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

This SAW component allows to stream data from most cisst/SAW components with little or no new code. It compiles on Windows, Linux and likely MacOS. It has been tested with:
* Linux
* Streaming prmStateJoint data from sawIntuitiveResearchKit and sawIntuitiveDaVinci
* Streaming `prmStateJoint` data from sawIntuitiveResearchKit and sawIntuitiveDaVinci

It current supports UDP sockets and the data is serialized using JSON
It currently supports UDP sockets and the data is serialized using the JSON
format. It is used to stream data from the different da Vinci robots
(at JHU) to HoloLens displays. On the HoloLens side, one can use the
open source package [dvrk-xr](https://github.com/jhu-dvrk/dvrk-xr).
open source package [dvrk-xr](https://github.com/jhu-dvrk/dvrk-xr). It can be used to receive and send data to any other SAW component (see https://github.com/jhu-cisst/cisst/wiki/cisst-libraries-and-SAW-components)

Based on user requests, we could add:
* TCP support
Expand All @@ -24,43 +24,34 @@ Based on user requests, we could add:

## Adding the component

One can create and add the `mtsSocketStreamer` component manually in
your `main` C function but we strongly recommend using the
You can create and add the `mtsSocketStreamer` component manually in
your `main` C/C++ code but we strongly recommend using the
`cisstMultiTask` manager ability to load a configuration file to add
and connect components. The dVRK main programs provide this options. See https://github.com/jhu-dvrk/sawIntuitiveResearchKit/blob/master/applications/mainQtConsoleJSON.cpp.
and connect components. Most cisst/SAW (including dVRK) programs have
already been updated with the code below so you likely don't need to
add this and can skip to the next section. See
https://github.com/jhu-dvrk/sawIntuitiveResearchKit/blob/master/applications/mainQtConsoleJSON.cpp.

There is first a command line option to specify one or more configuration files for the component manager:
```cpp
cmnCommandLineOptions options;
typedef std::list<std::string> managerConfigType;
managerConfigType managerConfig;

std::list<std::string> managerConfig;
options.AddOptionMultipleValues("m", "component-manager",
"JSON files to configure component manager",
cmnCommandLineOptions::OPTIONAL_OPTION, &managerConfig);
```

Then one has to use the configuration files to configure the component manager:
```cpp
const managerConfigType::iterator endConfig = managerConfig.end();
for (managerConfigType::iterator iterConfig = managerConfig.begin();
iterConfig != endConfig;
++iterConfig) {
if (!iterConfig->empty()) {
if (!cmnPath::Exists(*iterConfig)) {
CMN_LOG_INIT_ERROR << "File " << *iterConfig
<< " not found!" << std::endl;
} else {
if (!componentManager->ConfigureJSON(*iterConfig)) {
CMN_LOG_INIT_ERROR << "Configure: failed to configure component-manager for "
<< *iterConfig << std::endl;
return -1;
}
}
}
mtsManagerLocal * componentManager = mtsManagerLocal::GetInstance();
if (!componentManager->ConfigureJSON(managerConfig)) {
CMN_LOG_INIT_ERROR << "Configure: failed to configure component manager, check cisstLog for error messages" << std::endl;
return -1;
}
```
## Configuration file for the component manager
The configuration files for the component manager will look like (more examples can be found at https://github.com/jhu-dvrk/sawIntuitiveResearchKit/tree/master/share/socket-streamer):
```json
/* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
Expand Down Expand Up @@ -118,27 +109,82 @@ The configuration files for the component manager will look like (more examples
```

## Component configuration file
## Socket streamer configuration file

Each component created need a configuration file that specifies with read command to use to retrieve the data as well as the data type. For example:
Each component created need a configuration file that specifies which read command to use to retrieve the data as well as the data type. For example:
```json
/* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
{
"ip": "10.194.86.119",
"port": "48054",
"data": [
"read-commands": [
{
"name": "measured_js",
"type": "prmStateJoint"
}
]
,
"void-commands": ["hold", "free"]
,
"write-commands": [
{
"name": "servo_jp",
"type": "prmPositionJointSet"
}
]
,
"write-events": ["operating_state"]
}
```


## Testing the streamer

To test the streamer, you can use the `nc` tool on Linux. The main options are `l` to listen and `u` for UDP protocol. Then you need to add the IP address and port. With the example above, try:
To test the read commands and events, you can use the `nc` tool on
Linux. The main options are `l` to listen and `u` for UDP protocol.
Then you need to add the IP address and port. With the example above,
try:
```sh
nc -lu 10.194.86.119 48054
```
At that point you should see a continous stream for text in JSON format.
At that point you should see a continous stream of text in JSON format.

To test the void and write commands, you need to create your own code
and send the command name and payload in JSON format. For void
commands, send an empty string (`""`). You can find an example in
Python in the sawIntuitiveResearchKit repository under
`share/socket-streamer`:
https://github.com/jhu-dvrk/sawIntuitiveResearchKit/blob/devel/share/socket-streamer/example.py

## Using the socket streamer with Unity

This is based on code that can be found in the `share` directory.
This code was originally written by An Chi Chen and Muhammad Hadi when
they were students at Johns Hopkins. Their goal was to visualize and
control a dVRK PSM from Unity.

The main parts are setting up the socket in the ``start()``:
```csharp
// udp using socket
data = new byte[1024];
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 48051); // ensure that this port is the same as the one youre sending data from
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(ip);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
remote = (EndPoint)(sender);
```

And then you can read from the socket using:
```csharp
// read in message from dVRK
data = new byte[1024];
socket.ReceiveFrom(data, ref remote);
dVRK_msg = Encoding.UTF8.GetString(data); // dVRK_msg will then contain the data
```

Finally an example of how you would send data:
```csharp
// send json strings to dVRK
send_msg = Encoding.UTF8.GetBytes(pose_message); // pose_message is string to send
socket.SendTo(send_msg, remote);
```
4 changes: 4 additions & 0 deletions colcon.pkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "sawSocketStreamerAll",
"dependencies": ["cisst"]
}
69 changes: 44 additions & 25 deletions components/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# (C) Copyright 2019 Johns Hopkins University (JHU), All Rights Reserved.
# (C) Copyright 2019-2024 Johns Hopkins University (JHU), All Rights Reserved.
#
# --- begin cisst license - do not edit ---
#
Expand All @@ -9,42 +9,61 @@
#
# --- end cisst license ---

project (sawSocketStreamer)
cmake_minimum_required (VERSION 3.10)
project (sawSocketStreamer VERSION 1.2.0)

cmake_minimum_required(VERSION 2.8)
# create a list of required cisst libraries
set (REQUIRED_CISST_LIBRARIES cisstCommon
cisstVector
cisstOSAbstraction
cisstMultiTask
cisstParameterTypes)

set (REQUIRED_CISST_LIBRARIES
cisstCommon
cisstVector
cisstOSAbstraction
cisstMultiTask
cisstParameterTypes)
find_package (cisst 1.2.1 REQUIRED ${REQUIRED_CISST_LIBRARIES})

find_package (cisst REQUIRED ${REQUIRED_CISST_LIBRARIES})
if (cisst_FOUND_AS_REQUIRED)

if (cisst_FOUND)
# load cisst configuration
include (${CISST_USE_FILE})

# catkin/ROS paths
cisst_is_catkin_build (sawSocketStreamer_IS_CATKIN_BUILT)
if (sawSocketStreamer_IS_CATKIN_BUILT)
set (LIBRARY_OUTPUT_PATH "${CATKIN_DEVEL_PREFIX}/lib")
endif ()

include_directories (${CMAKE_BINARY_DIR})
cisst_set_output_path ()

# create/configure file for find_package (sawSocketStreamer)
set (sawSocketStreamer_INCLUDE_DIR
"${sawSocketStreamer_SOURCE_DIR}/include")
"${sawSocketStreamer_SOURCE_DIR}/include"
"${sawSocketStreamer_BINARY_DIR}/include")
set (sawSocketStreamer_HEADER_DIR "${sawSocketStreamer_SOURCE_DIR}/include/sawSocketStreamer")
set (sawSocketStreamer_LIBRARY_DIR "${LIBRARY_OUTPUT_PATH}")
set (sawSocketStreamer_LIBRARIES sawSocketStreamer)

# Allow c++ code to find local header files
include_directories (${sawSocketStreamer_INCLUDE_DIR} ${sawSocketStreamer_BINARY_DIR})

include_directories (${sawSocketStreamer_INCLUDE_DIR})
# add all config files for this component
cisst_add_config_files (sawSocketStreamer)

add_library (sawSocketStreamer
"include/sawSocketStreamer/sawSocketStreamerExport.h"
"include/sawSocketStreamer/mtsSocketStreamer.h"
"code/mtsSocketStreamer.cpp")
${sawSocketStreamer_HEADER_DIR}/sawSocketStreamerExport.h
code/mtsSocketStreamer.cpp
${sawSocketStreamer_HEADER_DIR}/mtsSocketStreamer.h)
set_target_properties (sawSocketStreamer PROPERTIES
VERSION ${sawSocketStreamer_VERSION}
FOLDER "sawSocketStreamer")
cisst_target_link_libraries (sawSocketStreamer ${REQUIRED_CISST_LIBRARIES})

# Install target for headers and library
install (DIRECTORY
"${sawSocketStreamer_SOURCE_DIR}/include/sawSocketStreamer"
"${sawSocketStreamer_BINARY_DIR}/include/sawSocketStreamer"
DESTINATION include
COMPONENT sawSocketStreamer-dev)

cisst_target_link_libraries (sawSocketStreamer
${REQUIRED_CISST_LIBRARIES})
install (TARGETS sawSocketStreamer COMPONENT sawSocketStreamer
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)

endif (cisst_FOUND)
else (cisst_FOUND_AS_REQUIRED)
message ("Information: code in ${CMAKE_CURRENT_SOURCE_DIR} will not be compiled, it requires ${REQUIRED_CISST_LIBRARIES}")
endif (cisst_FOUND_AS_REQUIRED)
Loading

0 comments on commit 0ac8a87

Please sign in to comment.