Skip to content

Commit de4a444

Browse files
committed
- Removed the need for _extra in eye_asset/name. Introduced asset_param_list.py to provide a list of parameters, since rosserial_client does not support param_list.
- Added support for iris_zoom (controls iris and pupil reflex), upperlid_zoom, and extra_zoom.
1 parent c936971 commit de4a444

File tree

8 files changed

+276
-114
lines changed

8 files changed

+276
-114
lines changed

eye_display/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ include_directories()
99

1010
catkin_install_python(PROGRAMS
1111
node_scripts/build.py node_scripts/demo_move_eye.py node_scripts/pub_eye_status.py
12-
node_scripts/ros_to_i2c.py
12+
node_scripts/ros_to_i2c.py node_scripts/asset_param_list.py
1313
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/node_scripts)

eye_display/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,12 @@ If you need more than the standard images (outline, iris, pupil, reflex, upperli
146146
extra1_position_x: [ 0, 20, 40, 20, 0, -20, -40, -20]
147147
extra1_position_y: [ 40, 20, 0, -20, -40, -20, 0, 20]
148148
extra1_rotation_theta: [ 0, 40, 80, 40, 0, -40, -80, -40]
149+
extra1_zoom: [ 1.0, 1.1, 1.2, 1.3, 1.4, 1.2, 1.0, 0.8, 0.7, 0.8, 0.9]
149150
path_extra2: "/krmt_reflex_heart.png"
150151
extra2_position_x: [ 0, 20, 0, -20]
151152
extra2_position_y: [ 0, 10, 0, -10]
152153
extra2_rotation_theta: [ 0, -40, -80, -40, 0, 40, 80, 40]
154+
extra2_zoom: [1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 1.5, 1.0, 0.5]
153155
extra2_default_pos_x: 75
154156
extra2_default_pos_y: 75
155157
extra2_default_theta: 0
@@ -183,6 +185,8 @@ rosrun eye_display update_ros_lib.sh
183185
This feature requires git 2.27+, so if you use Ubuntu<=20.04, please install latest version of git https://git-scm.com/downloads/linux
184186

185187
```
186-
$ git clone --filter=blob:none --sparse https://github.com/jsk-ros-pkg/jsk_3rdparty.git -b eye_display
187-
$ git sparse-checkout set eye_display
188+
git clone --filter=blob:none --sparse https://github.com/jsk-ros-pkg/jsk_3rdparty.git
189+
cd jsk_3rdparty
190+
git sparse-checkout set eye_display
191+
git checkout eye_display
188192
```

eye_display/include/eye.hpp

Lines changed: 103 additions & 23 deletions
Large diffs are not rendered by default.

eye_display/include/node_handle_ex.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ class NodeHandleEx : public NodeHandle_<Hardware, MAX_SUBSCRIBERS, MAX_PUBLISHER
1818
return super::getParam(name, param, length, timeout);
1919
}
2020
bool getParam(const char* name, float* param, int length = 1, int timeout = 1000) {
21-
logwarn("Failed to get param: length mismatch float");
2221
return super::getParam(name, param, length, timeout);
2322
}
2423
bool getParam(const char* name, char** param, int length = 1, int timeout = 1000) {
@@ -56,6 +55,16 @@ class NodeHandleEx : public NodeHandle_<Hardware, MAX_SUBSCRIBERS, MAX_PUBLISHER
5655
param[i] = super::req_param_resp.ints[i];
5756
return true;
5857
}
58+
bool getParam(const char *name, std::vector<float> &param, int timeout = 1000)
59+
{
60+
if (!super::requestParam(name, timeout))
61+
return false;
62+
param.resize(super::req_param_resp.floats_length);
63+
// copy it over
64+
for (int i = 0; i < super::req_param_resp.floats_length; i++)
65+
param[i] = super::req_param_resp.floats[i];
66+
return true;
67+
}
5968

