Skip to content

Commit 418ebae

Browse files
committed
feat: read csv compatibility and use dropdown to show compatibile robots
1 parent 028ae64 commit 418ebae

13 files changed

+292
-47
lines changed

.editorconfig

-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ max_line_length = 170
2525
[installation_linux.rst]
2626
max_line_length = 150
2727

28-
[installation_windows.rst]
29-
max_line_length = 140
30-
3128
[franka_ros2.rst]
3229
max_line_length = 151
3330

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
.vscode
44
package-lock.json
55
.env
6+
__pycache__
7+
source/_static/compatibility_data.js

Makefile

+14-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,20 @@ BUILDDIR = build
1212
help:
1313
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
1414

15-
.PHONY: help Makefile
15+
.PHONY: help Makefile clean html
16+
17+
# Generate compatibility data JavaScript file
18+
generate-js:
19+
@chmod +x $(SOURCEDIR)/_static/generate_compatibility_js.py
20+
@$(SOURCEDIR)/_static/generate_compatibility_js.py
21+
22+
# Clean build directory
23+
clean:
24+
rm -rf $(BUILDDIR)/*
25+
26+
# Custom html target that first generates JS
27+
html: generate-js
28+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
1629

1730
# Catch-all target: route all unknown targets to Sphinx using the new
1831
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).

source/_static/compatibility_data.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""Compatibility data for different robot versions."""
2+
3+
import os
4+
import csv
5+
from pathlib import Path
6+
7+
8+
def read_csv_data(file_path):
9+
"""Read CSV file and return headers and data."""
10+
print(f"Reading CSV file: {file_path}")
11+
with open(file_path, "r", encoding="utf-8") as f:
12+
reader = csv.reader(f)
13+
headers = next(reader) # First row contains headers
14+
data = [row for row in reader]
15+
print(f"Headers: {headers}")
16+
print(f"Data: {data}")
17+
return headers, data
18+
19+
20+
def load_compatibility_data():
21+
"""Load compatibility data from CSV files."""
22+
data_dir = Path(__file__).parent / "compatibility_data"
23+
print(f"Looking for CSV files in: {data_dir}")
24+
compatibility_data = {}
25+
26+
# Map of robot types to their CSV files
27+
robot_files = {"FR3": "FR3.csv", "FER": "FER.csv"}
28+
29+
for robot, filename in robot_files.items():
30+
file_path = data_dir / filename
31+
print(f"Checking for file: {file_path}")
32+
if file_path.exists():
33+
print(f"Found file for {robot}")
34+
headers, data = read_csv_data(file_path)
35+
compatibility_data[robot] = {"headers": headers, "data": data}
36+
else:
37+
print(f"File not found for {robot}")
38+
39+
print(f"Final compatibility data: {compatibility_data}")
40+
return compatibility_data
41+
42+
43+
# Load the compatibility data when the module is imported
44+
COMPATIBILITY_DATA = load_compatibility_data()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Robot System Version,libfranka Version,Robot/Gripper Server,franka_ros Version,Ubuntu / ROS 1
2+
>= 4.2.1,>= 0.9.1 < 0.10.0,5 / 3,>= 0.8.0,20.04 / noetic
3+
>= 4.0.0,>= 0.8.0,4 / 3,>= 0.8.0,20.04 / noetic
4+
>= 3.0.0,0.7.1,3 / 3,0.7.0,18.04 / melodic
5+
>= 1.3.0,0.5.0,3 / 2,0.6.0,16.04 / kinetic
6+
>= 1.2.0,0.3.0,2 / 2,0.4.0,16.04 / kinetic
7+
>= 1.1.0,0.2.0,2 / 1,,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Robot System Version,libfranka Version,Robot/Gripper Server,franka_ros2 Version,Ubuntu / ROS 2,franka_ros Version
2+
>= 5.7.2,>= 0.15.0,9 / 3,>= v1.0.0,22.04 / humble,>= 0.10.0
3+
>= 5.7.0,>= 0.14.0,8 / 3,N/A,22.04 / humble,>= 0.10.0
4+
>= 5.5.0,>= 0.13.3,7 / 3,">= v0.1.15",22.04 / humble,>= 0.10.0
5+
>= 5.2.0,">= 0.10.0 to >= 0.13.0",6 / 3,">= v0.1.0 to >= v0.1.8",22.04 / humble,>= 0.10.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Script to generate JavaScript compatibility data file from CSV files.
4+
This script reads CSV files containing compatibility information for different robot types
5+
and generates a JavaScript file with the data structured for use in the documentation.
6+
"""
7+
8+
import os
9+
import csv
10+
import json
11+
from pathlib import Path
12+
13+
14+
def read_csv_file(file_path):
15+
"""Read a CSV file and return headers and data."""
16+
with open(file_path, "r") as f:
17+
reader = csv.reader(f)
18+
headers = next(reader) # First row contains headers
19+
data = [row for row in reader]
20+
return headers, data
21+
22+
23+
def generate_js():
24+
"""Generate JavaScript file with compatibility data."""
25+
# Directory containing CSV files
26+
csv_dir = Path("source/_static/compatibility_data")
27+
28+
# Dictionary to store compatibility data
29+
compatibility_data = {}
30+
31+
# Map of file names to display names
32+
robot_display_names = {"FR3": "Franka Research 3", "FER": "FER"}
33+
34+
# Read each CSV file in the directory
35+
for csv_file in csv_dir.glob("*.csv"):
36+
robot_type = csv_file.stem # Get filename without extension
37+
headers, data = read_csv_file(csv_file)
38+
display_name = robot_display_names.get(robot_type, robot_type)
39+
compatibility_data[display_name] = {"headers": headers, "data": data}
40+
41+
# Robot descriptions
42+
robot_descriptions = {
43+
"Franka Research 3": "Latest generation Franka Robot with ROS 2 support",
44+
"FER": "Previous generation Franka Emika Robot",
45+
}
46+
47+
# Generate JavaScript content
48+
js_content = f"""// Generated compatibility data
49+
const compatibilityData = {json.dumps(compatibility_data, indent=2)};
50+
51+
// Robot descriptions
52+
const robotDescriptions = {json.dumps(robot_descriptions, indent=2)};
53+
"""
54+
55+
# Write to JavaScript file
56+
js_file_path = Path("source/_static/compatibility_data.js")
57+
with open(js_file_path, "w") as f:
58+
f.write(js_content)
59+
60+
61+
if __name__ == "__main__":
62+
generate_js()

source/compatibility.rst

+133-33
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,138 @@ implying that compatibility is not guaranteed (e.g., libfranka 0.2.0 may not be
1414
The Robot system versions 2.x.x are not listed in the table below, but they are included as compatible with Robot system version >= 1.3.0.
1515
Therefore, they are compatible with libfranka versions 0.4.0 and 0.5.0.
1616

17-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
18-
| Robot system version | libfranka version | Robot / Gripper |franka_ros2 version| franka_description| Ubuntu / ROS 2 | franka_ros version| Ubuntu / ROS 1 |
19-
| | | Server version | | | | | |
20-
+======================+===================+=================+===================+===================+===================+===================+===================+
21-
| >= 5.7.2 (FR3) | >= 0.15.0 | 9 / 3 | >= v1.0.0 | | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
22-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
23-
| >= 5.7.0 (FR3) | >= 0.14.0 | 8 / 3 | | | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
24-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
25-
| >= 5.5.0 (FR3) | >= 0.13.3 | 7 / 3 | >= v0.1.15 | >= 0.3.0 | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
26-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
27-
| >= 5.5.0 (FR3) | >= 0.13.3 | 7 / 3 | | | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
28-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
29-
| >= 5.2.0 (FR3) | >= 0.13.0 | 6 / 3 | >= v0.1.8 | | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
30-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
31-
| >= 5.2.0 (FR3) | >= 0.12.1 | 6 / 3 | >= v0.1.6 | | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
32-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
33-
| >= 5.2.0 (FR3) | >= 0.11.0 | 6 / 3 | >= v0.1.3 | | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
34-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
35-
| >= 5.2.0 (FR3) | >= 0.10.0 | 6 / 3 | >= v0.1.0 | | 22.04 / humble | >= 0.10.0 | 20.04 / noetic |
36-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
37-
| >= 4.2.1 (FER) | >= 0.9.1 < 0.10.0 | 5 / 3 | | | | >= 0.8.0 | 20.04 / noetic |
38-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
39-
| >= 4.0.0 (FER) | >= 0.8.0 | 4 / 3 | | | | >= 0.8.0 | 20.04 / noetic |
40-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
41-
| >= 3.0.0 (FER) | 0.7.1 | 3 / 3 | | | | 0.7.0 | 18.04 / melodic |
42-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
43-
| >= 1.3.0 (FER) | 0.5.0 | 3 / 2 | | | | 0.6.0 | 16.04 / kinetic |
44-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
45-
| >= 1.2.0 (FER) | 0.3.0 | 2 / 2 | | | | 0.4.0 | 16.04 / kinetic |
46-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
47-
| >= 1.1.0 (FER) | 0.2.0 | 2 / 1 | | | | | |
48-
+----------------------+-------------------+-----------------+-------------------+-------------------+-------------------+-------------------+-------------------+
17+
.. raw:: html
18+
19+
<style>
20+
.compatibility-container {
21+
background-color: white;
22+
padding: 20px;
23+
border-radius: 8px;
24+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
25+
margin: 20px 0;
26+
}
27+
.robot-select {
28+
padding: 8px 12px;
29+
font-size: 16px;
30+
margin-bottom: 20px;
31+
border: 1px solid #ddd;
32+
border-radius: 4px;
33+
width: 200px;
34+
}
35+
.compatibility-table {
36+
width: 100%;
37+
border-collapse: collapse;
38+
margin-top: 20px;
39+
}
40+
.compatibility-table th,
41+
.compatibility-table td {
42+
border: 1px solid #ddd;
43+
padding: 12px;
44+
text-align: left;
45+
}
46+
.compatibility-table th {
47+
background-color: #f8f9fa;
48+
font-weight: bold;
49+
}
50+
.compatibility-table tr:nth-child(even) {
51+
background-color: #f8f9fa;
52+
}
53+
.matrix {
54+
display: none;
55+
}
56+
.matrix.active {
57+
display: block;
58+
}
59+
.robot-description {
60+
margin-bottom: 15px;
61+
font-style: italic;
62+
color: #666;
63+
}
64+
</style>
65+
66+
<div class="compatibility-container">
67+
<select class="robot-select" id="robotSelector" onchange="showCompatibility()">
68+
</select>
69+
<div class="robot-description" id="robotDescription"></div>
70+
<div id="matrixContainer"></div>
71+
</div>
72+
73+
<script src="_static/compatibility_data.js"></script>
74+
<script>
75+
// Populate the dropdown
76+
const selector = document.getElementById('robotSelector');
77+
78+
// Sort robot names to ensure Franka Research 3 is first
79+
const robotNames = Object.keys(compatibilityData).sort((a, b) => {
80+
if (a === 'Franka Research 3') return -1;
81+
if (b === 'Franka Research 3') return 1;
82+
return a.localeCompare(b);
83+
});
84+
85+
robotNames.forEach(robot => {
86+
const option = document.createElement('option');
87+
option.value = robot;
88+
option.textContent = robot;
89+
selector.appendChild(option);
90+
});
91+
92+
// Set default selection to Franka Research 3
93+
selector.value = 'Franka Research 3';
94+
showCompatibility(); // Show the default selection immediately
95+
96+
function createTable(robotData) {
97+
const table = document.createElement('table');
98+
table.className = 'compatibility-table';
99+
100+
// Create header row
101+
const headerRow = document.createElement('tr');
102+
robotData.headers.forEach(header => {
103+
const th = document.createElement('th');
104+
th.textContent = header;
105+
headerRow.appendChild(th);
106+
});
107+
table.appendChild(headerRow);
108+
109+
// Create data rows
110+
robotData.data.forEach(row => {
111+
const tr = document.createElement('tr');
112+
row.forEach(cell => {
113+
const td = document.createElement('td');
114+
td.textContent = cell;
115+
tr.appendChild(td);
116+
});
117+
table.appendChild(tr);
118+
});
119+
120+
return table;
121+
}
122+
123+
function showCompatibility() {
124+
const selected = selector.value;
125+
const container = document.getElementById('matrixContainer');
126+
const descriptionElement = document.getElementById('robotDescription');
127+
128+
// Clear previous content
129+
container.innerHTML = '';
130+
descriptionElement.textContent = '';
131+
132+
if (selected && compatibilityData[selected]) {
133+
// Show robot description
134+
if (robotDescriptions[selected]) {
135+
descriptionElement.textContent = robotDescriptions[selected];
136+
}
137+
138+
// Create and show compatibility table
139+
const table = createTable(compatibilityData[selected]);
140+
container.appendChild(table);
141+
}
142+
}
143+
144+
// Initialize on page load
145+
document.addEventListener('DOMContentLoaded', function() {
146+
showCompatibility();
147+
});
148+
</script>
49149

50150
`Robot version line 19
51151
<https://github.com/frankaemika/libfranka-common/blob/fr3-develop/include/research_interface/robot/service_types.h>`_
@@ -74,4 +174,4 @@ The following table gives an overview of recommended Kernels.
74174
| 5.4.19 | 18.04 (Bionic) |
75175
+----------------+-------------------------+
76176
| 4.14.12 | 16.04 (Xenial Xerus) |
77-
+----------------+-------------------------+
177+
+----------------+-------------------------+

source/conf.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,23 @@
1616
# If extensions (or modules to document with autodoc) are in another directory,
1717
# add these directories to sys.path here. If the directory is relative to the
1818
# documentation root, use os.path.abspath to make it absolute, like shown here.
19-
#
20-
# import os
21-
# import sys
22-
# sys.path.insert(0, os.path.abspath('.'))
19+
import os
20+
import sys
21+
import json
22+
from pathlib import Path
23+
24+
sys.path.insert(0, os.path.abspath("_static"))
25+
26+
try:
27+
from compatibility_data import COMPATIBILITY_DATA
28+
29+
print("Loaded compatibility data:", COMPATIBILITY_DATA)
30+
except ImportError as e:
31+
print("Error loading compatibility data:", e)
32+
COMPATIBILITY_DATA = {}
33+
34+
# Make the data available to templates
35+
html_context = {"compatibility_data_json": COMPATIBILITY_DATA}
2336

2437
# -- General configuration ------------------------------------------------
2538

@@ -198,3 +211,6 @@ def api_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
198211
return [node], []
199212

200213
app.add_role("api", api_role)
214+
215+
# Add jinja2 filters
216+
app.add_config_value("compatibility_data_json", COMPATIBILITY_DATA, "html")

source/franka_ros.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ Possible claims to command interfaces are:
11651165
| - ``EffortJointInterface`` + | - ``EffortJointInterface`` + |
11661166
| ``PositionJointInterface`` | ``FrankaCartesianPoseInterface`` |
11671167
| - ``EffortJointInterface`` + | - ``EffortJointInterface`` + |
1168-
| ``VelocityJointInterface`` | ``FrankaCartesianVelocityInterface`` |
1168+
| ``VelocityJointInterface`` | ``FrankaCartesianVelocityInterface`` |
11691169
| - ``EffortJointInterface`` + | |
11701170
| ``FrankaCartesianPoseInterface`` | |
11711171
| - ``EffortJointInterface`` + | |

source/getting_started.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Getting started
22
===============
33

4-
After setting up the required software for :doc:`Linux <installation_linux>` or
5-
:doc:`Windows <installation_windows>`, it is time to connect to the robot and test the whole setup
4+
After setting up the required software for :doc:`Linux <installation_linux>`.
5+
It is time to connect to the robot and test the whole setup
66
by using FCI to read the current robot state.
77

88
Operating the robot

0 commit comments

Comments
 (0)