diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..c53b622
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,37 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Console logs / stack traces**
+Please wrap in [triple backticks (```)](https://help.github.com/en/articles/creating-and-highlighting-code-blocks) to make it easier to read.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots or videos to help explain your problem.
+
+**Environment (please complete the following information, where applicable):**
+- Unity Version: [e.g. Unity 2020.2.0f1]
+- Unity machine OS + version: [e.g. Windows 10]
+- ROS machine OS + version: [e.g. Ubuntu 18.04, ROS Noetic]
+- ROS–Unity communication: [e.g. Docker]
+- Branch or version: [e.g. v0.2.0]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..bbcbbe7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..6c88fde
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,34 @@
+## Proposed change(s)
+
+Describe the changes made in this PR.
+
+### Useful links (GitHub issues, JIRA tickets, forum threads, etc.)
+
+Provide any relevant links here.
+
+### Types of change(s)
+
+- [ ] Bug fix
+- [ ] New feature
+- [ ] Code refactor
+- [ ] Documentation update
+- [ ] Other (please describe)
+
+## Testing and Verification
+
+Please describe the tests that you ran to verify your changes. Please also provide instructions, ROS packages, and Unity project files as appropriate so we can reproduce the test environment.
+
+### Test Configuration:
+- Unity Version: [e.g. Unity 2020.2.0f1]
+- Unity machine OS + version: [e.g. Windows 10]
+- ROS machine OS + version: [e.g. Ubuntu 18.04, ROS Noetic]
+- ROS–Unity communication: [e.g. Docker]
+
+## Checklist
+- [ ] Ensured this PR is up-to-date with the `dev` branch
+- [ ] Created this PR to target the `dev` branch
+- [ ] Followed the style guidelines as described in the [Contribution Guidelines](../CONTRIBUTING.md)
+- [ ] Added tests that prove my fix is effective or that my feature works
+- [ ] Updated the documentation as appropriate
+
+## Other comments
\ No newline at end of file
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..a7a4c57
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,74 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at [unity-robotics@unity3d.com](mailto:unity-robotics@unity3d.com). All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.4, available at
+https://www.contributor-covenant.org/version/1/4/code-of-conduct/
+
+[homepage]: https://www.contributor-covenant.org
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..0f7253f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,64 @@
+# Contribution Guidelines
+
+Thank you for your interest in contributing to Unity Robotics! To facilitate your
+contributions, we've outlined a brief set of guidelines to ensure that your extensions
+can be easily integrated.
+
+## Communication
+
+First, please read through our
+[code of conduct](CODE_OF_CONDUCT.md),
+as we expect all our contributors to follow it.
+
+Second, before starting on a project that you intend to contribute to any of our
+Unity Robotics packages or tutorials, we **strongly** recommend posting on the repository's
+[Issues page](https://github.com/Unity-Technologies/ROS-TCP-Endpoint/issues) and
+briefly outlining the changes you plan to make. This will enable us to provide
+some context that may be helpful for you. This could range from advice and
+feedback on how to optimally perform your changes or reasons for not doing it.
+
+## Git Branches
+
+The `main` branch corresponds to the most recent stable version of the project. The `dev` branch
+contains changes that are staged to be merged into `main` as the team sees fit.
+
+When contributing to the project, please make sure that your Pull Request (PR)
+does the following:
+
+- Is up-to-date with and targets the `dev` branch
+- Contains a detailed description of the changes performed
+- Has corresponding changes to documentation, unit tests and sample environments (if
+ applicable)
+- Contains a summary of the tests performed to validate your changes
+- Links to issue numbers that the PR resolves (if any)
+
+
+
+## Code style
+
+All Python code should follow the [PEP 8 style guidelines](https://pep8.org/).
+
+All C# code should follow the [Microsoft C# Coding Conventions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions).
+Additionally, the [Unity Coding package](https://docs.unity3d.com/Packages/com.unity.coding@0.1/manual/index.html)
+can be used to format, encode, and lint your code according to the standard Unity
+development conventions. Be aware that these Unity conventions will supersede the
+Microsoft C# Coding Conventions where applicable.
+
+Please note that even if the code you are changing does not adhere to these guidelines,
+we expect your submissions to follow these conventions.
+
+## Contributor License Agreements
+
+When you open a pull request, you will be asked to acknowledge our Contributor
+License Agreement. We allow both individual contributions and contributions made
+on behalf of companies. We use an open source tool called CLA assistant. If you
+have any questions on our CLA, please
+[submit an issue](https://github.com/Unity-Technologies/ROS-TCP-Endpoint/issues) or
+email us at [unity-robotics@unity3d.com](mailto:unity-robotics@unity3d.com).
+
+## Contribution review
+
+Once you have a change ready following the above ground rules, simply make a
+pull request in GitHub.
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index d9a10c0..7507bc9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -174,3 +174,17 @@
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
+
+ Copyright 2020 Unity Technologies
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
index 2e44191..6af6ac0 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,25 @@
# ROS TCP Endpoint
+[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
+
+## Introduction
+
[ROS](https://www.ros.org/) package used to create an endpoint to accept ROS messages sent from a Unity scene using the [ROS TCP Connector](https://github.com/Unity-Technologies/ROS-TCP-Connector) scripts.
-Instructions and examples on how to use this ROS package can be found on the [Unity Robotics Hub](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/master/tutorials/ros_unity_integration/README.md) repository.
\ No newline at end of file
+Instructions and examples on how to use this ROS package can be found on the [Unity Robotics Hub](https://github.com/Unity-Technologies/Unity-Robotics-Hub/blob/master/tutorials/ros_unity_integration/README.md) repository.
+
+## Community and Feedback
+
+The Unity Robotics projects are open-source and we encourage and welcome contributions.
+If you wish to contribute, be sure to review our [contribution guidelines](CONTRIBUTING.md)
+and [code of conduct](CODE_OF_CONDUCT.md).
+
+## Support
+For general questions, feedback, or feature requests, connect directly with the
+Robotics team at [unity-robotics@unity3d.com](mailto:unity-robotics@unity3d.com).
+
+For bugs or other issues, please file a GitHub issue and the Robotics team will
+investigate the issue as soon as possible.
+
+## License
+[Apache License 2.0](LICENSE)
\ No newline at end of file
diff --git a/config/params.yaml b/config/params.yaml
new file mode 100644
index 0000000..50aaa22
--- /dev/null
+++ b/config/params.yaml
@@ -0,0 +1 @@
+ROS_IP: 127.0.0.1
\ No newline at end of file
diff --git a/launch/endpoint.launch b/launch/endpoint.launch
new file mode 100644
index 0000000..f5d7788
--- /dev/null
+++ b/launch/endpoint.launch
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/package.xml b/package.xml
index d2045bc..919cad9 100644
--- a/package.xml
+++ b/package.xml
@@ -1,7 +1,7 @@
ros_tcp_endpoint
- 0.2.0
+ 0.3.0
Acts as the bridge between Unity messages sent via Websocket and ROS messages.
Unity Robotics
diff --git a/src/ros_tcp_endpoint/__init__.py b/src/ros_tcp_endpoint/__init__.py
index 356575b..adb5b02 100644
--- a/src/ros_tcp_endpoint/__init__.py
+++ b/src/ros_tcp_endpoint/__init__.py
@@ -16,4 +16,4 @@
from .subscriber import RosSubscriber
from .service import RosService
from .server import TcpServer
-
+from .unity_service import UnityService
diff --git a/src/ros_tcp_endpoint/client.py b/src/ros_tcp_endpoint/client.py
index 7d19048..c54acb0 100644
--- a/src/ros_tcp_endpoint/client.py
+++ b/src/ros_tcp_endpoint/client.py
@@ -102,7 +102,7 @@ def read_message(conn):
data += packet
- if not data:
+ if full_message_size > 0 and not data:
print("No data for a message size of {}, breaking!".format(full_message_size))
return
@@ -164,6 +164,11 @@ def run(self):
response_message = self.serialize_message(destination, response)
self.conn.send(response_message)
return
+ elif destination == '__topic_list':
+ response = self.tcp_server.topic_list(data)
+ response_message = self.serialize_message(destination, response)
+ self.conn.send(response_message)
+ return
elif destination not in self.tcp_server.source_destination_dict.keys():
error_msg = "Topic/service destination '{}' is not defined! Known topics are: {} "\
.format(destination, self.tcp_server.source_destination_dict.keys())
diff --git a/src/ros_tcp_endpoint/server.py b/src/ros_tcp_endpoint/server.py
index b1b7d2a..ca45bf0 100644
--- a/src/ros_tcp_endpoint/server.py
+++ b/src/ros_tcp_endpoint/server.py
@@ -25,13 +25,14 @@
from .subscriber import RosSubscriber
from .publisher import RosPublisher
from ros_tcp_endpoint.msg import RosUnitySysCommand
+from ros_tcp_endpoint.srv import RosUnityTopicListResponse
class TcpServer:
"""
Initializes ROS node and TCP server.
"""
- def __init__(self, node_name, buffer_size=1024, connections=10, tcp_ip="", tcp_port=-1, timeout=10):
+ def __init__(self, node_name, buffer_size=1024, connections=10, tcp_ip="", tcp_port=-1, timeout_on_connect=10, timeout_on_send=0.8, timeout_on_idle=10):
"""
Initializes ROS node and class variables.
@@ -52,7 +53,7 @@ def __init__(self, node_name, buffer_size=1024, connections=10, tcp_ip="", tcp_p
unity_machine_ip = rospy.get_param("/UNITY_IP", '')
unity_machine_port = rospy.get_param("/UNITY_SERVER_PORT", 5005)
- self.unity_tcp_sender = UnityTcpSender(unity_machine_ip, unity_machine_port, timeout)
+ self.unity_tcp_sender = UnityTcpSender(unity_machine_ip, unity_machine_port, timeout_on_connect, timeout_on_send, timeout_on_idle)
self.node_name = node_name
self.source_destination_dict = {}
@@ -96,6 +97,9 @@ def send_unity_message(self, topic, message):
def send_unity_service(self, topic, service_class, request):
return self.unity_tcp_sender.send_unity_service(topic, service_class, request)
+ def topic_list(self, data):
+ return RosUnityTopicListResponse(self.source_destination_dict.keys())
+
def handle_syscommand(self, data):
message = RosUnitySysCommand().deserialize(data)
function = getattr(self.syscommands, message.command)
diff --git a/src/ros_tcp_endpoint/tcp_sender.py b/src/ros_tcp_endpoint/tcp_sender.py
index de6ad3b..018d1e2 100644
--- a/src/ros_tcp_endpoint/tcp_sender.py
+++ b/src/ros_tcp_endpoint/tcp_sender.py
@@ -14,21 +14,36 @@
import rospy
import socket
+import time
+import threading
+import struct
from .client import ClientThread
from ros_tcp_endpoint.msg import RosUnityError
from ros_tcp_endpoint.srv import UnityHandshake, UnityHandshakeResponse
+# queue module was renamed between python 2 and 3
+try:
+ from queue import Queue
+except:
+ from Queue import Queue
class UnityTcpSender:
"""
Connects and sends messages to the server on the Unity side.
"""
- def __init__(self, unity_ip, unity_port, timeout):
+ def __init__(self, unity_ip, unity_port, timeout_on_connect, timeout_on_send, timeout_on_idle):
self.unity_ip = unity_ip
self.unity_port = unity_port
# if we have a valid IP at this point, it was overridden locally so always use that
self.ip_is_overridden = (self.unity_ip != '')
- self.timeout = timeout
+ self.timeout_on_connect = timeout_on_connect
+ self.timeout_on_send = timeout_on_send
+ self.timeout_on_idle = timeout_on_idle
+ self.queue = Queue()
+ sender_thread = threading.Thread(target=self.sender_loop)
+ # Exit the server thread when the main thread terminates
+ sender_thread.daemon = True
+ sender_thread.start()
def handshake(self, incoming_ip, data):
message = UnityHandshake._request_class().deserialize(data)
@@ -53,16 +68,7 @@ def send_unity_message(self, topic, message):
return
serialized_message = ClientThread.serialize_message(topic, message)
-
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.settimeout(self.timeout)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- s.connect((self.unity_ip, self.unity_port))
- s.sendall(serialized_message)
- s.close()
- except Exception as e:
- rospy.loginfo("Exception {}".format(e))
+ self.queue.put(serialized_message)
def send_unity_service(self, topic, service_class, request):
if self.unity_ip == '':
@@ -70,12 +76,13 @@ def send_unity_service(self, topic, service_class, request):
return
serialized_message = ClientThread.serialize_message(topic, request)
-
+
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.settimeout(self.timeout)
+ s.settimeout(self.timeout_on_connect)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.connect((self.unity_ip, self.unity_port))
+ s.settimeout(self.timeout_on_send)
s.sendall(serialized_message)
destination, data = ClientThread.read_message(s)
@@ -86,4 +93,34 @@ def send_unity_service(self, topic, service_class, request):
return response
except Exception as e:
rospy.loginfo("Exception {}".format(e))
-
\ No newline at end of file
+
+ def sender_loop(self):
+ s = None
+ idletimeout = 0
+
+ while True:
+ item = self.queue.get()
+
+ retries = 0
+ while retries < 3:
+ retries+=1
+
+ try:
+ if time.time() > idletimeout:
+ if s != None:
+ s.close()
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.settimeout(self.timeout_on_connect)
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ s.connect((self.unity_ip, self.unity_port))
+ s.settimeout(self.timeout_on_send)
+
+ s.sendall(item)
+ idletimeout = time.time() + self.timeout_on_idle
+ break # sent ok. break the retries loop
+ except socket.timeout:
+ idletimeout = 0 # assume the connection has been closed, force a reconnect
+ except Exception as e:
+ rospy.loginfo("Exception {}".format(e))
+ idletimeout = 0
diff --git a/srv/RosUnityTopicList.srv b/srv/RosUnityTopicList.srv
new file mode 100644
index 0000000..895f4a6
--- /dev/null
+++ b/srv/RosUnityTopicList.srv
@@ -0,0 +1,2 @@
+---
+string[] topics
\ No newline at end of file