-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enable kxreus for using model server
- Loading branch information
Showing
8 changed files
with
329 additions
and
20 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
(require :robot-interface "package://pr2eus/robot-interface.l") | ||
|
||
(ros::load-ros-manifest "control_msgs") | ||
(ros::load-ros-manifest "kxr_controller") | ||
|
||
|
||
(defun load-robot-model (&key (port 8000) | ||
(namespace nil)) | ||
(let* ((port "8000") | ||
(hash (if namespace (format nil "~A~A" namespace (ros::get-param "/eusmodel_hash")) | ||
(ros::get-param "/eusmodel_hash"))) | ||
(robot-name (if namespace (format nil "~A~A" namespace (ros::get-param "/eus_robot_name")) | ||
(ros::get-param "/eus_robot_name"))) | ||
(outpath (ros::resolve-ros-path (format nil "package://kxreus/models/cache/~A.l" hash))) | ||
(server-url (format nil "http://~A:~A/~A.l" | ||
(ros::get-host) | ||
port | ||
hash))) | ||
(when (not (probe-file outpath)) | ||
(while (not (= (unix:system (format nil "wget -O ~A ~A" | ||
outpath | ||
server-url | ||
)) | ||
0)) | ||
(ros::ros-info (format nil "Waiting model file from server url ~A" server-url)) | ||
(unix::usleep (* 1000 1000)))) | ||
(load outpath) | ||
(funcall (read-from-string robot-name)))) | ||
|
||
|
||
(defclass kxr-interface | ||
:super robot-interface | ||
:slots (joint-names servo-on-off-client)) | ||
|
||
|
||
(defmethod kxr-interface | ||
(:init (robot &rest args &key (type :default-controller) &allow-other-keys) | ||
(let* ((namespace (cadr (memq :namespace args))) | ||
(joint-param (if namespace (format nil "~A/~A" namespace "/kxr_fullbody_controller/joints") | ||
"/kxr_fullbody_controller/joints"))) | ||
(setq joint-names (ros::get-param joint-param nil)) | ||
(while (and (ros::ok) (null joint-names)) | ||
(ros::ros-info (format nil "Waiting ~A rosparam set" joint-param)) | ||
(setq joint-names (ros::get-param joint-param nil)) | ||
(ros::sleep))) | ||
|
||
(send-super* :init :robot robot :type type | ||
:groupname "kxr_interface" | ||
args) | ||
|
||
(setq servo-on-off-client (instance ros::simple-action-client :init | ||
(if namespace (format nil "~A/~A" namespace "/kxr_fullbody_controller/servo_on_off") "/kxr_fullbody_controller/servo_on_off") | ||
kxr_controller::ServoOnOffAction | ||
:groupname groupname)) | ||
(dolist (action (list servo-on-off-client)) | ||
(unless (and joint-action-enable (send action :wait-for-server 3)) | ||
(setq joint-action-enable nil) | ||
(ros::ros-warn "~A is not respond, kxr-interface is disabled" action) | ||
(return))) | ||
t) | ||
(:default-controller | ||
() | ||
(send self :fullbody-controller)) | ||
(:fullbody-controller | ||
() | ||
(list | ||
(list | ||
(cons :controller-action "kxr_fullbody_controller/follow_joint_trajectory") | ||
(cons :controller-state "kxr_fullbody_controller/state") | ||
(cons :action-type control_msgs::FollowJointTrajectoryAction) | ||
(cons :joint-names joint-names)))) | ||
(:servo-on | ||
(&key (names nil)) | ||
(unless joint-action-enable | ||
(if viewer (send self :draw-objects)) | ||
(return-from :servo-on t)) | ||
(when (null names) | ||
(setq names joint-names)) | ||
(let* (goal result) | ||
;; send current angle-vector | ||
(send self :angle-vector (send self :state :potentio-vector) 0.1) | ||
(send self :wait-interpolation) | ||
|
||
(setq goal (instance kxr_controller::ServoOnOffGoal :init)) | ||
(send goal :joint_names names) | ||
(send goal :servo_on_states (make-array (length names) :initial-element t)) | ||
(send servo-on-off-client :send-goal goal))) | ||
(:servo-off | ||
(&key (names nil)) | ||
(unless joint-action-enable | ||
(if viewer (send self :draw-objects)) | ||
(return-from :servo-off t)) | ||
(when (null names) | ||
(setq names joint-names)) | ||
(let* (goal result) | ||
(setq goal (instance kxr_controller::ServoOnOffGoal :init)) | ||
(send goal :joint_names names) | ||
(send goal :servo_on_states (make-array (length names) :initial-element nil)) | ||
(send servo-on-off-client :send-goal goal)))) | ||
|
||
|
||
(defun kxr-init (&key | ||
(namespace nil) | ||
(create-viewer t)) | ||
(unless (boundp '*robot*) | ||
(setq *robot* (load-robot-model :namespace namespace | ||
:port (ros::get-param (if namespace (format nil "~A/port" namespace) "/port") 8000)))) | ||
(unless (ros::ok) (ros::roseus "kxr_eus_interface")) | ||
(unless (boundp '*ri*) | ||
(setq *ri* (instance kxr-interface :init *robot* :namespace namespace))) | ||
|
||
(ros::spin-once) | ||
(send *ri* :spin-once) | ||
(send *robot* :angle-vector (send *ri* :angle-vector)) | ||
(when create-viewer (objects (list *robot*)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<launch> | ||
|
||
<arg name="namespace" default="" /> | ||
<arg name="port" default="8000" /> | ||
|
||
<group if="$(eval len(arg('namespace')) > 0)" ns="$(arg namespace)" > | ||
<node name="eusmodel_server" | ||
pkg="kxreus" type="eus_model_server.py" > | ||
</node> | ||
|
||
<node name="http_server_node" | ||
pkg="kxreus" type="http_server_node.py" > | ||
<rosparam subst_value="true" > | ||
port: $(arg port) | ||
</rosparam> | ||
</node> | ||
</group> | ||
|
||
<group unless="$(eval len(arg('namespace')) > 0)"> | ||
<node name="eusmodel_server" | ||
pkg="kxreus" type="eus_model_server.py" > | ||
</node> | ||
|
||
<node name="http_server_node" | ||
pkg="kxreus" type="http_server_node.py" > | ||
<rosparam subst_value="true" > | ||
port: $(arg port) | ||
</rosparam> | ||
</node> | ||
</group> | ||
|
||
</launch> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#!/usr/bin/env python | ||
|
||
import hashlib | ||
import os | ||
import tempfile | ||
|
||
from filelock import FileLock | ||
import rospkg | ||
import rospy | ||
from skrobot.model import RobotModel | ||
from skrobot.utils.urdf import no_mesh_load_mode | ||
from urdfeus.urdf2eus import urdf2eus | ||
|
||
|
||
def checksum_md5(filename, blocksize=8192): | ||
"""Calculate md5sum. | ||
Parameters | ||
---------- | ||
filename : str or pathlib.Path | ||
input filename. | ||
blocksize : int | ||
MD5 has 128-byte digest blocks (default: 8192 is 128x64). | ||
Returns | ||
------- | ||
md5 : str | ||
calculated md5sum. | ||
""" | ||
filename = str(filename) | ||
hash_factory = hashlib.md5() | ||
with open(filename, 'rb') as f: | ||
for chunk in iter(lambda: f.read(blocksize), b''): | ||
hash_factory.update(chunk) | ||
return hash_factory.hexdigest() | ||
|
||
|
||
class EusModelServer(object): | ||
|
||
def __init__(self): | ||
full_namespace = rospy.get_namespace() | ||
last_slash_pos = full_namespace.rfind('/') | ||
self.clean_namespace = full_namespace[:last_slash_pos] \ | ||
if last_slash_pos != 0 else '' | ||
|
||
def run(self): | ||
rate = rospy.Rate(1) | ||
while not rospy.is_shutdown(): | ||
rate.sleep() | ||
urdf = rospy.get_param( | ||
self.clean_namespace + '/robot_description', | ||
None) | ||
if urdf is not None: | ||
tmp_file = tempfile.mktemp() | ||
with open(tmp_file, "w") as f: | ||
f.write(urdf) | ||
md5sum = checksum_md5(tmp_file) | ||
|
||
r = RobotModel() | ||
with open(tmp_file, 'r') as f: | ||
with no_mesh_load_mode(): | ||
r.load_urdf_file(f) | ||
robot_name = r.urdf_robot_model.name | ||
|
||
rospack = rospkg.RosPack() | ||
kxreus_path = rospack.get_path('kxreus') | ||
eus_path = os.path.join( | ||
kxreus_path, 'models', '{}.l'.format(md5sum)) | ||
if os.path.exists(eus_path): | ||
rospy.set_param(self.clean_namespace + '/eus_robot_name', | ||
robot_name) | ||
rospy.set_param(self.clean_namespace + '/eusmodel_hash', | ||
md5sum) | ||
continue | ||
|
||
lock_path = eus_path + ".lock" | ||
lock = FileLock(lock_path, timeout=10) | ||
try: | ||
with lock: | ||
with open(eus_path, 'w') as f: | ||
urdf2eus(tmp_file, fp=f) | ||
rospy.loginfo( | ||
'Eusmodel is saved to {}'.format(eus_path)) | ||
os.remove(lock_path) | ||
finally: | ||
if os.path.exists(tmp_file): | ||
os.remove(tmp_file) | ||
|
||
|
||
if __name__ == '__main__': | ||
rospy.init_node('model_server') | ||
server = EusModelServer() | ||
server.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
#!/usr/bin/env python | ||
|
||
from http.server import HTTPServer | ||
from http.server import SimpleHTTPRequestHandler | ||
import os | ||
import threading | ||
|
||
from filelock import FileLock | ||
from filelock import Timeout | ||
import rospkg | ||
import rospy | ||
|
||
|
||
class CustomHTTPRequestHandler(SimpleHTTPRequestHandler): | ||
def __init__(self, *args, directory=None, **kwargs): | ||
self.base_directory = directory | ||
super().__init__(*args, **kwargs) | ||
|
||
def translate_path(self, path): | ||
path = super().translate_path(path) | ||
rel_path = os.path.relpath(path, os.getcwd()) | ||
full_path = os.path.join(self.base_directory, rel_path) \ | ||
if self.base_directory else path | ||
return full_path | ||
|
||
def do_GET(self): | ||
filepath = self.translate_path(self.path) | ||
lock_path = filepath + ".lock" | ||
|
||
if os.path.exists(lock_path): | ||
try: | ||
with FileLock(lock_path, timeout=1): | ||
super().do_GET() | ||
except Timeout: | ||
self.send_response(503) | ||
self.end_headers() | ||
self.wfile.write( | ||
b"Service Unavailable: File is currently locked.") | ||
else: | ||
super().do_GET() | ||
|
||
|
||
class ThreadedHTTPServer(object): | ||
def __init__(self, host, port, handler_class, directory): | ||
def handler_factory(*args, **kwargs): | ||
return handler_class( | ||
*args, directory=directory, **kwargs) | ||
self.server = HTTPServer((host, port), handler_factory) | ||
self.server_thread = threading.Thread(target=self.server.serve_forever) | ||
self.server_thread.daemon = True | ||
|
||
def start(self): | ||
self.server_thread.start() | ||
rospy.loginfo("HTTP Server Running...") | ||
|
||
def stop(self): | ||
self.server.shutdown() | ||
self.server.server_close() | ||
rospy.loginfo("HTTP Server Stopped.") | ||
|
||
|
||
if __name__ == '__main__': | ||
rospy.init_node('http_server_node') | ||
|
||
rospack = rospkg.RosPack() | ||
kxreus_path = rospack.get_path('kxreus') | ||
www_directory = os.path.join(kxreus_path, 'models') | ||
|
||
full_namespace = rospy.get_namespace() | ||
last_slash_pos = full_namespace.rfind('/') | ||
clean_namespace = full_namespace[:last_slash_pos] \ | ||
if last_slash_pos != 0 else '' | ||
|
||
port = rospy.get_param(clean_namespace + '/port', 8000) | ||
server = ThreadedHTTPServer( | ||
'0.0.0.0', port, CustomHTTPRequestHandler, www_directory) | ||
server.start() | ||
|
||
rospy.spin() | ||
|
||
server.stop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
scikit-robot==0.0.32 | ||
urdfeus==0.0.5 | ||
scikit-robot | ||
urdfeus |