6069
#define def_char_log_formatter(funcname) \
6170
void funcname(const char *format, ...) { \

eye_display/include/ros_lib.h

Lines changed: 80 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ extern EyeManager eye;
3737

3838
ros::Subscriber<geometry_msgs::Point> sub_point("~look_at", &callback_look_at);
3939
ros::Subscriber<std_msgs::String> sub_eye_status("~eye_status", &callback_emotion);
40+
4041
void callback_look_at(const geometry_msgs::Point &msg)
4142
{
4243
eye.set_gaze_direction((float)msg.x, (float)msg.y);
@@ -49,13 +50,6 @@ void callback_emotion(const std_msgs::String &msg)
4950
std::string ros_read_asset()
5051
{
5152
std::map<std::string, EyeAsset>& eye_asset_map = eye.eye_asset_map;
52-
while (not nh.connected())
53-
{
54-
nh.spinOnce();
55-
delay(1000);
56-
}
57-
delay(500); // wait 0.5 sec before reading asset
58-
5953
std::ostringstream oss;
6054

6155
bool mode_right;
@@ -77,94 +71,102 @@ std::string ros_read_asset()
7771
oss << "eye_asset_names: ";
7872
for (auto it = eye_asset_names.begin(); it != eye_asset_names.end(); ++it) {
7973
std::string name = *it;
80-
std::string suffix = "_extra";
81-
if (name.size() >= suffix.size() &&
82-
name.rfind(suffix) == name.size() - suffix.size()) {
83-
name = name.substr(0, name.size() - suffix.size());
84-
}
8574
oss << name;
8675
if (std::next(it) != eye_asset_names.end()) oss << ", ";
8776
}
8877
oss << "\n";
8978
//
9079
for(auto name: eye_asset_names) {
9180
char eye_asset_map_key[256];
92-
bool have_extra = false;
93-
std::string suffix = "_extra";
94-
if (name.size() >= suffix.size() &&
95-
name.rfind(suffix) == name.size() - suffix.size()) {
96-
name = name.substr(0, name.size() - suffix.size());
97-
have_extra = true;
98-
}
99-
// path_upperlid
100-
for(const std::string& type: {"upperlid", "outline", "iris", "pupil", "reflex"}) {
81+
82+
// path
83+
std::vector<std::string> eye_types;
84+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset_%s_eye_types", name.c_str());
85+
nh.getParam(eye_asset_map_key, eye_types);
86+
for(const std::string& type: eye_types) {
10187
std::string path;
10288
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/path_%s", name.c_str(), type.c_str());
10389
if (nh.getParam(eye_asset_map_key, path)) {
10490
oss << "eye_asset_image_path: " << name << ": " << type << ": " << path << "\n";
10591
}
10692
}
107-
// upperlid_position, upperlid_default_pos_x, upperlid_default_pos_y, upperlid_default_theta
108-
std::vector<int> position;
109-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/upperlid_position", name.c_str());
110-
if (nh.getParam(eye_asset_map_key, position, 300)) { // timeout == 300
111-
oss << "eye_asset_position: " << name << ": upperlid: " << joinVector(position) << "\n";
112-
} else { // v2 API, upperlid_position_x, upperlid_position_y, upperlid_rotate_theta instead of upperlid_position
113-
nh.logwarn("Using v2 API (position_x, position_y, rotation_theta). Please ignore the above 'Parameter %sn does not exist' message", eye_asset_map_key);
114-
std::vector<int> position_x, position_y, rotation_theta;
115-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/upperlid_position_x", name.c_str());
116-
if (nh.getParam(eye_asset_map_key, position_x)) {
117-
oss << "eye_asset_position_x: " << name << ": upperlid: " << joinVector(position_x) << "\n";
118-
}
119-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/upperlid_position_y", name.c_str());
120-
if (nh.getParam(eye_asset_map_key, position_y)) {
121-
oss << "eye_asset_position_y: " << name << ": upperlid: " << joinVector(position_y) << "\n";
122-
}
123-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/upperlid_rotation_theta", name.c_str());
124-
if (nh.getParam(eye_asset_map_key, rotation_theta)) {
125-
oss << "eye_asset_rotation_theta: " << name << ": upperlid: " << joinVector(rotation_theta) << "\n";
126-
}
127-
} //v2 API
128-
for(const std::string& pos: {"default_pos_x", "default_pos_y", "default_theta"}) {
129-
int data;
130-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/upperlid_%s", name.c_str(), pos.c_str());
131-
if (nh.getParam(eye_asset_map_key, &data)) {
132-
oss << "eye_asset_" << pos << ": " << name << ": upperlid: " << data << "\n";
93+
94+
// position
95+
std::vector<std::string> eye_positions;
96+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset_%s_positions", name.c_str());
97+
nh.getParam(eye_asset_map_key, eye_positions);
98+
for(const std::string& eye_position: eye_positions) {
99+
if (eye_position == "NONE") continue;
100+
std::vector<int> position;
101+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s", name.c_str(), eye_position.c_str());
102+
if (nh.getParam(eye_asset_map_key, position)) {
103+
size_t pos = eye_position.find('_');
104+
if ( pos != std::string::npos ) {
105+
std::string eye_type = eye_position.substr(0, pos);
106+
std::string position_type = eye_position.substr(pos+1);
107+
oss << "eye_asset_" << position_type << ": " << name << ": " << eye_type << ": " << joinVector(position) << "\n";
108+
} else {
109+
logerror("Invalid param name : %s", eye_position);
110+
}
133111
}
134112
}
135-
// v3 API (extra images)
136-
if (have_extra) {
137-
for(const std::string& type: {"extra1", "extra2"}) {
138-
std::string path;
139-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/path_%s", name.c_str(), type.c_str());
140-
if (nh.getParam(eye_asset_map_key, path, 300)) { // timeout == 300
141-
oss << "eye_asset_image_path: " << name << ": " << type << ": " << path << "\n";
142-
}
143-
std::vector<int> position_x, position_y, rotation_theta;
144-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s_position_x", name.c_str(), type.c_str());
145-
if (nh.getParam(eye_asset_map_key, position_x)) {
146-
oss << "eye_asset_position_x: " << name << ": " << type << ": " << joinVector(position_x) << "\n";
147-
}
148-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s_position_y", name.c_str(), type.c_str());
149-
if (nh.getParam(eye_asset_map_key, position_y)) {
150-
oss << "eye_asset_position_y: " << name << ": " << type << ": " << joinVector(position_y) << "\n";
151-
}
152-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s_rotation_theta", name.c_str(), type.c_str());
153-
if (nh.getParam(eye_asset_map_key, rotation_theta)) {
154-
oss << "eye_asset_rotation_theta: " << name << ": " << type << ": " << joinVector(rotation_theta) << "\n";
155-
}
156-
int data;
157-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s_default_pos_x", name.c_str(), type.c_str());
158-
if (nh.getParam(eye_asset_map_key, &data)) {
159-
oss << "eye_asset_default_pos_x: " << name << ": " << type << ": " << data << "\n";
113+
114+
// rotation
115+
std::vector<std::string> eye_rotations;
116+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset_%s_rotations", name.c_str());
117+
nh.getParam(eye_asset_map_key, eye_rotations);
118+
for(const std::string& eye_rotation: eye_rotations) {
119+
if (eye_rotation == "NONE") continue;
120+
std::vector<int> rotation;
121+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s", name.c_str(), eye_rotation.c_str());
122+
if (nh.getParam(eye_asset_map_key, rotation)) {
123+
size_t pos = eye_rotation.find('_');
124+
if ( pos != std::string::npos ) {
125+
std::string eye_type = eye_rotation.substr(0, pos);
126+
std::string rotation_type = eye_rotation.substr(pos+1);
127+
oss << "eye_asset_" << rotation_type << ": " << name << ": " << eye_type << ": " << joinVector(rotation) << "\n";
128+
} else {
129+
logerror("Invalid param name : %s", eye_rotation);
160130
}
161-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s_default_pos_y", name.c_str(), type.c_str());
162-
if (nh.getParam(eye_asset_map_key, &data)) {
163-
oss << "eye_asset_default_pos_y: " << name << ": " << type << ": " << data << "\n";
131+
}
132+
}
133+
134+
// default
135+
std::vector<std::string> eye_defaults;
136+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset_%s_defaults", name.c_str());
137+
nh.getParam(eye_asset_map_key, eye_defaults);
138+
for(const std::string& eye_default: eye_defaults) {
139+
if (eye_default == "NONE") continue;
140+
std::vector<int> defaults;
141+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s", name.c_str(), eye_default.c_str());
142+
if (nh.getParam(eye_asset_map_key, defaults)) {
143+
size_t pos = eye_default.find('_');
144+
if ( pos != std::string::npos ) {
145+
std::string eye_type = eye_default.substr(0, pos);
146+
std::string default_type = eye_default.substr(pos+1);
147+
oss << "eye_asset_" << default_type << ": " << name << ": " << eye_type << ": " << joinVector(defaults) << "\n";
148+
} else {
149+
logerror("Invalid param name : %s", eye_default);
164150
}
165-
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s_default_theta", name.c_str(), type.c_str());
166-
if (nh.getParam(eye_asset_map_key, &data)) {
167-
oss << "eye_asset_default_theta: " << name << ": " << type << ": " << data << "\n";
151+
}
152+
}
153+
154+
// zoom
155+
std::vector<std::string> eye_zooms;
156+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset_%s_zooms", name.c_str());
157+
nh.getParam(eye_asset_map_key, eye_zooms);
158+
for(const std::string& eye_zoom: eye_zooms) {
159+
if (eye_zoom == "NONE") continue;
160+
std::vector<float> zooms;
161+
snprintf(eye_asset_map_key, sizeof(eye_asset_map_key), "~eye_asset/%s/%s", name.c_str(), eye_zoom.c_str());
162+
if (nh.getParam(eye_asset_map_key, zooms)) {
163+
size_t pos = eye_zoom.find('_');
164+
if ( pos != std::string::npos ) {
165+
std::string eye_type = eye_zoom.substr(0, pos);
166+
std::string zoom_type = eye_zoom.substr(pos+1);
167+
oss << "eye_asset_" << zoom_type << ": " << name << ": " << eye_type << ": " << joinVector(zooms) << "\n";
168+
} else {
169+
logerror("Invalid param name : %s", eye_zoom);
168170
}
169171
}
170172
}

eye_display/launch/demo.launch

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,34 @@
1414
type="serial_node.py"
1515
name="eye_display"
1616
output="screen"
17-
unless="$(arg use_i2c)"
17+
unless="$(arg use_i2c)"
1818
>
1919
<param name="port" value="$(arg port)" />
2020
<param name="baud" value="$(arg baud)" />
2121
<param name="mode_right" value="$(arg mode_right)" />
2222
<param name="direction" value="$(arg direction)" />
2323
<rosparam command="load" ns="eye_asset" file="$(arg eye_asset_file)" />
24-
<param name="eye_asset_text" command="cat $(arg eye_asset_file)" />
24+
</node>
25+
<!-- The namespace (ns) used by asset_param_list must match the
26+
node name of serial_node.py. If you rename node name of
27+
serial_node.py, make sure to update the namespace in
28+
asset_param_list.py accordingly to ensure proper parameter
29+
retrieval. -->
30+
<node
31+
ns="eye_display"
32+
pkg="eye_display"
33+
type="asset_param_list.py"
34+
name="asset_param_list"
35+
output="screen"
36+
unless="$(arg use_i2c)"
37+
>
2538
</node>
2639
<node
2740
pkg="eye_display"
2841
type="ros_to_i2c.py"
2942
name="eye_display"
3043
output="screen"
31-
if="$(arg use_i2c)"
44+
if="$(arg use_i2c)"
3245
>
3346
<param name="i2c_device" value="$(arg i2c_device)" />
3447
<param name="i2c_bus" value="$(arg i2c_bus)" />
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env python
2+
3+
import os
4+
import rospy
5+
import rosparam
6+
from rosserial_msgs.srv import RequestParam, RequestParamResponse
7+
8+
# This node provides a list of parameters related to eye_asset.
9+
# When getParam is called from the ESP32 with non-existent names, it takes a long time to timeout and returns an error.
10+
# To prevent this delay, we first retrieve the list of available parameter names before requesting their values.
11+
12+
def main():
13+
rospy.init_node('asset_param_list')
14+
15+
# get eye_asset param
16+
param_ns = rospy.get_namespace().rstrip('/')
17+
eye_asset_names = rospy.get_param("{}/eye_asset/names".format(param_ns))
18+
19+
for name in eye_asset_names:
20+
eye_asset_param_names = rospy.get_param("{}/eye_asset/{}".format(param_ns, name)).keys()
21+
22+
eye_types = []
23+
for key in eye_asset_param_names:
24+
# image path : cehck if key start with path_
25+
if key.startswith("path_"):
26+
eye_type = key[len("path_"):]
27+
eye_types.append(eye_type)
28+
rospy.set_param("{}/eye_asset_{}_eye_types".format(param_ns, name), eye_types)
29+
30+
positions = []
31+
for eye_type in eye_types:
32+
positions.extend([n for n in eye_asset_param_names if n.startswith("{}_position".format(eye_type))])
33+
if not positions:
34+
positions.append('NONE')
35+
rospy.set_param("{}/eye_asset_{}_positions".format(param_ns, name), positions)
36+
37+
rotations = []
38+
for eye_type in eye_types:
39+
rotations.extend([n for n in eye_asset_param_names if n.startswith("{}_rotation".format(eye_type))])
40+
if not rotations:
41+
rotations.append('NONE')
42+
rospy.set_param("{}/eye_asset_{}_rotations".format(param_ns, name), rotations)
43+
44+
defaults = []
45+
for eye_type in eye_types:
46+
defaults.extend([n for n in eye_asset_param_names if n.startswith("{}_default".format(eye_type))])
47+
if not defaults:
48+
defaults.append('NONE')
49+
rospy.set_param("{}/eye_asset_{}_defaults".format(param_ns, name), defaults)
50+
51+
zooms = []
52+
for eye_type in eye_types:
53+
zooms.extend([n for n in eye_asset_param_names if n.startswith("{}_zoom".format(eye_type))])
54+
if not zooms:
55+
zooms.append('NONE')
56+
rospy.set_param("{}/eye_asset_{}_zooms".format(param_ns, name), zooms)
57+
58+
if __name__ == "__main__":
59+
main()

eye_display/node_scripts/ros_to_i2c.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ def main():
9494
rospy.logwarn("Invalid direction ({})".format(direction))
9595

9696
# get eye_asset param
97-
eye_asset_names_raw = rospy.get_param("~eye_asset/names")
98-
# remove '_extra' suffix when setting eye_asset_names.
99-
eye_asset_names = [s[:-len("_extra")] if s.endswith("_extra") else s for s in eye_asset_names_raw]
97+
eye_asset_names = rospy.get_param("~eye_asset/names")
10098
send_data_to_i2c("eye_asset_names: {}".format(', '.join(eye_asset_names)))
10199

102100
for name in eye_asset_names:
@@ -125,6 +123,3 @@ def main():
125123

126124
if __name__ == "__main__":
127125
main()
128-
129-
130-

0 commit comments

Comments
 (0)