-TABLE` marker pair |
+| Sidebar config | `sidebars.js` |
+| Doc ID format | `drivers/TSF-85/SDK/C++/index` |
diff --git a/docs/drivers.mdx b/docs/drivers.mdx
deleted file mode 100644
index f9e5b29..0000000
--- a/docs/drivers.mdx
+++ /dev/null
@@ -1,54 +0,0 @@
----
-sidebar_position: 1
----
-
-# Drivers
-
-Select a driver below to get started with your Robotiq hardware.
-
-
-export const C = () => Third party ;
-
-export const N = () => New ;
-
-
-## Drivers for low-level coding
-
-Robotiq hardware communication protocols are described in detail in the product manuals, which serve as the authoritative reference for developing custom drivers.
-
-Below are some low-level drivers developed by Robotiq and third parties.
-
-Feel free to contact Robotiq to share your driver needs — we will investigate development possibilities.
-
-| Hardware | Docs | Python | C++ |
-|---|---|---|---|
-| 2F-85 | [Manual](https://robotiq.com/support) | [pyRobotiqGripper](https://github.com/castetsb/pyRobotiqGripper) | To come soon ... |
-| 2F-140 | [Manual](https://robotiq.com/support) | [pyRobotiqGripper](https://github.com/castetsb/pyRobotiqGripper) | To come soon ... |
-| Hand-E | [Manual](https://robotiq.com/support) | [pyRobotiqGripper](https://github.com/castetsb/pyRobotiqGripper) | To come soon ... |
-| ePick | [Manual](https://robotiq.com/support) |-|-|
-| TSF-85 | [Manual](https://robotiq.com/support) | [Robotiq (git)](https://github.com/Robotiq/tactile_sensors) | [Robotiq (git)](https://github.com/Robotiq/tactile_sensors) |
-| FT300-S | [Manual](https://robotiq.com/support) | [pyFT300](https://github.com/castetsb/pyFT300) | [Sensor development package](https://robotiq.com/support) |
-
-## Drivers for development platforms
-
-Below are some plugins developed by Robotiq and third parties for common robotic software platforms.
-
-Feel free to contact Robotiq to share your plugin needs — we will investigate development possibilities.
-
-
-https://github.com/PickNikRobotics/ros2_epick_gripper
-
-| Hardware | ROS2 | Isaac Sim | PyBullet |
-|---|---|---|---|
-| 2F-85 | [PickNikRobotics - Generic (git)](https://github.com/PickNikRobotics/ros2_robotiq_gripper) [PickNikRobotics - UR (git)](https://github.com/IFRA-Cranfield/ros2_RobotiqGripper_UR) | [Included](https://docs.isaacsim.omniverse.nvidia.com/latest/assets/usd_assets_robots.html) | [pybullet\_ur5\_robotiq](https://github.com/ElectronicElephant/pybullet_ur5_robotiq) |
-| 2F-140 | [PickNikRobotics - Generic (git)](https://github.com/PickNikRobotics/ros2_robotiq_gripper) [PickNikRobotics - UR (git)](https://github.com/IFRA-Cranfield/ros2_RobotiqGripper_UR) | [Included](https://docs.isaacsim.omniverse.nvidia.com/latest/assets/usd_assets_robots.html) | [pybullet\_ur5\_robotiq](https://github.com/ElectronicElephant/pybullet_ur5_robotiq) |
-| Hand-E | [PickNikRobotics - Generic (git)](https://github.com/PickNikRobotics/ros2_robotiq_gripper) [PickNikRobotics - UR (git)](https://github.com/IFRA-Cranfield/ros2_RobotiqGripper_UR) | [Included](https://docs.isaacsim.omniverse.nvidia.com/latest/assets/usd_assets_robots.html) | - |
-| ePick | [PickNikRobotics (git)](https://github.com/PickNikRobotics/ros2_epick_gripper) |-|-|
-| TSF-85 | [Robotiq (git)](https://github.com/robotiq/ros) | [Lab-CORO (git)](https://github.com/Lab-CORO/TSF-85) | - |
-| FT300-S | [PickNikRobotics (git)](https://github.com/panagelak/rq_fts_ros2_driver) | - | - |
-
-## Other useful references
-
-| Repository | Description |
-|---|---|
-| [ur_rtde](https://sdurobotics.gitlab.io/ur_rtde) | Provides some useful [instructions](https://sdurobotics.gitlab.io/ur_rtde/guides/guides.html#use-with-robotiq-gripper) on how to control a Robotiq gripper directly using a raw TCP socket |
diff --git a/docs/drivers/2F hande/GraspGen/index.mdx b/docs/drivers/2F hande/GraspGen/index.mdx
new file mode 100644
index 0000000..d9b4554
--- /dev/null
+++ b/docs/drivers/2F hande/GraspGen/index.mdx
@@ -0,0 +1,18 @@
+---
+title: GraspGen
+sidebar_label: GraspGen
+---
+
+
+
+
+
+
+
+
+
+
+
+Robotiq 2F gripper is part of GraspGen embedded assest.
+
+https://github.com/NVlabs/GraspGen/tree/main/assets/robotiq
\ No newline at end of file
diff --git a/docs/drivers/2F hande/Physics Engine/Isaac Sim/index.mdx b/docs/drivers/2F hande/Physics Engine/Isaac Sim/index.mdx
new file mode 100644
index 0000000..b0c93d2
--- /dev/null
+++ b/docs/drivers/2F hande/Physics Engine/Isaac Sim/index.mdx
@@ -0,0 +1,19 @@
+---
+title: Isaac Sim
+sidebar_label: Isaac Sim
+---
+
+
+
+
+
+
+
+
+
+
+
+Robotiq 2F gripper is part of Isaac Sim embedded assest.
+
+https://docs.isaacsim.omniverse.nvidia.com/latest/assets/usd_assets_robots.html
+
diff --git a/docs/drivers/2F hande/Physics Engine/PyBullet/index.mdx b/docs/drivers/2F hande/Physics Engine/PyBullet/index.mdx
new file mode 100644
index 0000000..02df3fb
--- /dev/null
+++ b/docs/drivers/2F hande/Physics Engine/PyBullet/index.mdx
@@ -0,0 +1,22 @@
+---
+title: PyBullet
+sidebar_label: PyBullet
+---
+
+
+
+
+
+
+
+
+
+
+
+Grippers are controlled by writting their registers using modbus RTU protocol.
+You will find detailed information in the gripper manual available on robotiq
+support page: https://robotiq.com/support
+
+While not developped and supported by robotiq some driver project for PyBullet
+have been done by the community:
+https://github.com/ElectronicElephant/pybullet_ur5_robotiq
\ No newline at end of file
diff --git a/docs/drivers/2F hande/ROS/ROS1/index.mdx b/docs/drivers/2F hande/ROS/ROS1/index.mdx
new file mode 100644
index 0000000..3d6bd38
--- /dev/null
+++ b/docs/drivers/2F hande/ROS/ROS1/index.mdx
@@ -0,0 +1,31 @@
+---
+title: ROS1
+sidebar_label: ROS1
+---
+
+
+
+
+
+
+
+Indigo Jade Kinetic Melodic
+
+
+
+
+
+
+
+
+
+
+
+Grippers are controlled by writting their registers using modbus RTU protocol.
+You will find detailed information in the gripper manual available on robotiq
+support page:
+https://robotiq.com/support
+
+While not developped and supported by robotiq some ROS driver project have
+been done by the community:
+- https://github.com/ros-industrial-attic/robotiq
\ No newline at end of file
diff --git a/docs/drivers/2F hande/ROS/ROS2/index.mdx b/docs/drivers/2F hande/ROS/ROS2/index.mdx
new file mode 100644
index 0000000..b168c15
--- /dev/null
+++ b/docs/drivers/2F hande/ROS/ROS2/index.mdx
@@ -0,0 +1,32 @@
+---
+title: ROS2
+sidebar_label: ROS2
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Robotiq is currently working to provide an official supported ROS 2 driver for
+2F85, 2F140 and Hande grippers.
+
+Grippers are controlled by writting their registers using modbus RTU protocol.
+You will find detailed information in the gripper manual available on robotiq
+support page:
+https://robotiq.com/support
+
+While not developped and supported by robotiq some ROS driver project have
+been done by the community:
+- https://github.com/PickNikRobotics/ros2_robotiq_gripper
diff --git a/docs/drivers/2F hande/SDK/C++/index.mdx b/docs/drivers/2F hande/SDK/C++/index.mdx
new file mode 100644
index 0000000..9fa43b6
--- /dev/null
+++ b/docs/drivers/2F hande/SDK/C++/index.mdx
@@ -0,0 +1,25 @@
+---
+title: C++
+sidebar_label: C++
+---
+
+
+
+
+
+
+
+
+
+
+Robotiq is currently working to provide an official supported C++ driver for
+2F85, 2F140 and Hande grippers.
+
+Grippers are controlled by writting their registers using modbus RTU protocol.
+You will find detailed information in the gripper manual available on robotiq
+support page:
+https://robotiq.com/support
+
+While not developped and supported by robotiq some C++ driver project have
+been done by the community:
+- https://github.com/PickNikRobotics/ros2_robotiq_gripper/tree/main/robotiq_driver
diff --git a/docs/drivers/2F hande/SDK/Python/index.mdx b/docs/drivers/2F hande/SDK/Python/index.mdx
new file mode 100644
index 0000000..350aeec
--- /dev/null
+++ b/docs/drivers/2F hande/SDK/Python/index.mdx
@@ -0,0 +1,21 @@
+---
+title: Python
+sidebar_label: Python
+---
+
+
+
+
+
+
+
+
+
+Grippers are controlled by writting their registers using modbus RTU protocol.
+You will find detailed information in the gripper manual available on robotiq
+support page:
+https://robotiq.com/support
+
+While not developped and supported by robotiq some Python driver project have
+been done by the community:
+- https://github.com/castetsb/pyRobotiqGripper
diff --git a/docs/drivers/2F hande/index.mdx b/docs/drivers/2F hande/index.mdx
new file mode 100644
index 0000000..d4a60c7
--- /dev/null
+++ b/docs/drivers/2F hande/index.mdx
@@ -0,0 +1,77 @@
+---
+title: 2F / Hand-E
+sidebar_label: 2F-85 / 2F-140 / Hand-E
+---
+
+Software tools for 2F-85, 2F-140, and Hand-E adaptive parallel grippers.
+
+
+
+
+
+## Available drivers
+
+### SDK
+
+{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:START */}
+| Product | C | C++ | Python |
+|---|---|---|---|
+| 2F / Hand-E | - | [](SDK/C++) | [](SDK/Python) |
+
+- **C** — Low-level C driver talking directly to the hardware's communication protocol (e.g. Modbus RTU, serial).
+- **C++** — Low-level C++ driver/SDK for direct hardware integration.
+- **Python** — Python driver/SDK for scripting and rapid prototyping.
+{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:END */}
+
+### ROS
+
+#### ROS2
+
+{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:START */}
+| ROS2 | Humble | Iron | Jazzy | Rolling |
+|---|---|---|---|---|
+| 2F / Hand-E | [](ROS/ROS2) | [](ROS/ROS2) | - | [](ROS/ROS2) |
+
+- **Humble** — ROS 2 LTS release (2022), supported until 2027.
+- **Iron** — ROS 2 release (2023), end of life.
+- **Jazzy** — ROS 2 LTS release (2024), supported until 2029.
+- **Rolling** — ROS 2 rolling development distro, always tracking the latest sources.
+{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:END */}
+
+#### ROS1
+
+{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:START */}
+| ROS1 | Indigo | Jade | Kinetic | Melodic |
+|---|---|---|---|---|
+| 2F / Hand-E | [](ROS/ROS1) | [](ROS/ROS1) | [](ROS/ROS1) | [](ROS/ROS1) |
+
+- **Indigo** — ROS 1 release (2014), end of life.
+- **Jade** — ROS 1 release (2015), end of life.
+- **Kinetic** — ROS 1 release (2016), end of life.
+- **Melodic** — ROS 1 release (2018), end of life.
+{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:END */}
+
+### Physics Engine
+
+{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:START */}
+| Product | Isaac Sim | PyBullet |
+|---|---|---|
+| 2F / Hand-E | [](Physics%20Engine/Isaac%20Sim) | [](Physics%20Engine/PyBullet) |
+
+- **Isaac Sim** — NVIDIA Isaac Sim integration for simulating the hardware.
+- **PyBullet** — PyBullet integration for physics-based simulation.
+{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:END */}
+
+### Other
+
+{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:START */}
+| Product | GraspGen |
+|---|---|
+| 2F / Hand-E | [](GraspGen) |
+
+- **GraspGen** — NVIDIA GraspGen asset/model package with Robotiq gripper definitions for grasp synthesis research.
+{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:END */}
diff --git a/docs/drivers/FT300/ROS/ROS2/index.mdx b/docs/drivers/FT300/ROS/ROS2/index.mdx
new file mode 100644
index 0000000..6b44243
--- /dev/null
+++ b/docs/drivers/FT300/ROS/ROS2/index.mdx
@@ -0,0 +1,24 @@
+---
+title: ROS2
+sidebar_label: ROS2
+---
+
+
+
+
+
+
+
+
+
+
+
+The FT300 force and torque data can be read from its modbus registers or stream
+to serial port.
+You will find detailed information in the FT300 manual available on robotiq
+support page:
+https://robotiq.com/support
+
+While not developped and supported by robotiq, some ROS driver project have
+been done by the community:
+- https://github.com/panagelak/rq_fts_ros2_driver
diff --git a/docs/drivers/FT300/SDK/C/_readme.md b/docs/drivers/FT300/SDK/C/_readme.md
new file mode 100644
index 0000000..5e90988
--- /dev/null
+++ b/docs/drivers/FT300/SDK/C/_readme.md
@@ -0,0 +1,125 @@
+# Robotiq FT Sensor Driver (v1.0.1)
+
+C driver for the Robotiq FT 300 force/torque sensor. It talks to the sensor over a serial (RS-485/Modbus) connection, decodes the streaming force/torque data, and exposes it either as console output, over a TCP socket (for Universal Robots integration), or logged to a CSV file. Despite the `.cpp`-style naming in some contexts, the code itself is plain C (C99), compiled with `gcc`.
+
+## Package layout
+
+```
+driver/
+├── makefile # Top-level build rules for all targets
+├── src/ # Platform-independent sensor driver core
+│ ├── rq_int.h # Fixed-width integer typedefs (INT_8, UINT_16, ...)
+│ ├── rq_sensor_com.c/.h # Serial port + Modbus RTU communication with the sensor
+│ ├── rq_sensor_state.c/.h # Driver state machine (init → read info → start stream → run)
+│ └── Thread/ # Thin cross-platform wrappers over pthreads / Win32 threads
+├── Linux/
+│ ├── src/main.c # Standalone console app (prints readings to stdout)
+│ ├── src/rq_sensor_socket.* # TCP server used by the UR build
+│ └── UR/main.c # Universal Robots build: serves sensor data over TCP
+├── Windows/
+│ ├── src/main.c # Standalone console app (Windows serial backend)
+│ ├── compiler.bat # Convenience script to build with MinGW
+│ └── Data_logger/src/main.c # Interactive CLI tool that logs readings to a CSV file
+└── obj/, bin/ # Build output (created by make)
+```
+
+The core (`driver/src`) is shared by every target; only the serial-port backend (`rq_sensor_com.c`, guarded by `__unix__` / `_WIN32` macros) and the entry point (`main.c`) differ per platform.
+
+## What it does
+
+1. Scans serial ports (`/dev/ttyS*`, `/dev/ttyUSB*` on Linux; `COM0`–`COM255` on Windows) at 19200 baud looking for a device that answers a Modbus "read firmware version" request starting with `F`.
+2. Reads high-level sensor info: firmware version, serial number, production year (Modbus holding registers).
+3. Commands the sensor into streaming mode and continuously decodes incoming frames into six force/torque components: `Fx, Fy, Fz` (N) and `Mx, My, Mz` (N·m).
+4. Depending on the build target, either prints the values, serves them over TCP, or writes them to a CSV file.
+
+If the connection drops or an invalid stream is detected, the driver automatically returns to the initialization state and retries.
+
+## Prerequisites
+
+- `gcc` and `make`.
+- Linux: the user running the driver must belong to the `dialout` group to access the serial port (see `driver/Linux/README`).
+- Windows: [MinGW](http://www.mingw.org/) installed (used by `compiler.bat`), plus `zlib1.dll` (bundled in `driver/Windows/`).
+- A Robotiq FT sensor connected via its serial adapter.
+
+## Hello world
+
+The quickest way to see the driver work is to build and run the plain Linux console target:
+
+```bash
+# from the package root
+cd driver
+make linux
+
+# make sure your user can access the serial port (log out/in after this once)
+sudo usermod -aG dialout $USER
+
+# plug in the FT sensor, then run the driver
+./Linux/bin/driverSensor
+```
+
+With the sensor connected, the driver auto-detects it and starts printing one line per reading:
+
+```
+( 0.010000 , -0.002000 , 9.810000 , 0.001000 , 0.000000 , -0.000500 )
+```
+
+That's the sensor saying "hello": each line is a `(Fx, Fy, Fz, Mx, My, Mz)` reading, updated every time a new frame is decoded. Press `Ctrl+C` to stop. See below for the Windows, UR, and data-logger builds.
+
+## Building
+
+All targets are driven by `driver/makefile`, run from the `driver/` directory.
+
+| Command | Produces | Description |
+|---|---|---|
+| `make windows` | `Windows/bin/driverSensor.exe` | Windows console driver |
+| `make linux` | `Linux/bin/driverSensor` | Linux console driver |
+| `make universal` | `Linux/UR/bin/driverSensor` | Linux TCP server build for Universal Robots |
+| `make data_logger` | `Windows/Data_logger/bin/data_logger.exe` | Windows CSV logging tool |
+| `make clean` | — | Removes all build artifacts |
+
+On Windows you can instead double-click/run `driver/Windows/compiler.bat`, which sets up the MinGW `PATH` and calls `make` for you.
+
+Note: `make windows` and `make data_logger` build static libraries (`libRQSensorWin.a`) using `gcc`/`ar` — they are meant to be run from a MinGW shell (e.g. MSYS), not a plain Windows `cmd.exe`, since the makefile relies on Unix-style tools.
+
+## Running
+
+### Console driver (`Linux/bin/driverSensor`, `Windows/bin/driverSensor.exe`)
+
+Run the binary with no arguments. It auto-detects the sensor, then prints one line per reading:
+
+```
+( 0.010000 , -0.002000 , 9.810000 , 0.001000 , 0.000000 , -0.000500 )
+```
+
+The six values are `Fx, Fy, Fz, Mx, My, Mz`, in that order.
+
+### Universal Robots build (`Linux/UR/bin/driverSensor`)
+
+This build has no console output. Instead it opens two TCP servers on `localhost`:
+
+- **Port 63350** — command/accessor socket. Accepts:
+ - `GET SNU` → returns the sensor serial number
+ - `GET FWV` → returns the firmware version
+ - `GET PYE` → returns the production year
+ - `SET ZRO` → zeroes the sensor (tares current force/torque readings as the new baseline)
+- **Port 63351** — streaming socket. Continuously pushes the same `( Fx , Fy , Fz , Mx , My , Mz )` formatted string used by the console build, once per decoded frame.
+
+Only one client per socket is supported (`MAX_CLIENTS = 1`).
+
+### Data logger (`Windows/Data_logger/bin/data_logger.exe`)
+
+Interactive CLI:
+
+1. Prompts for the number of samples to record over a 10-second window (1–1000).
+2. Prompts for an output filename (defaults to `Data.csv` if left blank; `.csv` is appended automatically).
+3. Prints sensor firmware version, serial number, and production year, then streams `t(s),FX,FY,FZ,MX,MY,MZ` rows to both the console and the CSV file at the requested rate.
+
+## Protocol notes
+
+- Communication with the sensor is Modbus RTU over a virtual serial port, slave address `9`, 19200 baud, 8N1.
+- Streaming frames are validated with a Modbus-style CRC16 before being decoded; force components are scaled by `/100` and torque components by `/1000` from the raw 16-bit values.
+- `rq_com_do_zero_force_flag()` / `SET ZRO` captures the current reading as an offset that is subtracted from all subsequent readings (a software zero/tare, not a sensor recalibration).
+
+## License
+
+BSD 3-Clause, Copyright (c) 2014, Robotiq, Inc. Full text is reproduced at the top of every source file.
diff --git a/docs/drivers/FT300/SDK/C/index.mdx b/docs/drivers/FT300/SDK/C/index.mdx
new file mode 100644
index 0000000..5e16230
--- /dev/null
+++ b/docs/drivers/FT300/SDK/C/index.mdx
@@ -0,0 +1,18 @@
+---
+title: C
+sidebar_label: C
+---
+
+
+
+
+
+Robotiq developped a C driver for the FT300S.
+
+This C driver can be downloaded from robotiq support website: https://robotiq.com/support.
+
+Here below is a presentation about this package.
+
+import Readme from './_readme.md';
+
+
diff --git a/docs/drivers/FT300/SDK/Python/index.mdx b/docs/drivers/FT300/SDK/Python/index.mdx
new file mode 100644
index 0000000..ace01a7
--- /dev/null
+++ b/docs/drivers/FT300/SDK/Python/index.mdx
@@ -0,0 +1,23 @@
+---
+title: Python
+sidebar_label: Python
+---
+
+
+
+
+
+
+
+
+
+The FT300 force and torque data can be read from its modbus registers or stream
+to serial port.
+You will find detailed information in the FT300 manual available on robotiq
+support page:
+https://robotiq.com/support
+
+While not developped and supported by robotiq, some python driver project have
+been done by the community:
+- https://github.com/castetsb/pyFT300
+
diff --git a/docs/drivers/FT300/index.mdx b/docs/drivers/FT300/index.mdx
new file mode 100644
index 0000000..b3143ae
--- /dev/null
+++ b/docs/drivers/FT300/index.mdx
@@ -0,0 +1,57 @@
+---
+title: FT300-S
+sidebar_label: FT300-S
+---
+
+Software tool for Robotiq FT300-S force/torque sensor.
+
+
+
+
+
+## Available drivers
+
+### SDK
+
+{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:START */}
+| Product | C | C++ | Python |
+|---|---|---|---|
+| FT300-S | [](SDK/C) | - | [](SDK/Python) |
+
+- **C** — Low-level C driver talking directly to the hardware's communication protocol (e.g. Modbus RTU, serial).
+- **C++** — Low-level C++ driver/SDK for direct hardware integration.
+- **Python** — Python driver/SDK for scripting and rapid prototyping.
+{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:END */}
+
+### ROS
+
+#### ROS2
+
+{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:START */}
+| ROS2 | Humble | Iron | Jazzy | Rolling |
+|---|---|---|---|---|
+| FT300-S | [](ROS/ROS2) | - | - | - |
+
+- **Humble** — ROS 2 LTS release (2022), supported until 2027.
+- **Iron** — ROS 2 release (2023), end of life.
+- **Jazzy** — ROS 2 LTS release (2024), supported until 2029.
+- **Rolling** — ROS 2 rolling development distro, always tracking the latest sources.
+{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:END */}
+
+#### ROS1
+
+{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:START */}
+_No products currently support ROS 1._
+{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:END */}
+
+### Physics Engine
+
+{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:START */}
+_No physics engine integrations documented yet._
+{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:END */}
+
+### Other
+
+{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:START */}
+_No other community integrations documented yet._
+{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:END */}
diff --git a/docs/drivers/TSF-85/Physics Engine/Isaac Sim/index.mdx b/docs/drivers/TSF-85/Physics Engine/Isaac Sim/index.mdx
new file mode 100644
index 0000000..d318b44
--- /dev/null
+++ b/docs/drivers/TSF-85/Physics Engine/Isaac Sim/index.mdx
@@ -0,0 +1,18 @@
+---
+title: Isaac Sim
+sidebar_label: Isaac Sim
+---
+
+
+
+
+
+
+
+
+
+
+
+A Isaac driver for TSF-85 is available in the following repository:
+
+https://github.com/Lab-CORO/TSF-85
\ No newline at end of file
diff --git a/docs/drivers/TSF-85/ROS/ROS2/index.mdx b/docs/drivers/TSF-85/ROS/ROS2/index.mdx
new file mode 100644
index 0000000..48d797c
--- /dev/null
+++ b/docs/drivers/TSF-85/ROS/ROS2/index.mdx
@@ -0,0 +1,78 @@
+---
+title: ROS2
+sidebar_label: ROS2
+---
+
+
+
+
+
+
+
+
+
+
+
+The `robotiq_tsf` ROS 2 Jazzy package publishes the TSF-85 tactile sensor's
+static, dynamic, IMU, and fused-orientation data as ROS topics. It is
+available in the following repository:
+
+https://github.com/robotiq/ros/tree/main/robotiq_tsf
+
+## Build
+
+Clone the repository into your ROS 2 workspace's `src/` folder and build with
+`colcon`:
+
+```bash
+cd ~/ros2_ws/src
+git clone https://github.com/robotiq/ros.git
+cd ~/ros2_ws
+colcon build --packages-select robotiq_tsf
+source install/setup.bash
+```
+
+## Run
+
+Launch the sensor node:
+
+```bash
+ros2 run robotiq_tsf poll_data_node
+```
+
+The node publishes on the following topics:
+
+| Topic | Message Type | Description |
+|---|---|---|
+| `TactileSensor/StaticData` | `robotiq_tsf/StaticData` | Taxel pressure data — two fingers, each with 28 `uint16` values |
+| `TactileSensor/Dynamic` | `robotiq_tsf/Dynamic` | Dynamic force data — two fingers, each with one `int16` value |
+| `TactileSensor/Accelerometer` | `robotiq_tsf/Accelerometer` | Raw accelerometer — two readings of `[x, y, z]` `int16` |
+| `TactileSensor/Gyroscope` | `robotiq_tsf/Gyroscope` | Raw gyroscope — two readings of `[x, y, z]` `int16` |
+| `TactileSensor/EulerAngle` | `robotiq_tsf/EulerAngle` | Fused orientation — two readings of `[roll, pitch, yaw]` `float32` |
+| `TactileSensor/Quaternion` | `robotiq_tsf/Quaternion` | Fused orientation — two readings of `[w, x, y, z]` `float64` |
+| `TactileSensor/Timestamp` | `robotiq_tsf/Timestamp` | Per-finger firmware timestamp — two `uint16` values |
+
+> `EulerAngle` and `Quaternion` are only published once the IMU bias
+> calibration period completes at startup — keep the sensor still during
+> this time.
+
+## Docker
+
+The repository's `docker/` folder provides scripts to build and run the
+driver in a container, with sensor devices mapped in automatically. Clone
+with submodules to pull in the required utilities:
+
+```bash
+git clone --recurse-submodules https://github.com/robotiq/ros.git
+```
+
+If you already cloned without `--recurse-submodules`:
+
+```bash
+git submodule update --init
+```
+
+| Script | Description |
+|---|---|
+| `build_launch_docker_ros2.sh` | Builds the Docker image and launches a container with sensor devices mapped in |
+| `sensor_install.sh` | Sets up udev rules and permissions for bare-metal (non-Docker) use |
diff --git a/docs/drivers/TSF-85/SDK/C++/index.mdx b/docs/drivers/TSF-85/SDK/C++/index.mdx
new file mode 100644
index 0000000..a2da440
--- /dev/null
+++ b/docs/drivers/TSF-85/SDK/C++/index.mdx
@@ -0,0 +1,25 @@
+---
+title: C++
+sidebar_label: C++
+---
+
+
+
+
+
+
+
+
+
+The source files of the TSF CPP driver developed and maintained by Robotiq
+team is available the the following repository:
+
+https://github.com/robotiq/tactile_sensors/tree/main/sdk_cpp
+
+Here below are the related instructions to use this driver.
+
+## Intro
+
+import Readme from './_readme.md';
+
+
\ No newline at end of file
diff --git a/docs/drivers/TSF-85/SDK/Python/index.mdx b/docs/drivers/TSF-85/SDK/Python/index.mdx
new file mode 100644
index 0000000..4c7260b
--- /dev/null
+++ b/docs/drivers/TSF-85/SDK/Python/index.mdx
@@ -0,0 +1,25 @@
+---
+title: Python
+sidebar_label: Python
+---
+
+
+
+
+
+
+
+
+
+Example of TSF usage via python are available developped and maintained by Robotiq
+team is available the the folowing repository:
+
+https://github.com/robotiq/tactile_sensors/tree/main/sensor_quickstart
+
+Are below are the related instructions to use this driver.
+
+## Intro
+
+import Readme from './_readme.md';
+
+
\ No newline at end of file
diff --git a/docs/drivers/TSF-85/index.mdx b/docs/drivers/TSF-85/index.mdx
new file mode 100644
index 0000000..9bc76f8
--- /dev/null
+++ b/docs/drivers/TSF-85/index.mdx
@@ -0,0 +1,70 @@
+---
+title: TSF-85
+sidebar_label: TSF-85
+---
+
+Software tools for Robotiq TSF-85 tactile sensor.
+
+
+
+
+
+
+The TSF-85 provides per-finger data at 1 kHz over USB:
+- **28-element tactile array** (7×4 grid) per finger — updated at 60 Hz
+- **IMU** (accelerometer, gyroscope, magnetometer)
+- **Dynamic tactile** sensor
+
+
+
+## Available drivers
+
+### SDK
+
+{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:START */}
+| Product | C | C++ | Python |
+|---|---|---|---|
+| TSF-85 | - | [](SDK/C++) | [](SDK/Python) |
+
+- **C** — Low-level C driver talking directly to the hardware's communication protocol (e.g. Modbus RTU, serial).
+- **C++** — Low-level C++ driver/SDK for direct hardware integration.
+- **Python** — Python driver/SDK for scripting and rapid prototyping.
+{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:END */}
+
+### ROS
+
+#### ROS2
+
+{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:START */}
+| ROS2 | Humble | Iron | Jazzy | Rolling |
+|---|---|---|---|---|
+| TSF-85 | - | - | [](ROS/ROS2) | - |
+
+- **Humble** — ROS 2 LTS release (2022), supported until 2027.
+- **Iron** — ROS 2 release (2023), end of life.
+- **Jazzy** — ROS 2 LTS release (2024), supported until 2029.
+- **Rolling** — ROS 2 rolling development distro, always tracking the latest sources.
+{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:END */}
+
+#### ROS1
+
+{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:START */}
+_No products currently support ROS 1._
+{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:END */}
+
+### Physics Engine
+
+{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:START */}
+| Product | Isaac Sim | PyBullet |
+|---|---|---|
+| TSF-85 | [](Physics%20Engine/Isaac%20Sim) | - |
+
+- **Isaac Sim** — NVIDIA Isaac Sim integration for simulating the hardware.
+- **PyBullet** — PyBullet integration for physics-based simulation.
+{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:END */}
+
+### Other
+
+{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:START */}
+_No other community integrations documented yet._
+{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:END */}
diff --git a/docs/intro.mdx b/docs/intro.mdx
new file mode 100644
index 0000000..1efca71
--- /dev/null
+++ b/docs/intro.mdx
@@ -0,0 +1,83 @@
+---
+title: Overview
+sidebar_label: Overview
+sidebar_position: 0
+---
+
+## Hardware documentation
+
+Robotiq hardware communication protocols are described in detail in the product
+manuals, which serve as the reference for developing custom drivers.
+
+Hardware manuals are available on Robotiq support website:
+https://robotiq.com/support
+
+## Software tools
+
+Badge colors indicate who maintains the integration:  an official Robotiq-maintained driver,  a community-maintained project.
+
+### SDKs/languages
+
+{/* AUTO-GENERATED-SDK-TABLE:START */}
+| Product | C | C++ | Python |
+|---|---|---|---|
+| [2F / Hand-E](drivers/2F%20hande) | - | [](drivers/2F%20hande/SDK/C++) | [](drivers/2F%20hande/SDK/Python) |
+| [FT300-S](drivers/FT300) | [](drivers/FT300/SDK/C) | - | [](drivers/FT300/SDK/Python) |
+| [TSF-85](drivers/TSF-85) | - | [](drivers/TSF-85/SDK/C++) | [](drivers/TSF-85/SDK/Python) |
+
+- **C** — Low-level C driver talking directly to the hardware's communication protocol (e.g. Modbus RTU, serial).
+- **C++** — Low-level C++ driver/SDK for direct hardware integration.
+- **Python** — Python driver/SDK for scripting and rapid prototyping.
+{/* AUTO-GENERATED-SDK-TABLE:END */}
+
+### ROS
+
+#### ROS2
+
+{/* AUTO-GENERATED-ROS2-TABLE:START */}
+| ROS2 | Humble | Iron | Jazzy | Rolling |
+|---|---|---|---|---|
+| [2F / Hand-E](drivers/2F%20hande) | [](drivers/2F%20hande/ROS/ROS2) | [](drivers/2F%20hande/ROS/ROS2) | - | [](drivers/2F%20hande/ROS/ROS2) |
+| [FT300-S](drivers/FT300) | [](drivers/FT300/ROS/ROS2) | - | - | - |
+| [TSF-85](drivers/TSF-85) | - | - | [](drivers/TSF-85/ROS/ROS2) | - |
+
+- **Humble** — ROS 2 LTS release (2022), supported until 2027.
+- **Iron** — ROS 2 release (2023), end of life.
+- **Jazzy** — ROS 2 LTS release (2024), supported until 2029.
+- **Rolling** — ROS 2 rolling development distro, always tracking the latest sources.
+{/* AUTO-GENERATED-ROS2-TABLE:END */}
+
+#### ROS1
+
+{/* AUTO-GENERATED-ROS1-TABLE:START */}
+| ROS1 | Indigo | Jade | Kinetic | Melodic |
+|---|---|---|---|---|
+| [2F / Hand-E](drivers/2F%20hande) | [](drivers/2F%20hande/ROS/ROS1) | [](drivers/2F%20hande/ROS/ROS1) | [](drivers/2F%20hande/ROS/ROS1) | [](drivers/2F%20hande/ROS/ROS1) |
+
+- **Indigo** — ROS 1 release (2014), end of life.
+- **Jade** — ROS 1 release (2015), end of life.
+- **Kinetic** — ROS 1 release (2016), end of life.
+- **Melodic** — ROS 1 release (2018), end of life.
+{/* AUTO-GENERATED-ROS1-TABLE:END */}
+
+### Physics engine
+
+{/* AUTO-GENERATED-PHYSICS_ENGINE-TABLE:START */}
+| Product | Isaac Sim | PyBullet |
+|---|---|---|
+| [2F / Hand-E](drivers/2F%20hande) | [](drivers/2F%20hande/Physics%20Engine/Isaac%20Sim) | [](drivers/2F%20hande/Physics%20Engine/PyBullet) |
+| [TSF-85](drivers/TSF-85) | [](drivers/TSF-85/Physics%20Engine/Isaac%20Sim) | - |
+
+- **Isaac Sim** — NVIDIA Isaac Sim integration for simulating the hardware.
+- **PyBullet** — PyBullet integration for physics-based simulation.
+{/* AUTO-GENERATED-PHYSICS_ENGINE-TABLE:END */}
+
+### Other community projects
+
+{/* AUTO-GENERATED-OTHER-TABLE:START */}
+| Product | GraspGen |
+|---|---|
+| [2F / Hand-E](drivers/2F%20hande) | [](drivers/2F%20hande/GraspGen) |
+
+- **GraspGen** — NVIDIA GraspGen asset/model package with Robotiq gripper definitions for grasp synthesis research.
+{/* AUTO-GENERATED-OTHER-TABLE:END */}
\ No newline at end of file
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 1345c5a..12005c5 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -31,6 +31,7 @@ const config = {
projectName: 'robotiq.github.io', // Usually your repo name.
onBrokenLinks: 'throw',
+ onBrokenAnchors: 'throw',
// Even if you don't use internationalization, you can use this field to set
// useful metadata like html lang. For example, if your site is Chinese, you
@@ -82,14 +83,15 @@ theme: {
type: 'docSidebar',
sidebarId: 'driverSidebar',
position: 'left',
- label: 'Drivers',
- },
- {
- type: 'docSidebar',
- sidebarId: 'examplesSidebar',
- position: 'left',
- label: 'Examples',
+ label: 'Docs',
},
+ // Examples navbar item — uncomment when content is ready
+ // {
+ // type: 'docSidebar',
+ // sidebarId: 'examplesSidebar',
+ // position: 'left',
+ // label: 'Examples',
+ // },
{
href: 'https://github.com/robotiq',
label: 'GitHub',
@@ -105,11 +107,11 @@ theme: {
items: [
{
label: 'Drivers',
- to: '/docs/drivers',
+ to: '/docs/intro',
},
{
- label: 'Examples',
- to: '/docs/examples',
+ label: 'Contribute',
+ to: '/docs/contribute',
},
],
},
diff --git a/docs/examples.mdx b/draft/examples.mdx
similarity index 100%
rename from docs/examples.mdx
rename to draft/examples.mdx
diff --git a/docs/hardware.mdx b/draft/hardware.mdx
similarity index 97%
rename from docs/hardware.mdx
rename to draft/hardware.mdx
index af07b04..91abacc 100644
--- a/docs/hardware.mdx
+++ b/draft/hardware.mdx
@@ -32,9 +32,9 @@ The FT300-S is a compact force/torque sensor mounted between the robot flange an
alt="FT300-S — six-axis force and torque measurement"
style={{maxHeight: '220px', objectFit: 'contain'}}
/>
-
+
The FT300-S measures forces (Fx, Fy, Fz) and torques (Tx, Ty, Tz) on all six axes.
-
+
**Typical applications:**
diff --git a/external/tactile_sensors b/external/tactile_sensors
new file mode 160000
index 0000000..51948f3
--- /dev/null
+++ b/external/tactile_sensors
@@ -0,0 +1 @@
+Subproject commit 51948f3102b4eb660ce1f941ef2de792f85f4837
diff --git a/package-lock.json b/package-lock.json
index 36aed42..6bc892f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,7 +19,8 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.10.1",
- "@docusaurus/types": "3.10.1"
+ "@docusaurus/types": "3.10.1",
+ "gray-matter": "^4.0.3"
},
"engines": {
"node": ">=20.0"
diff --git a/package.json b/package.json
index df59d9b..10db045 100644
--- a/package.json
+++ b/package.json
@@ -4,10 +4,13 @@
"private": true,
"scripts": {
"docusaurus": "docusaurus",
+ "generate": "node scripts/sync-external-docs.js && node scripts/generate-tools-table.js",
+ "prestart": "npm run generate",
"start": "docusaurus start",
+ "prebuild": "npm run generate",
"build": "docusaurus build",
+ "test": "node scripts/check-build.js",
"swizzle": "docusaurus swizzle",
- "deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
@@ -25,7 +28,8 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.10.1",
- "@docusaurus/types": "3.10.1"
+ "@docusaurus/types": "3.10.1",
+ "gray-matter": "^4.0.3"
},
"browserslist": {
"production": [
diff --git a/preview.sh b/preview.sh
new file mode 100755
index 0000000..16acc34
--- /dev/null
+++ b/preview.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+# Locally visualize the documentation website.
+# Usage: ./preview.sh [port] (default port: 3000)
+set -euo pipefail
+
+cd "$(dirname "$0")"
+PORT="${1:-3000}"
+
+# 1. Make sure submodules (external repo docs) are present.
+echo "==> Syncing git submodules..."
+git submodule update --init --recursive
+
+# 2. Install dependencies only if needed.
+if [ ! -d node_modules ]; then
+ echo "==> Installing npm dependencies..."
+ npm install
+fi
+
+# 3. Start the dev server (prestart syncs external docs + regenerates the tools table).
+echo "==> Starting Docusaurus at http://localhost:${PORT}/ (Ctrl+C to stop)"
+npm run start -- --port "${PORT}"
diff --git a/scripts/check-build.js b/scripts/check-build.js
new file mode 100644
index 0000000..a407f90
--- /dev/null
+++ b/scripts/check-build.js
@@ -0,0 +1,63 @@
+// Basic "the docs are not broken" smoke test, run against the production
+// build produced by `npm run build`.
+//
+// Docusaurus already fails the build on broken internal links / anchors
+// (onBrokenLinks: 'throw' in docusaurus.config.js), so a successful build is
+// most of the guarantee. This script adds a few cheap sanity checks on top:
+// 1. the build actually happened,
+// 2. the key pages were emitted, and
+// 3. the auto-generated tools table was injected into the intro page
+// (catches a silently-broken generate-tools-table.js).
+//
+// Usage: npm run build && npm test
+
+const fs = require('fs');
+const path = require('path');
+
+const ROOT = path.resolve(__dirname, '..');
+const BUILD_DIR = path.join(ROOT, 'build');
+
+// Stable routes that should always be generated. Kept deliberately short so
+// the test doesn't turn into a mirror of the sidebar — it's a smoke test.
+const REQUIRED_PAGES = [
+ 'index.html',
+ '404.html',
+ 'docs/intro/index.html',
+ 'docs/contribute/index.html',
+ 'docs/drivers/TSF-85/index.html',
+];
+
+const errors = [];
+
+if (!fs.existsSync(BUILD_DIR)) {
+ console.error('[check-build] No build/ directory found. Run `npm run build` first.');
+ process.exit(1);
+}
+
+for (const page of REQUIRED_PAGES) {
+ if (!fs.existsSync(path.join(BUILD_DIR, page))) {
+ errors.push(`missing expected page: ${page}`);
+ }
+}
+
+// The intro page must contain the generated tools table (a rendered
+// with at least one shields.io support badge). If the generator no-ops or
+// breaks, the section renders empty and this catches it.
+const introPath = path.join(BUILD_DIR, 'docs/intro/index.html');
+if (fs.existsSync(introPath)) {
+ const intro = fs.readFileSync(introPath, 'utf8');
+ if (!intro.includes('');
+ }
+ if (!intro.includes('img.shields.io/badge')) {
+ errors.push('docs/intro tools table has no support badges (generator likely no-op)');
+ }
+}
+
+if (errors.length) {
+ console.error('[check-build] FAILED:');
+ for (const e of errors) console.error(' - ' + e);
+ process.exit(1);
+}
+
+console.log(`[check-build] OK — ${REQUIRED_PAGES.length} pages present, tools table generated.`);
diff --git a/scripts/generate-tools-table.js b/scripts/generate-tools-table.js
new file mode 100644
index 0000000..17ecbe5
--- /dev/null
+++ b/scripts/generate-tools-table.js
@@ -0,0 +1,346 @@
+// Regenerates the software-tools tables by scanning docs/drivers/:
+// - one table per category (SDK, Physics Engine, Other) in docs/intro.mdx
+// and on each product's own index.mdx, all products x tools in that category
+// - one distro-compatibility table per ROS generation (ROS2, ROS1) in
+// docs/intro.mdx and on each product's own index.mdx, all products x distros
+//
+// Each product (hardware) is a folder under docs/drivers/ with its own
+// index.mdx (frontmatter title = row label). Underneath, tool pages are
+// found by walking the folder tree until an index.mdx with a
+// `Category-` shields.io badge is found — that page is a leaf ("tool")
+// classified into that category, regardless of how deep it's nested (e.g.
+// docs/drivers//SDK/Python/index.mdx or docs/drivers//ROS/ROS2/index.mdx).
+// Plain folders in between (SDK/, ROS/, Physics Engine/) are just containers.
+//
+// Non-ROS tool pages carry a single `Supported_by--` badge,
+// shown compactly as the table cell.
+//
+// ROS tool pages (Category-ROS1 / Category-ROS2) instead carry one or more
+// `Distro-` badges, each immediately followed by its own
+// `Supported_by--` badge — one pair per ROS distro that page
+// supports. Those pairs become the columns of the ROS compatibility table.
+//
+// Add a new hardware folder, tool page, or distro badge under docs/drivers/
+// and every table picks it up automatically on the next `npm start` / `npm run build`.
+
+const fs = require('fs');
+const path = require('path');
+const matter = require('gray-matter');
+
+const ROOT = path.resolve(__dirname, '..');
+const DRIVERS_DIR = path.join(ROOT, 'docs', 'drivers');
+const INTRO_FILE = path.join(ROOT, 'docs', 'intro.mdx');
+
+// Non-ROS categories: rendered as a plain "product x tool" table.
+const CATEGORIES = ['SDK', 'Physics_Engine', 'Other'];
+const CATEGORY_DISPLAY = {
+ SDK: 'SDK',
+ Physics_Engine: 'Physics Engine',
+ Other: 'Other',
+};
+const NO_PRODUCTS_MESSAGE = {
+ SDK: '_No SDK drivers documented yet._',
+ Physics_Engine: '_No physics engine integrations documented yet._',
+ Other: '_No other community integrations documented yet._',
+};
+
+// ROS categories: rendered as a "product x distro" compatibility table.
+const ROS_CATEGORIES = ['ROS2', 'ROS1'];
+const NO_ROS_MESSAGE = {
+ ROS2: '_No products currently support ROS 2._',
+ ROS1: '_No products currently support ROS 1._',
+};
+
+// Preferred left-to-right column/distro order. Anything not listed here
+// still appears automatically — it's just sorted alphabetically after these.
+const COLUMN_ORDER = {
+ SDK: ['C', 'C++', 'Python'],
+ Physics_Engine: ['Isaac Sim', 'PyBullet'],
+ Other: [],
+};
+const DISTRO_ORDER = {
+ ROS2: ['Foxy', 'Galactic', 'Humble', 'Iron', 'Jazzy', 'Rolling'],
+ ROS1: ['Indigo', 'Jade', 'Kinetic', 'Melodic', 'Noetic'],
+};
+
+// One-line description shown in the legend below each ROS compatibility
+// table. A distro missing here still gets its own column — it just has no
+// legend entry until one is added.
+const DISTRO_DESCRIPTIONS = {
+ 'Foxy': 'ROS 2 LTS release (2020), end of life.',
+ 'Galactic': 'ROS 2 release (2021), end of life.',
+ 'Humble': 'ROS 2 LTS release (2022), supported until 2027.',
+ 'Iron': 'ROS 2 release (2023), end of life.',
+ 'Jazzy': 'ROS 2 LTS release (2024), supported until 2029.',
+ 'Rolling': 'ROS 2 rolling development distro, always tracking the latest sources.',
+ 'Indigo': 'ROS 1 release (2014), end of life.',
+ 'Jade': 'ROS 1 release (2015), end of life.',
+ 'Kinetic': 'ROS 1 release (2016), end of life.',
+ 'Melodic': 'ROS 1 release (2018), end of life.',
+ 'Noetic': 'Final ROS 1 release (2020), end of life May 2025.',
+};
+
+// One-line description shown in the legend below each category table. A
+// column missing here still appears — it just has no legend entry.
+const COLUMN_DESCRIPTIONS = {
+ 'C': 'Low-level C driver talking directly to the hardware\'s communication protocol (e.g. Modbus RTU, serial).',
+ 'C++': 'Low-level C++ driver/SDK for direct hardware integration.',
+ 'Python': 'Python driver/SDK for scripting and rapid prototyping.',
+ 'Isaac Sim': 'NVIDIA Isaac Sim integration for simulating the hardware.',
+ 'PyBullet': 'PyBullet integration for physics-based simulation.',
+ 'GraspGen': 'NVIDIA GraspGen asset/model package with Robotiq gripper definitions for grasp synthesis research.',
+};
+
+const START_MARKER = (key) => `{/* AUTO-GENERATED-${key}-TABLE:START */}`;
+const END_MARKER = (key) => `{/* AUTO-GENERATED-${key}-TABLE:END */}`;
+
+// Frontmatter is parsed with gray-matter (already a transitive dependency of
+// Docusaurus, declared directly here) rather than a hand-rolled regex, so
+// quoted values and colons inside a title (e.g. `title: "Foo: bar"`) parse
+// correctly instead of producing a wrong column key.
+function readFrontmatterTitle(raw) {
+ const { data } = matter(raw);
+ return typeof data.title === 'string' ? data.title.trim() : null;
+}
+
+function readCategory(raw) {
+ const m = raw.match(/badge\/Category-([A-Za-z0-9_]+)-[A-Za-z0-9]+\)/);
+ return m ? m[1] : null;
+}
+
+// Reads the page's own "Supported by " badge and returns a compact
+// version for the table — same label/color, without the "Supported by"
+// prefix — so the table stays dense. The source page's badge is untouched.
+function readCompactBadge(raw) {
+ const badge = raw.match(/badge\/Supported_by-([A-Za-z0-9_]+)-([A-Za-z0-9]+)/);
+ if (!badge) return null;
+ const [, label, color] = badge;
+ const displayLabel = label.replace(/_/g, ' ');
+ return ``;
+}
+
+// Reads each Distro badge paired with the Supported_by badge immediately
+// following it — one pair per ROS distro the page supports.
+function readDistroSupportPairs(raw) {
+ const pairs = [];
+ const re = /badge\/Distro-([A-Za-z0-9_]+)-[A-Za-z0-9]+\)[\s\S]*?badge\/Supported_by-([A-Za-z0-9_]+)-([A-Za-z0-9]+)\)/g;
+ let m;
+ while ((m = re.exec(raw))) {
+ const [, distro, label, color] = m;
+ const displayLabel = label.replace(/_/g, ' ');
+ pairs.push({
+ distro: distro.replace(/_/g, ' '),
+ badge: ``,
+ });
+ }
+ return pairs;
+}
+
+function docHref(...segments) {
+ // Escape characters that would break Markdown link syntax or be misread as
+ // a URL fragment/query (space, #, ?, %) — everything else (e.g. the "+" in
+ // "C++") must stay literal to match the page's actual URL.
+ return segments.map((s) => s.replace(/[ #?%]/g, (c) => encodeURIComponent(c))).join('/');
+}
+
+function isDirectory(p) {
+ return fs.statSync(p).isDirectory();
+}
+
+// Walks a hardware folder looking for tool leaf pages: an index.mdx carrying
+// a Category badge. Recurses through plain container folders (SDK/, ROS/,
+// Physics Engine/, ...) that have no such index.mdx of their own.
+function collectToolPages(dir, hardwareDir) {
+ const found = [];
+ for (const name of fs.readdirSync(dir).sort()) {
+ const full = path.join(dir, name);
+ if (!isDirectory(full)) continue;
+
+ const indexPath = path.join(full, 'index.mdx');
+ if (fs.existsSync(indexPath)) {
+ const raw = fs.readFileSync(indexPath, 'utf8');
+ const category = readCategory(raw);
+ if (category) {
+ found.push({
+ indexPath,
+ raw,
+ category,
+ relSegments: path.relative(hardwareDir, full).split(path.sep),
+ title: readFrontmatterTitle(raw) || name,
+ });
+ continue;
+ }
+ }
+ found.push(...collectToolPages(full, hardwareDir));
+ }
+ return found;
+}
+
+// product: { title, href, indexPath, tools: { SDK: { toolTitle -> {href, localHref, badge} }, ... },
+// ros: { ROS2: {href, localHref, pairs: [{distro, badge}]}, ... } }
+const products = [];
+const categoryColumns = { SDK: new Set(), Physics_Engine: new Set(), Other: new Set() };
+const rosDistros = { ROS2: new Set(), ROS1: new Set() };
+
+for (const hardwareName of fs.readdirSync(DRIVERS_DIR).sort()) {
+ const hardwareDir = path.join(DRIVERS_DIR, hardwareName);
+ if (!isDirectory(hardwareDir)) continue;
+
+ const hardwareIndex = path.join(hardwareDir, 'index.mdx');
+ if (!fs.existsSync(hardwareIndex)) continue;
+
+ const product = {
+ title: readFrontmatterTitle(fs.readFileSync(hardwareIndex, 'utf8')) || hardwareName,
+ href: docHref('drivers', hardwareName),
+ indexPath: hardwareIndex,
+ tools: { SDK: {}, Physics_Engine: {}, Other: {} },
+ ros: {},
+ };
+
+ for (const tool of collectToolPages(hardwareDir, hardwareDir)) {
+ const href = docHref('drivers', hardwareName, ...tool.relSegments);
+ const localHref = docHref(...tool.relSegments);
+
+ if (tool.category === 'ROS1' || tool.category === 'ROS2') {
+ const pairs = readDistroSupportPairs(tool.raw);
+ product.ros[tool.category] = { href, localHref, pairs };
+ pairs.forEach((p) => rosDistros[tool.category].add(p.distro));
+ continue;
+ }
+
+ if (!CATEGORIES.includes(tool.category)) continue; // unknown category badge — ignore
+ categoryColumns[tool.category].add(tool.title);
+ product.tools[tool.category][tool.title] = {
+ href,
+ localHref,
+ badge: readCompactBadge(tool.raw),
+ };
+ }
+
+ products.push(product);
+}
+
+function byOrder(order) {
+ return (a, b) => {
+ const ra = order.indexOf(a);
+ const rb = order.indexOf(b);
+ if (ra === -1 && rb === -1) return a.localeCompare(b);
+ if (ra === -1) return 1;
+ if (rb === -1) return -1;
+ return ra - rb;
+ };
+}
+
+function buildCategoryTable(catKey, productList, { local } = {}) {
+ const columns = [...categoryColumns[catKey]].sort(byOrder(COLUMN_ORDER[catKey] || []));
+ const relevant = productList.filter((p) => Object.keys(p.tools[catKey]).length > 0);
+ if (!columns.length || !relevant.length) return null;
+
+ const header = `| Product | ${columns.join(' | ')} |`;
+ const separator = `|${'---|'.repeat(columns.length + 1)}`;
+ const rows = relevant.map((p) => {
+ const cells = columns.map((col) => {
+ const tool = p.tools[catKey][col];
+ if (!tool) return '-';
+ const href = local ? tool.localHref : tool.href;
+ return tool.badge ? `[${tool.badge}](${href})` : `[${col}](${href})`;
+ });
+ const productCell = local ? p.title : `[${p.title}](${p.href})`;
+ return `| ${productCell} | ${cells.join(' | ')} |`;
+ });
+
+ return [header, separator, ...rows].join('\n');
+}
+
+function buildRosTable(rosKey, productList, { local } = {}) {
+ const distros = [...rosDistros[rosKey]].sort(byOrder(DISTRO_ORDER[rosKey] || []));
+ const relevant = productList.filter((p) => p.ros[rosKey]);
+ if (!distros.length || !relevant.length) return null;
+
+ const header = `| ${rosKey} | ${distros.join(' | ')} |`;
+ const separator = `|${'---|'.repeat(distros.length + 1)}`;
+ const rows = relevant.map((p) => {
+ const entry = p.ros[rosKey];
+ const href = local ? entry.localHref : entry.href;
+ const cells = distros.map((distro) => {
+ const pair = entry.pairs.find((pp) => pp.distro === distro);
+ return pair ? `[${pair.badge}](${href})` : '-';
+ });
+ const productCell = local ? p.title : `[${p.title}](${p.href})`;
+ return `| ${productCell} | ${cells.join(' | ')} |`;
+ });
+
+ return [header, separator, ...rows].join('\n');
+}
+
+function legendFor(catKey) {
+ return [...categoryColumns[catKey]]
+ .sort(byOrder(COLUMN_ORDER[catKey] || []))
+ .filter((col) => COLUMN_DESCRIPTIONS[col])
+ .map((col) => `- **${col}** — ${COLUMN_DESCRIPTIONS[col]}`)
+ .join('\n');
+}
+
+function legendForRos(rosKey) {
+ return [...rosDistros[rosKey]]
+ .sort(byOrder(DISTRO_ORDER[rosKey] || []))
+ .filter((distro) => DISTRO_DESCRIPTIONS[distro])
+ .map((distro) => `- **${distro}** — ${DISTRO_DESCRIPTIONS[distro]}`)
+ .join('\n');
+}
+
+function escapeRegExp(str) {
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+function writeBetweenMarkers(filePath, key, content) {
+ const startMarker = START_MARKER(key);
+ const endMarker = END_MARKER(key);
+ const raw = fs.readFileSync(filePath, 'utf8');
+ const markerRegex = new RegExp(`${escapeRegExp(startMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`);
+
+ if (!markerRegex.test(raw)) {
+ throw new Error(
+ `[generate-tools-table] Markers not found in ${path.relative(ROOT, filePath)}. Add ${startMarker} and ${endMarker} where the table should be inserted.`
+ );
+ }
+
+ const block = `${startMarker}\n${content}\n${endMarker}`;
+ fs.writeFileSync(filePath, raw.replace(markerRegex, block), 'utf8');
+}
+
+// --- docs/intro.mdx: one table per category, across all products ---
+
+for (const catKey of CATEGORIES) {
+ const table = buildCategoryTable(catKey, products, { local: false });
+ const legend = table ? legendFor(catKey) : '';
+ const content = table ? [table, legend].filter(Boolean).join('\n\n') : NO_PRODUCTS_MESSAGE[catKey];
+ writeBetweenMarkers(INTRO_FILE, catKey.toUpperCase(), content);
+}
+
+for (const rosKey of ROS_CATEGORIES) {
+ const table = buildRosTable(rosKey, products, { local: false });
+ const legend = table ? legendForRos(rosKey) : '';
+ const content = table ? [table, legend].filter(Boolean).join('\n\n') : NO_ROS_MESSAGE[rosKey];
+ writeBetweenMarkers(INTRO_FILE, rosKey, content);
+}
+
+console.log(`[generate-tools-table] Wrote ${CATEGORIES.length + ROS_CATEGORIES.length} category tables to docs/intro.mdx`);
+
+// --- each product's own index.mdx: same tables, scoped to that one product ---
+
+for (const product of products) {
+ for (const catKey of CATEGORIES) {
+ const table = buildCategoryTable(catKey, [product], { local: true });
+ const legend = table ? legendFor(catKey) : '';
+ const content = table ? [table, legend].filter(Boolean).join('\n\n') : NO_PRODUCTS_MESSAGE[catKey];
+ writeBetweenMarkers(product.indexPath, `PRODUCT-${catKey.toUpperCase()}`, content);
+ }
+ for (const rosKey of ROS_CATEGORIES) {
+ const table = buildRosTable(rosKey, [product], { local: true });
+ const legend = table ? legendForRos(rosKey) : '';
+ const content = table ? [table, legend].filter(Boolean).join('\n\n') : NO_ROS_MESSAGE[rosKey];
+ writeBetweenMarkers(product.indexPath, `PRODUCT-${rosKey}`, content);
+ }
+ console.log(`[generate-tools-table] Wrote category tables to ${path.relative(ROOT, product.indexPath)}`);
+}
diff --git a/scripts/sync-external-docs.js b/scripts/sync-external-docs.js
new file mode 100644
index 0000000..bd18ca0
--- /dev/null
+++ b/scripts/sync-external-docs.js
@@ -0,0 +1,167 @@
+// Copies content from git submodules into the Docusaurus docs tree.
+// Supports single files and full folders. Add new repos to JOBS below.
+//
+// Single-file job: all relative links become absolute GitHub URLs.
+// Folder job: links within the copied folder stay relative;
+// links escaping the folder become absolute GitHub URLs.
+
+const fs = require('fs');
+const path = require('path');
+const { execSync } = require('child_process');
+
+const ROOT = path.resolve(__dirname, '..');
+
+// Reset all submodules to the committed state before syncing,
+// so local edits inside external/ never silently affect the build.
+try {
+ execSync('git submodule update --init --force', { cwd: ROOT, stdio: 'inherit' });
+} catch {
+ console.warn('[sync-external-docs] git submodule update failed — continuing with current state');
+}
+
+// ── Add new repos here ─────────────────────────────────────────────────────
+const JOBS = [
+ // TSF 85 CPP driver README
+ {
+ submodule: 'tactile_sensors',
+ repoUrl: 'https://github.com/robotiq/tactile_sensors',
+ branch: 'main',
+ from: 'sdk_cpp/README.md',
+ to: 'drivers/TSF-85/SDK/C++/_readme.md',
+ },
+ // TSF 85 Python driver README
+ {
+ submodule: 'tactile_sensors',
+ repoUrl: 'https://github.com/robotiq/tactile_sensors',
+ branch: 'main',
+ from: 'sensor_quickstart/README.md',
+ to: 'drivers/TSF-85/SDK/Python/_readme.md',
+ },
+ // Folder example — uncomment when a repo has a docs/ folder:
+ // {
+ // submodule: 'tactile_sensors',
+ // repoUrl: 'https://github.com/Robotiq/tactile_sensors',
+ // branch: 'main',
+ // from: 'docs',
+ // to: 'drivers/tsf-85',
+ // },
+];
+// ───────────────────────────────────────────────────────────────────────────
+
+const MARKDOWN_EXTS = new Set(['.md', '.mdx']);
+const COPY_EXTS = new Set(['.md', '.mdx', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.pdf']);
+
+function isAbsoluteHref(href) {
+ return /^(https?:\/\/|mailto:|#|\/)/.test(href);
+}
+
+// Rewrites markdown links in `content`.
+// srcFile / destFile : absolute paths of the file being processed
+// copiedRoot : if non-null, the source folder being synced as a whole.
+// Links that resolve inside it are re-expressed as relative paths
+// from the destination file. Pass null for single-file syncs.
+// destCopiedRoot : destination counterpart of copiedRoot (null for single-file)
+// submoduleRoot : absolute path to the submodule root
+// repoUrl / branch : used to build absolute GitHub URLs
+function rewriteLinks(content, { srcFile, destFile, copiedRoot, destCopiedRoot, submoduleRoot, repoUrl, branch }) {
+ const srcDir = path.dirname(srcFile);
+ const destDir = path.dirname(destFile);
+
+ // Strip content wrapped in ... .
+ // Lets a submodule README carry a "full docs at " blurb that renders on GitHub
+ // but never makes it into the synced docs page.
+ content = content.replace(/[\s\S]*?\n?/g, '');
+
+ // Strip the leading H1 — the wrapper .mdx supplies the page title via
+ // sidebar_label frontmatter. Uses 'm' (without 'g') so it finds the first
+ // "# " line anywhere near the top and removes only that one match, even
+ // when the README opens with a badge or blank line before its title.
+ content = content.replace(/^# .*\n+/m, '');
+
+ // Convert autolinks to [url](url) — MDX treats angle-bracket URLs as JSX and fails.
+ content = content.replace(/<(https?:\/\/[^>\s]+)>/g, '[$1]($1)');
+
+ return content.replace(/(!?)\[([^\]]*)\]\(([^)\n]+)\)/g, (match, bang, text, href) => {
+ const hashIdx = href.indexOf('#');
+ const hrefPath = hashIdx >= 0 ? href.slice(0, hashIdx) : href;
+ const anchor = hashIdx >= 0 ? href.slice(hashIdx) : '';
+
+ if (!hrefPath.trim() || isAbsoluteHref(hrefPath)) return match;
+
+ const absTarget = path.resolve(srcDir, hrefPath);
+
+ if (copiedRoot) {
+ const relToRoot = path.relative(copiedRoot, absTarget);
+ if (!relToRoot.startsWith('..')) {
+ // Target is inside the copied folder — rewrite as a relative path from dest
+ const absDestTarget = path.join(destCopiedRoot, relToRoot);
+ const newRel = path.relative(destDir, absDestTarget).replace(/\\/g, '/');
+ return `${bang}[${text}](${newRel}${anchor})`;
+ }
+ }
+
+ // Target escapes the copied content — make it an absolute GitHub URL.
+ // Image embeds (`![...]`) need the raw file bytes to render as an ;
+ // a "blob" URL serves GitHub's HTML file-viewer page instead, which
+ // renders as a broken image. Plain links keep using blob/tree so
+ // clicking them opens GitHub's viewer.
+ const relToSubmodule = path.relative(submoduleRoot, absTarget).replace(/\\/g, '/');
+ if (bang) {
+ const rawBase = repoUrl.replace('https://github.com/', 'https://raw.githubusercontent.com/');
+ return `${bang}[${text}](${rawBase}/${branch}/${relToSubmodule}${anchor})`;
+ }
+ const hasExt = path.extname(relToSubmodule) !== '';
+ const ghBase = hasExt ? `${repoUrl}/blob/${branch}` : `${repoUrl}/tree/${branch}`;
+ return `[${text}](${ghBase}/${relToSubmodule}${anchor})`;
+ });
+}
+
+function processFile(srcFile, destFile, opts) {
+ fs.mkdirSync(path.dirname(destFile), { recursive: true });
+ if (MARKDOWN_EXTS.has(path.extname(srcFile).toLowerCase())) {
+ const raw = fs.readFileSync(srcFile, 'utf8');
+ fs.writeFileSync(destFile, rewriteLinks(raw, { srcFile, destFile, ...opts }), 'utf8');
+ } else {
+ fs.copyFileSync(srcFile, destFile);
+ }
+}
+
+function processFolder(srcDir, destDir, opts) {
+ for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
+ const srcChild = path.join(srcDir, entry.name);
+ const destChild = path.join(destDir, entry.name);
+ if (entry.isDirectory()) {
+ processFolder(srcChild, destChild, opts);
+ } else if (COPY_EXTS.has(path.extname(entry.name).toLowerCase())) {
+ processFile(srcChild, destChild, opts);
+ }
+ }
+}
+
+for (const job of JOBS) {
+ const submoduleRoot = path.join(ROOT, 'external', job.submodule);
+ const srcPath = path.join(submoduleRoot, job.from);
+ const destPath = path.join(ROOT, 'docs', job.to);
+
+ if (!fs.existsSync(srcPath)) {
+ console.warn(`[sync-external-docs] Missing: external/${job.submodule}/${job.from} — run: git submodule update --init`);
+ continue;
+ }
+
+ const isDir = fs.statSync(srcPath).isDirectory();
+ const opts = {
+ copiedRoot: isDir ? srcPath : null,
+ destCopiedRoot: isDir ? destPath : null,
+ submoduleRoot,
+ repoUrl: job.repoUrl,
+ branch: job.branch,
+ };
+
+ if (isDir) {
+ processFolder(srcPath, destPath, opts);
+ console.log(`[sync-external-docs] ${job.submodule}/${job.from}/ → docs/${job.to}/`);
+ } else {
+ processFile(srcPath, destPath, { ...opts, srcFile: srcPath, destFile: destPath });
+ console.log(`[sync-external-docs] ${job.submodule}/${job.from} → docs/${job.to}`);
+ }
+}
diff --git a/sidebars.js b/sidebars.js
index aee4398..32a594b 100644
--- a/sidebars.js
+++ b/sidebars.js
@@ -15,8 +15,98 @@
@type {import('@docusaurus/plugin-content-docs').SidebarsConfig}
*/
const sidebars = {
- driverSidebar: ['drivers'],
- examplesSidebar: ['examples'],
+ driverSidebar: [
+ 'intro',
+ {
+ type: 'category',
+ label: '2F / Hand-E',
+ link: { type: 'doc', id: 'drivers/2F hande/index' },
+ items: [
+ {
+ type: 'category',
+ label: 'SDK',
+ items: [
+ 'drivers/2F hande/SDK/C++/index',
+ 'drivers/2F hande/SDK/Python/index',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'ROS',
+ items: [
+ 'drivers/2F hande/ROS/ROS2/index',
+ 'drivers/2F hande/ROS/ROS1/index',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Physics Engine',
+ items: [
+ 'drivers/2F hande/Physics Engine/Isaac Sim/index',
+ 'drivers/2F hande/Physics Engine/PyBullet/index',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Other',
+ items: [
+ 'drivers/2F hande/GraspGen/index',
+ ],
+ },
+ ],
+ },
+ {
+ type: 'category',
+ label: 'TSF-85',
+ link: { type: 'doc', id: 'drivers/TSF-85/index' },
+ items: [
+ {
+ type: 'category',
+ label: 'SDK',
+ items: [
+ 'drivers/TSF-85/SDK/C++/index',
+ 'drivers/TSF-85/SDK/Python/index',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'ROS',
+ items: [
+ 'drivers/TSF-85/ROS/ROS2/index',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Physics Engine',
+ items: [
+ 'drivers/TSF-85/Physics Engine/Isaac Sim/index',
+ ],
+ },
+ ],
+ },
+ {
+ type: 'category',
+ label: 'FT300-S',
+ link: { type: 'doc', id: 'drivers/FT300/index' },
+ items: [
+ {
+ type: 'category',
+ label: 'SDK',
+ items: [
+ 'drivers/FT300/SDK/C/index',
+ 'drivers/FT300/SDK/Python/index',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'ROS',
+ items: [
+ 'drivers/FT300/ROS/ROS2/index',
+ ],
+ },
+ ],
+ },
+ ]
};
export default sidebars;
diff --git a/src/components/HomepageFeatures/styles.module.css b/src/components/HomepageFeatures/styles.module.css
index f729c89..181061d 100644
--- a/src/components/HomepageFeatures/styles.module.css
+++ b/src/components/HomepageFeatures/styles.module.css
@@ -13,16 +13,10 @@
border-radius: 0 0 8px 8px;
overflow: hidden;
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.07);
- transition: box-shadow 0.22s ease, transform 0.22s ease;
margin-bottom: 1.5rem;
height: 100%;
}
-.featureCard:hover {
- box-shadow: 0 8px 36px rgba(30, 166, 230, 0.22);
- transform: translateY(-4px);
-}
-
/* Image showcase area */
.imageArea {
display: grid;
@@ -42,21 +36,12 @@
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14), 0 2px 16px rgba(0, 0, 0, 0.4);
}
-[data-theme='dark'] .featureCard:hover {
- box-shadow: 0 0 0 1px rgba(30, 166, 230, 0.5), 0 8px 36px rgba(30, 166, 230, 0.18);
-}
-
/* Product images (grippers, sensors) */
.productImg {
width: 100%;
max-height: 120px;
object-fit: contain;
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.10));
- transition: transform 0.22s ease;
-}
-
-.featureCard:hover .productImg {
- transform: scale(1.06);
}
/* Tech logos (C++, Python, ROS2) */
@@ -64,11 +49,6 @@
width: 100%;
max-height: 54px;
object-fit: contain;
- transition: transform 0.22s ease;
-}
-
-.featureCard:hover .logoImg {
- transform: scale(1.07);
}
/* Card text body */
diff --git a/src/css/custom.css b/src/css/custom.css
index 2d91951..9e7b704 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -136,3 +136,13 @@ table thead tr {
--ifm-alert-background-color: rgba(30, 166, 230, 0.08);
--ifm-alert-border-color: var(--robotiq-blue);
}
+
+/* ── Logo chips: third-party logos are often dark-on-transparent and
+ disappear against the dark theme background, so give them a light
+ backing in dark mode only. ── */
+[data-theme='dark'] .logo-chip {
+ background-color: #ffffff;
+ border-radius: 8px;
+ padding: 0.25rem 0.5rem;
+ display: inline-flex;
+}
diff --git a/src/pages/index.js b/src/pages/index.js
index 5200982..f31c1a4 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -18,7 +18,7 @@ function HomepageHeader() {
+ to="/docs/intro">
Get Started
diff --git a/static/img/Ros_logo.svg.png b/static/img/Ros_logo.svg.png
deleted file mode 100644
index b94e2c1..0000000
Binary files a/static/img/Ros_logo.svg.png and /dev/null differ
diff --git a/static/img/images.jpg b/static/img/graspgen.jpg
similarity index 100%
rename from static/img/images.jpg
rename to static/img/graspgen.jpg
diff --git a/static/img/ros1.png b/static/img/ros1.png
new file mode 100644
index 0000000..0e99936
Binary files /dev/null and b/static/img/ros1.png differ
diff --git a/static/img/ros2.webp b/static/img/ros2.webp
new file mode 100644
index 0000000..a3b7c3f
Binary files /dev/null and b/static/img/ros2.webp differ