From bf4cf1d94b7c9a40c92626f1daeef1a1e8a78b32 Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:07:08 +0200 Subject: [PATCH 1/9] Reapply "test linkcheck" This reverts commit 95cffd72df76c0cb09a92f61211ed2cf0039048e. --- .pre-commit-config.yaml | 14 ++++++++++++++ docs/underwater-gps/interface/ugps-led.md | 2 ++ mkdocs-linkcheck.yml | 4 ++++ 3 files changed, 20 insertions(+) create mode 100644 .pre-commit-config.yaml create mode 100644 mkdocs-linkcheck.yml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..ffe99242 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,14 @@ +repos: + - repo: local + hooks: + - id: test-echo + name: Test echo + entry: echo "Testing pre-commit hooks" + language: system + pass_filenames: false + + # - id: mkdocs-linkcheck + # name: Check mkdocs links + # entry: mkdocs build --config-file mkdocs-linkcheck.yml + # language: system + # pass_filenames: false \ No newline at end of file diff --git a/docs/underwater-gps/interface/ugps-led.md b/docs/underwater-gps/interface/ugps-led.md index 1747b3e6..87d4ef15 100644 --- a/docs/underwater-gps/interface/ugps-led.md +++ b/docs/underwater-gps/interface/ugps-led.md @@ -1,6 +1,8 @@ # LED Indicators Only the topside box and the Locator U1 has LED indicators. +Here is a broken [link](http://example.com/feil) + ## Topside |LED name | Description | diff --git a/mkdocs-linkcheck.yml b/mkdocs-linkcheck.yml new file mode 100644 index 00000000..31a23463 --- /dev/null +++ b/mkdocs-linkcheck.yml @@ -0,0 +1,4 @@ +site_name: Check links +plugins: + - linkcheck: + fail_on_warning: true From 6d013617fe483bd0986e284fab64ac856306d4a6 Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:07:12 +0200 Subject: [PATCH 2/9] Reapply "local linkcheck" This reverts commit ba09bd98c5325236106eb97179ad4f7c724d1863. --- .pre-commit-config.yaml | 14 -------------- hooks/pre-push | 13 +++++++++++++ install-hooks.sh | 4 ++++ mkdocs-linkcheck.yml | 4 ++-- mkdocs.yml | 3 +++ requirements.txt | 38 +++++++++++++++++++++++++++++++++++++- 6 files changed, 59 insertions(+), 17 deletions(-) delete mode 100644 .pre-commit-config.yaml create mode 100755 hooks/pre-push create mode 100755 install-hooks.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index ffe99242..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,14 +0,0 @@ -repos: - - repo: local - hooks: - - id: test-echo - name: Test echo - entry: echo "Testing pre-commit hooks" - language: system - pass_filenames: false - - # - id: mkdocs-linkcheck - # name: Check mkdocs links - # entry: mkdocs build --config-file mkdocs-linkcheck.yml - # language: system - # pass_filenames: false \ No newline at end of file diff --git a/hooks/pre-push b/hooks/pre-push new file mode 100755 index 00000000..c3d8cafd --- /dev/null +++ b/hooks/pre-push @@ -0,0 +1,13 @@ +#!/bin/bash +# Pre-push hook: run MkDocs linkcheck + +echo "Running MkDocs linkcheck..." +python -m mkdocs build --config-file mkdocs-linkcheck.yml + +if [ $? -ne 0 ]; then + echo "Linkcheck failed! Push aborted." + exit 1 +fi + +echo "Linkcheck passed. Proceeding with push." +exit 0 \ No newline at end of file diff --git a/install-hooks.sh b/install-hooks.sh new file mode 100755 index 00000000..194a88b3 --- /dev/null +++ b/install-hooks.sh @@ -0,0 +1,4 @@ +#!/bin/bash +mkdir -p .git/hooks +ln -sf ../../hooks/pre-push .git/hooks/pre-push +echo "Pre-push hook installed!" \ No newline at end of file diff --git a/mkdocs-linkcheck.yml b/mkdocs-linkcheck.yml index 31a23463..5ef0bfb7 100644 --- a/mkdocs-linkcheck.yml +++ b/mkdocs-linkcheck.yml @@ -1,4 +1,4 @@ -site_name: Check links +site_name: build linkcheck plugins: - linkcheck: - fail_on_warning: true + fail_on_warning: true \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index c9b4a423..b90aa740 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,6 +1,9 @@ site_name: Documentation site_url: "https://waterlinked.github.io" repo_url: https://github.com/waterlinked/waterlinked.github.io +plugins: + - linkcheck: + fail_on_warning: true theme: name: material theme_dir: docstheme/material diff --git a/requirements.txt b/requirements.txt index b5917eb5..845505f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,39 @@ +aiohappyeyeballs==2.6.1 +aiohttp==3.12.15 +aiosignal==1.4.0 +async-timeout==5.0.1 +attrs==25.3.0 +cfgv==3.4.0 +click==8.2.1 +distlib==0.4.0 +filelock==3.19.1 +frozenlist==1.7.0 +ghp-import==2.1.0 +identify==2.6.13 +idna==3.10 +importlib_metadata==8.7.0 +Jinja2==3.0.3 +Markdown==3.8 +MarkupSafe==3.0.2 +mergedeep==1.3.4 mkdocs==1.2.3 +mkdocs-linkcheck==1.0.6 mkdocs-material==7.2.0 -jinja2<3.1.0 +mkdocs-material-extensions==1.3.1 +multidict==6.6.4 +nodeenv==1.9.1 +packaging==25.0 +platformdirs==4.4.0 +pre_commit==4.3.0 +propcache==0.3.2 +Pygments==2.19.1 +pymdown-extensions==10.15 +python-dateutil==2.9.0.post0 +PyYAML==6.0.2 +pyyaml_env_tag==1.1 +six==1.17.0 +typing_extensions==4.15.0 +virtualenv==20.34.0 +watchdog==6.0.0 +yarl==1.20.1 +zipp==3.22.0 From 1dae3dd390586695a21431f18220b0f3745d4f90 Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:07:16 +0200 Subject: [PATCH 3/9] Reapply "Added automatic link-checking and fixed plenty of links" This reverts commit 797940fd8897c3419af6d0d7d83ee43a3ef328cc. --- README.md | 4 + checklinks.py | 99 ++++++++++++++++++ docs/dvl/axes.md | 2 +- docs/dvl/bluerov-integration.md | 2 +- docs/dvl/dead-reckoning.md | 8 +- docs/dvl/dvl-protocol.md | 6 +- docs/dvl/dvl-troubleshooting.md | 4 +- docs/dvl/gui/dashboard.md | 4 +- docs/dvl/interfaces.md | 2 +- docs/dvl/networking.md | 10 +- docs/dvl/sw-update.md | 6 +- docs/explorer-kit/gui/api.md | 2 +- docs/explorer-kit/gui/settings.md | 2 +- docs/explorer-kit/locators/locator-a1.md | 2 +- docs/explorer-kit/locators/locator-s1.md | 2 +- docs/explorer-kit/quickstart.md | 2 +- docs/explorer-kit/upgrader.md | 10 +- docs/img/ugps-img/ugps-imu-calibration.png | Bin 0 -> 66064 bytes docs/modem-m64/modem-m64-protocol.md | 2 +- docs/sonar-3d/sonar-3d-15-config.md | 6 +- docs/sonar-3d/sonar-3d-15-networking.md | 2 +- .../integration/bluerov-integration-a1.md | 4 +- .../integration/bluerov-integration-u1.md | 4 +- .../integration/bluerov-integration.md | 12 +-- .../integration/external-gps.md | 6 +- docs/underwater-gps/interface/ugps-led.md | 2 +- docs/underwater-gps/interface/warnings.md | 2 +- docs/underwater-gps/introduction.md | 6 +- docs/underwater-gps/quickstart.md | 12 +-- docs/underwater-gps/reference-frames.md | 2 +- docs/underwater-gps/sw-update.md | 6 +- docs/underwater-gps/ugps-sys-setup.md | 12 +-- docs/underwater-gps/ugps-sysconfig.md | 24 +++-- hooks/pre-push | 65 ++++++++++-- mkdocs-linkcheck.yml | 4 - mkdocs.yml | 9 +- 36 files changed, 251 insertions(+), 96 deletions(-) create mode 100644 checklinks.py create mode 100644 docs/img/ugps-img/ugps-imu-calibration.png delete mode 100644 mkdocs-linkcheck.yml diff --git a/README.md b/README.md index 7cea4ee8..cbce33ef 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ python -m venv venv source venv/bin/activate (Linux) venv\Scripts\activate.bat (Windows) pip install -r requirements.txt +./install-hooks.sh mkdocs serve ``` @@ -34,3 +35,6 @@ mkdocs serve ## Deploy changes to server After the changes have been tested and they work, push the changes to the master branch and Github will build the website and publish it on https://docs.waterlinked.com. +## Automatic link-checker +When you push to git, all links are automatically checked. Any errors will be listed in your terminal. If you want to check links before pushing, use > ./hooks/pre-push + diff --git a/checklinks.py b/checklinks.py new file mode 100644 index 00000000..2c8c57ae --- /dev/null +++ b/checklinks.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +import re +import sys +from pathlib import Path + +# Regex for Markdown links: [text](target) +LINK_RE = re.compile(r"\[([^\]]+)\]\(([^)]+)\)") + +def slugify_heading(text: str) -> str: + """Convert Markdown heading text to MkDocs anchor format.""" + slug = text.strip().lower() + slug = re.sub(r"[^\w\s-]", "", slug) # remove punctuation + slug = re.sub(r"\s+", "-", slug) # spaces -> dashes + return slug + + +def extract_headings(md_file: Path): + """Return a set of anchor slugs from headings in md files.""" + headings = set() + if not md_file.is_file(): + return headings + for line in md_file.read_text(encoding="utf-8").splitlines(): + if line.startswith("#"): + heading_text = line.lstrip("#").strip() + headings.add(slugify_heading(heading_text)) + return headings + +def check_md_file(md_file: Path): + """Check links in md files.""" + errors = [] + if not md_file.is_file(): # <-- add this check + return errors + + for line_number, line in enumerate(md_file.read_text(encoding="utf-8").splitlines(), start=1): + + stripped = line.strip() + # Skip HTML and python comments + if stripped.startswith("#"): + continue + elif stripped.startswith(""): + continue + + for match in LINK_RE.finditer(line): + text, target = match.groups() + + # Skip external links + if target.startswith(("http://", "https://", "mailto:")): + continue + + # Remove leading slash for site-root relative links + elif target.startswith("/"): + target = target[1:] + + # Split anchor from file + if "#" in target: + if target.startswith("#"): + file_part, anchor = md_file, target[1:] + else: + file_part, anchor = target.split("#", 1) + else: + file_part, anchor = target, None + + # Resolve relative path' + target_path = Path(file_part) if isinstance(file_part, Path) else Path(file_part) #Make sure it's a Path object + target_file = (md_file.parent / target_path).resolve() + + if not target_file.exists() and not target_file.suffix: + target_file = (md_file.parent / (target_path.name + ".md")).resolve() + if not target_file.exists(): + errors.append(f"{md_file}:{line_number}: File not found -> {target}") + continue + + if target_file.is_file() and anchor: + headings = extract_headings(target_file) + if anchor not in headings: + errors.append(f"{md_file}:{line_number}: Anchor not found -> {target}") + + if target_file.is_dir(): + continue + + return errors + + +def main(md_dir): + md_dir = Path(md_dir) + all_errors = [] + for md_file in md_dir.rglob("*.md"): + all_errors.extend(check_md_file(md_file)) + + if all_errors: + print(f'Found {len(all_errors)} internal link errors in md files:') + for e in all_errors: + print(e) + return 1 + print("No internal link errors found.") + return 0 + +if __name__ == "__main__": + exit(main(sys.argv[1])) diff --git a/docs/dvl/axes.md b/docs/dvl/axes.md index f801b934..97e3899c 100644 --- a/docs/dvl/axes.md +++ b/docs/dvl/axes.md @@ -52,7 +52,7 @@ By default, the body frame and vehicle frame is the same and align with the DVL' The DVL can be mounted at an angle to the forward direction of a vehicle to which it is attached. -To be precise, the clockwise angle θ in degrees around the Z axis (i.e. in the X-Y plane) from the forward axis of the vehicle to the forward axis of the DVL can be entered as a 'mounting rotation offset' in the [GUI](../gui/configuration), or via the TCP or serial [protocols](../dvl-protocol/). +To be precise, the clockwise angle θ in degrees around the Z axis (i.e. in the X-Y plane) from the forward axis of the vehicle to the forward axis of the DVL can be entered as a 'mounting rotation offset' in the [GUI](../dvl/gui/configuration.md), or via the TCP or serial [protocols](../dvl-protocol/). The DVL will then output data in the vehicle frame obtained by rotating the [DVL body frame](#body-frame) anti-clockwise around the Z-axis by θ degrees: the X-axis of the velocities outputted by the DVL will be aligned with the forward axis of the vehicle, and, at time zero, the X-axis of the DVL's [frame](../dead-reckoning#frame) for dead reckoning will be aligned with the forward axis of the vehicle. diff --git a/docs/dvl/bluerov-integration.md b/docs/dvl/bluerov-integration.md index 05f64d87..4db755b5 100644 --- a/docs/dvl/bluerov-integration.md +++ b/docs/dvl/bluerov-integration.md @@ -47,7 +47,7 @@ You will also need: * Utility knife * Wire stripping tool * Zip ties -* 4 x 30 cm (12") wires (options discussed under [Connect DVL-A50 and BlueROV2](#connect-dvl-a50-and-bluerov2)). If possible, use 2 x red and 2 x black wires. +* 4 x 30 cm (12") wires (options discussed under [Connect DVL-A50 and BlueROV2](#attach-dvl-a50-to-bluerov2)). If possible, use 2 x red and 2 x black wires. * 15 cm (6") ethernet cable ## Preparation diff --git a/docs/dvl/dead-reckoning.md b/docs/dvl/dead-reckoning.md index 67815afb..9cc69621 100644 --- a/docs/dvl/dead-reckoning.md +++ b/docs/dvl/dead-reckoning.md @@ -4,8 +4,8 @@ The DVL-A50 and DVL-A125 run a dead reckoning algorithm which estimates the orie ## Starting dead reckoning -1. Calibrate the gyroscope by pressing *More -> Calibrate gyro* in the [GUI](../gui/dashboard) whilst the DVL is stationary. -2. Click the 'Reset' button ![](../img/dvl_gui_icon_reset.png) in the [GUI](../gui/dashboard), or send a reset command over the TCP or serial [protocol](../dvl-protocol). +1. Calibrate the gyroscope by pressing *More -> Calibrate gyro* in the [GUI](../dvl/gui/dashboard.md) whilst the DVL is stationary. +2. Click the 'Reset' button ![](../img/dvl_gui_icon_reset.png) in the [GUI](../dvl/gui/dashboard.md), or send a reset command over the TCP or serial [protocol](../dvl-protocol). Failure to perform gyro calibration will result in less accurate dead reckoning. @@ -22,11 +22,11 @@ When the DVL fails in its determination of velocity, speed and position are pred !!! note When the DVL is powered on in the air, its position will drift significantly. This should be ignored, and dead reckoning should be [started](#starting-dead-reckoning) in water when ready. -The position of the DVL can be viewed in the GUI [dashboard](../gui/dashboard/) or be fetched by [API](../dvl-protocol/#dead-reckoning-report). +The position of the DVL can be viewed in the GUI [dashboard](../dvl/gui/dashboard.md) or be fetched by [API](../dvl-protocol/#dead-reckoning-report). ## Orientation -The calculation of the orientation of the DVL is based upon the accelerometer and gyroscope measurements of its IMU. The orientation is represented by roll, pitch, and yaw angles, and can be viewed in the GUI [dashboard](../gui/dashboard/) or be fetched by [API](../dvl-protocol/#dead-reckoning-report). +The calculation of the orientation of the DVL is based upon the accelerometer and gyroscope measurements of its IMU. The orientation is represented by roll, pitch, and yaw angles, and can be viewed in the GUI [dashboard](../dvl/gui/dashboard.md) or be fetched by [API](../dvl-protocol/#dead-reckoning-report). - Roll is a rotation around the X axis of the DVL - Pitch is a rotation around the Y axis of the DVL diff --git a/docs/dvl/dvl-protocol.md b/docs/dvl/dvl-protocol.md index 3b8713bf..2ff713ac 100644 --- a/docs/dvl/dvl-protocol.md +++ b/docs/dvl/dvl-protocol.md @@ -538,7 +538,7 @@ The new configuration will not be returned in the response, but can be obtained ### Velocity report, old format (wrx) [Deprecated] -Same purpose as the [velocity report](#velocity-report), but in an older format: +Same purpose as the [velocity report](#velocity-report-wrz), but in an older format: `wrx,`*[time],[vx],[vy],[vz],[fom],[altitude],[valid],[status]* @@ -571,7 +571,7 @@ wrx,1164.94,0.000,0.000,0.000,2.707,-1.00,n,1*39 ### Transducer report, old format (wrt) [Deprecated] -Same purpose as the [transducer report](#transducer-report), but in an older format, and combining the data of all four transducers: +Same purpose as the [transducer report](#transducer-report-wru), but in an older format, and combining the data of all four transducers: `wrt,`*[dist_1],[dist_2],[dist_3],[dist_4]* @@ -605,7 +605,7 @@ Checksum is formatted as a hexadecimal number using 2 lower-case characters (ex: Compatible implementations: * Python 3: [crcmod](https://pypi.org/project/crcmod/) `crcmod.predefined.mkPredefinedCrcFun("crc-8")` -* Golang: [github.com/sigurn/crc8](github.com/sigurn/crc8) `crc8.MakeTable(crc8.CRC8)` +* Golang: [github.com/sigurn/crc8](https://github.com/sigurn/crc8) `crc8.MakeTable(crc8.CRC8)` Example for how to verify checksum using Python 3 and [crcmod](https://pypi.org/project/crcmod/): diff --git a/docs/dvl/dvl-troubleshooting.md b/docs/dvl/dvl-troubleshooting.md index c66d1f0d..711f6589 100644 --- a/docs/dvl/dvl-troubleshooting.md +++ b/docs/dvl/dvl-troubleshooting.md @@ -6,7 +6,7 @@ Below is a small list to check if your DVL is not performing as expected or you In the Support Portal please describe the test environment or test setup you have used and how the DVL is mounted. If possible, open the DVL GUI and go to Diagnostic Log in the left menu. Press the Create Diagnostic Report button. This will automatically record a log file that you can download to your computer. Please add the [Diagnostic reports](gui/diagnostic-report.md) and pictures of the test setup in the support portal. This will help our support team greatly! -If the troubleshooting guide do not help, please check out [FAQ DVL](faq.md#faq-dvl)! +If the troubleshooting guide do not help, please check out [FAQ DVL](../dvl/faq.md)! ### Check if DVL is powered 1. Put the DVL under water and power it on with an adequate power supply. @@ -14,7 +14,7 @@ If the troubleshooting guide do not help, please check out [FAQ DVL](faq.md#faq- * Does the LED turn on? ### LED -1. For LED status, see [LED Signals](../interfaces#LED-Signals). +1. For LED status, see [LED Signals](../dvl/interfaces.md#led-signals). ### Wiring 1. Check that you have wired your DVL correctly, see [Wiring interface](../interfaces#wiring-interface). diff --git a/docs/dvl/gui/dashboard.md b/docs/dvl/gui/dashboard.md index 9a23f697..7c4b359d 100644 --- a/docs/dvl/gui/dashboard.md +++ b/docs/dvl/gui/dashboard.md @@ -1,8 +1,8 @@ # Dashboard -Both the DVL-A50 and the DVL-A125 have a web-based GUI. In your favorite web browser, simply navigate to the DVL's [IP address](../../networking). +Both the DVL-A50 and the DVL-A125 have a web-based GUI. In your favorite web browser, simply navigate to the DVL's [IP address](../networking.md). -The default page is a dashboard which provides a summary and visualisation of both the velocity and [dead reckoning](../../dead-reckoning) data outputted by the DVL, as well as an indication of current status. +The default page is a dashboard which provides a summary and visualisation of both the velocity and [dead reckoning](../dead-reckoning.md) data outputted by the DVL, as well as an indication of current status. ## Screenshot diff --git a/docs/dvl/interfaces.md b/docs/dvl/interfaces.md index 62a06840..8c88cac7 100644 --- a/docs/dvl/interfaces.md +++ b/docs/dvl/interfaces.md @@ -91,7 +91,7 @@ See the DVL's [serial protocol](../dvl-protocol#serial-protocol). ## Ethernet Interface -See [networking](../networking) and the DVL's [TCP protocol](../dvl-protocol#ethernet-protocol-tcp). +See [networking](../networking) and the DVL's [TCP protocol](../dvl/dvl-protocol.md#json-protocol-tcp). ## Code examples diff --git a/docs/dvl/networking.md b/docs/dvl/networking.md index 2162088f..942586e1 100644 --- a/docs/dvl/networking.md +++ b/docs/dvl/networking.md @@ -3,7 +3,7 @@ The DVL has several services available over ethernet: * [Multicast DNS](#multicast-dns-mdns) (mDNS) for easy discovery -* Web [GUI](../gui/dashboard), providing a visualisation of the data outputted by the DVL, as well as configuration, [updating of software](../sw-update), diagnostics, and more. +* Web [GUI](../dvl/gui/dashboard.md), providing a visualisation of the data outputted by the DVL, as well as configuration, [updating of software](../sw-update), diagnostics, and more. * TCP [data stream](#tcp-data-stream) * [Software updates](../sw-update) @@ -11,7 +11,7 @@ The DVL has several services available over ethernet: ### Multicast DNS (mDNS) -The DVL runs a DHCP client which will attempt to obtain an IP address from a DHCP server (e.g. in a router) on the same network, and supports mDNS: the mDNS name of the DVL is `waterlinked-dvl`. On a computer which supports mDNS, one can then simply access the web [GUI](../gui/dashboard) at [http://waterlinked-dvl](http://waterlinked-dvl). +The DVL runs a DHCP client which will attempt to obtain an IP address from a DHCP server (e.g. in a router) on the same network, and supports mDNS: the mDNS name of the DVL is `waterlinked-dvl`. On a computer which supports mDNS, one can then simply access the web [GUI](../dvl/gui/dashboard.md) at [http://waterlinked-dvl](http://waterlinked-dvl). !!! note If no DHCP server is available on the network, it is recommended to use the [fallback IP](#fallback-ip) or configure a [static IP address](#via-the-gui), as the DVL can spend up to 5 minutes searching for a DHCP server. @@ -23,11 +23,11 @@ The DVL will always be available with the static IP address: **192.168.194.95**. * Connect an ethernet cable directly from the DVL to your computer. * For an/the ethernet interface of your computer, configure it to have a static IP address in the same subnet as 192.168.194.95, e.g. 192.168.194.90 or anything else of the form 192.168.194.xxx if using a subnet of the form 255.255.255.0 (aka 192.168.194.0/24). * Activate the ethernet interface of your computer which you configured in the previous step. -* In a web browser, open http://192.168.194.95 to access the web [GUI](../gui/dashboard). +* In a web browser, open http://192.168.194.95 to access the web [GUI](../dvl/gui/dashboard.md). ### Via the GUI -The IP address of the DVL can be configured in two ways via the web [GUI](../gui/dashboard): +The IP address of the DVL can be configured in two ways via the web [GUI](../dvl/gui/dashboard.md): * DCHP client: an IP address is obtained from a DHCP server (e.g. in a router) on the same network, as in the discussion of [mDNS](#multicast-dns-mdns) above. * Static: equip the DVL with a certain static IP address. @@ -39,4 +39,4 @@ After the IP configuration of the DVL is modified, the DVL needs to be rebooted ## TCP data stream -The DVL can output data and receive commands over Transmission Control Protocol (TCP). A TCP server is available on port **16171** which outputs the latest data to all connected clients, and which listens to commands from any of these connected clients. See the DVL's TCP [protocol](./dvl-protocol.md#ethernet-protocol-tcp). +The DVL can output data and receive commands over Transmission Control Protocol (TCP). A TCP server is available on port **16171** which outputs the latest data to all connected clients, and which listens to commands from any of these connected clients. See the DVL's TCP [protocol](../dvl/dvl-protocol.md#json-protocol-tcp). diff --git a/docs/dvl/sw-update.md b/docs/dvl/sw-update.md index 8adbf4e2..c6bfdd8d 100644 --- a/docs/dvl/sw-update.md +++ b/docs/dvl/sw-update.md @@ -2,7 +2,7 @@ It is recommended to always run the latest DVL software where possible. The latest software can be obtained [automatically](#automatic-software-update) or [manually](#offline-software-update). -The release notes for each release is available in the [GUI](../gui/dashboard) and also in the [GUI demo](https://dvl.demo.waterlinked.com/#/about). +The release notes for each release is available in the [GUI](../dvl/gui/dashboard.md) and also in the [GUI demo](https://dvl.demo.waterlinked.com/#/about). !!! Warning During the software upgrade, the thermal protection feature is turned off. To prevent the DVL from overheating, it is important to submerge the DVL in water throughout the update process. @@ -12,7 +12,7 @@ The release notes for each release is available in the [GUI](../gui/dashboard) a ## Automatic software update -The DVL's [GUI](../gui/dashboard) automatically checks and indicates if a new software version is available. +The DVL's [GUI](../dvl/gui/dashboard.md) automatically checks and indicates if a new software version is available. * Connect the DVL over ethernet to a network connected to the internet. If on a personal computer, it may be necessary to make a network bridge between a network interface (such as wifi) which has access to the internet and the ethernet interface through which the DVL is connected. * Go to http://[IP_ADDRESS_OF_THE_DVL]:9000 in a web browser. @@ -22,7 +22,7 @@ The DVL's [GUI](../gui/dashboard) automatically checks and indicates if a new so If it is not possible to connect the DVL to the internet, one can proceed as follows. -* Find the current version and chip ID of the DVL at *Menu -> About* in the [GUI](../gui/dashboard). +* Find the current version and chip ID of the DVL at *Menu -> About* in the [GUI](../dvl/gui/dashboard.md). * Manually download an update package (`.wlup`) from the [update server](https://update.waterlinked.com/) using the chip ID. * Verify if the downloaded version is newer than the currently running version. * Set system time as shown below. diff --git a/docs/explorer-kit/gui/api.md b/docs/explorer-kit/gui/api.md index 7f7b8850..91e9a7d7 100644 --- a/docs/explorer-kit/gui/api.md +++ b/docs/explorer-kit/gui/api.md @@ -16,7 +16,7 @@ See [demo.waterlinked.com/swagger](http://demo.waterlinked.com/swagger) for the Any programming language can be used to interact with the API. We have examples in both [python](https://github.com/waterlinked/examples) and [go](https://github.com/waterlinked/ugps-nmea-go), which currently cover, for instance: -* Sending of locator depth when using the [A1 locator](../locators/locator-a1) (see the script `externaldepth.py`). +* Sending of locator depth when using the [A1 locator](../locators/locator-a1.md) (see the script `externaldepth.py`). * Sending in of satellite GPS data (positioning and/or heading) from an external GPS receiver (see the script `nmeainput.py` or its [go analogue](https://github.com/waterlinked/ugps-nmea-go)) * Export of tracks to a GPX file (see the script `tracklog.py`) * Output of the positions calculated by the UGPS G2 system in NMEA format (see the script `nmeaoutput.py` or its [go analogue](https://github.com/waterlinked/ugps-nmea-go)) diff --git a/docs/explorer-kit/gui/settings.md b/docs/explorer-kit/gui/settings.md index 5f1e5351..4bff93f4 100644 --- a/docs/explorer-kit/gui/settings.md +++ b/docs/explorer-kit/gui/settings.md @@ -7,7 +7,7 @@ In this section you choose which locator you are using with the system and on which channel it is sending. The Water Linked default channel is 17 and this is the channel that the Locator-S1 is running on. If using the Locator-U1 the channel needs to macth the rotary switch at the back of the U1. !!! warning - If you are using the Locator-A1 or S1, you need to provid depth information to the topside unit. Description on how to do this is found [here](api.md#providing-depth-to-system-when-using-locator-a1s1). + If you are using the Locator-A1 or S1, you need to provid depth information to the topside unit. This is implemented through the explorer-kit's[API](../gui/api.md). ## Top-side Setup diff --git a/docs/explorer-kit/locators/locator-a1.md b/docs/explorer-kit/locators/locator-a1.md index b8b25c39..80372081 100644 --- a/docs/explorer-kit/locators/locator-a1.md +++ b/docs/explorer-kit/locators/locator-a1.md @@ -4,7 +4,7 @@ ## Description -The Locator-A1 has the smallest physical footprint in our series of locators. It can be integrated into even the most compact ROVs. The Locator-A1 does not carry its own depth sensor, and the Master-D1 requires that the depth be provided from your underwater vehicle (ROV etc.) This can be achieved by means of the [UGPS API](../gui/api). +The Locator-A1 has the smallest physical footprint in our series of locators. It can be integrated into even the most compact ROVs. The Locator-A1 does not carry its own depth sensor, and the Master-D1 requires that the depth be provided from your underwater vehicle (ROV etc.) This can be achieved by means of the [UGPS API](../gui/api.md). ## Wiring interface diff --git a/docs/explorer-kit/locators/locator-s1.md b/docs/explorer-kit/locators/locator-s1.md index 15092b4f..28f9e25d 100644 --- a/docs/explorer-kit/locators/locator-s1.md +++ b/docs/explorer-kit/locators/locator-s1.md @@ -11,7 +11,7 @@ Some Locator-S1 attributes can be configured using an integrated UART (3V3) inte Locator-S1 supports channel 16,17 and 18. -As the Locator-S1 does not carry its own depth sensor, the depth needs to be provided from the underwater vehicle (ROV etc.) to the topside Master-D1 using the software API. Example of how to perform this can be found [here](../gui/api.md#providing-depth-to-system-when-using-locator-a1s1). +As the Locator-S1 does not carry its own depth sensor, the depth needs to be provided from the underwater vehicle (ROV etc.) to the topside Master-D1 using the software API. This can be achieved by means of the [UGPS API](../gui/api.md). ## LED Signals diff --git a/docs/explorer-kit/quickstart.md b/docs/explorer-kit/quickstart.md index 1d07cc2b..ed0e8050 100644 --- a/docs/explorer-kit/quickstart.md +++ b/docs/explorer-kit/quickstart.md @@ -41,7 +41,7 @@ Now that everything is connected and ready it is time to select the right locato After selecting the correct locator, you need to provide the correct placement of the receivers to the GUI for the positioning to work correctly. This is done by drag'n drop of each receiver to the correct placment relative to the topside unit. The position of each receiver is seen below in the map view. It you click on the receiver you get a pop up with the possibility to write its exact placment. Once this is done you can limit the search range by using the same drag and drop feature. !!! warning - If you are using the Locator-A1 or S1, you need to provide depth information to the topside unit. Description on how to do this is found [here](gui/api.md#providing-depth-to-system-when-using-locator-a1s1). + If you are using the Locator-A1 or S1, you need to provide depth information to the topside unit. This is achieved using the explorer-kit [API](../explorer-kit/gui/api.md). !!! tip Reducing the search range helps to improve the performance of the system. It is recomended to limith this range if you are operating in a smaller area. This is especially important in tanks. diff --git a/docs/explorer-kit/upgrader.md b/docs/explorer-kit/upgrader.md index 98cd056e..e40d9c81 100644 --- a/docs/explorer-kit/upgrader.md +++ b/docs/explorer-kit/upgrader.md @@ -10,7 +10,7 @@ A software update package (.wlup file) includes all files required to update the Please select the update process that is best suited to you: -* If the Underwater GPS GUI is visible to you on [http://192.168.2.94](http://192.168.2.94) please use the [Update with static IP](#update-using-static-ip). +* Type *http://192.168.2.94* in your web browser. If the Underwater GPS GUI is visible to you, please use the [Update with static IP](#update-using-static-ip). * If the Underwater GPS GUI is not shown when using the link above, please use the [Update with DHCP](#update-using-dhcp). !!! warning @@ -33,12 +33,12 @@ This procedure works if you have haven't changed the jumpers on the Master-D1, y | 2 | Power off the system | | | 3 | Connect the upgrade plug included in the kit or connect GPIO0 to ground using a jumper cable | ![upgrade_plug](../img/upgrade_plug.jpg) ![upgrade_jumper](/../img/upgrade_jumper.jpg) | | 4 | Power on the system | | -| 6 | Go to web gui [http://192.168.2.94](http://192.168.2.94) | If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | +| 6 | Open the web gui by typing *http://192.168.2.94* in your web browser.| If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | | 7 | Remove the upgade plug or the jumper grounding GP0. | | | 8 | Click “Browse file” and select correct <>.wlup file | | | 9 | Wait for update process to complete | | | 10 | When the update process is complete and successful, the system will automatically reboot to standard mode | If process fails, please try again | -| 11 | Verify that the SW version has updated by going to the web gui [http://192.168.2.94](http://192.168.2.94) | If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | +| 11 | Verify that the SW version has updated by going to the web gui *http://192.168.2.94* | If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | | 12 | Upgrade process complete | Celebrate with your favorite beverage | @@ -55,11 +55,11 @@ This procedure works if you don't know how to set a static IP address on your co | 5 | Configure the network on your computer to get IP address from DHCP | (this is default on most computers, so if you haven't set a static ip you're good) | | 6 | Connect the upgrade plug included in the kit or connect GPIO0 to ground using a jumper cable | ![upgrade_plug](../img/upgrade_plug.jpg) ![upgrade_jumper](/../img/upgrade_jumper.jpg) | | 7 | Power on the system | | -| 8 | Go to web GUI [http://192.168.0.1](http://192.168.0.1) | If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | +| 8 | In your web browser, open *http://192.168.0.1* | If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | | 9 | Remove the grounding of GP0. | | | 10 | Click “Browse file” and select correct <>.wlup file | | | 11 | Wait for update process to complete | | | 12 | When the update process is complete and successful, the system will automatically reboot to standard mode | If process fails, please try again | -| 13 | Verify that the SW version has updated by going to the web gui [http://192.168.0.1](http://192.168.0.1) | If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | +| 13 | Verify that the SW version has updated by opeing the web gui in your browser: *http://192.168.0.1* | If you see a blank or partly broken page, try to clean browser cache by pressing Ctrl-F5 or opening the page in "Private"/"Incognito" mode | | 14 | Reset network settings to original setting from step 2 | See [network settings](hardware.md). | | 15 | Upgrade process complete | Celebrate with your favorite beverage | diff --git a/docs/img/ugps-img/ugps-imu-calibration.png b/docs/img/ugps-img/ugps-imu-calibration.png new file mode 100644 index 0000000000000000000000000000000000000000..7f1d66cea19f4e791351eb5f608852be2c628564 GIT binary patch literal 66064 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

us)EaVzb6fS_*w{4o-PJ6% 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 PJxCX1&L^Gy_3r-x@RQPp literal 0 HcmV?d00001 diff --git a/docs/modem-m64/modem-m64-protocol.md b/docs/modem-m64/modem-m64-protocol.md index 85534991..ecbe8eb1 100644 --- a/docs/modem-m64/modem-m64-protocol.md +++ b/docs/modem-m64/modem-m64-protocol.md @@ -50,7 +50,7 @@ The modem with role B will go back to listen mode if several consecutive packets Payload where every byte is \0 is reserved. It is used to keep modems in sync if no data packet is queued by the user. This sync packet is filtered out by the receiver. Avoid this payload by compressing the data or otherwise ensuring atleast 1 bit is non-zero. Checksum is optional when sending commands to the modem. The modem always returns a checksum. The checksum algorithm -is CRC-8 and it is formatted as a hexadecimal number using 2 lower-case charaters (ex: `*c3`). See the [checksum section](../../dvl/dvl-protocol/#checksum) of the manual for our DVL product (which uses the same CRC-8 algorithm) for further details and example code. +is CRC-8 and it is formatted as a hexadecimal number using 2 lower-case charaters (ex: `*c3`). See the [checksum section](../dvl/dvl-protocol.md#checksum) of the manual for our DVL product (which uses the same CRC-8 algorithm) for further details and example code. ## Commands diff --git a/docs/sonar-3d/sonar-3d-15-config.md b/docs/sonar-3d/sonar-3d-15-config.md index f614dd55..ea926f8b 100644 --- a/docs/sonar-3d/sonar-3d-15-config.md +++ b/docs/sonar-3d/sonar-3d-15-config.md @@ -25,7 +25,7 @@ Acoustics are disabled when the Sonar first boot. You'll see a message in the 3D ### Network -Set how the Sonar 3D-15 is assigned an IP on your network: Automatic IP (DHCP) or Static IP. Default is Automatic IP. For further details regarding network setup, [see Networking](/Sonar-3d/Sonar-3d-15-networking/). +Set how the Sonar 3D-15 is assigned an IP on your network: Automatic IP (DHCP) or Static IP. Default is Automatic IP. For further details regarding network setup, [see Networking](../sonar-3d/sonar-3d-15-networking.md). !!! Note Saved Network Settings are persistent, meaning it is kept on restart. @@ -83,7 +83,7 @@ Allows for upgrading the Sonar's firmware. Click the button to open a new tab to ![Upgrade firmware](../img/Sonar-3D-15-config-advanced-firmware.png) -The firmware upgrader allows for automatically checking and upgrading the Sonar firmware if neccessary. This requires a working Internet connection to work. Alternatively, an offline (manual) upgrade can be used. [Read more about offline firmware upgrades](/sonar-3d-15-software-update/#offline-software-update). +The firmware upgrader allows for automatically checking and upgrading the Sonar firmware if neccessary. This requires a working Internet connection to work. Alternatively, an offline (manual) upgrade can be used. [Read more about offline firmware upgrades](../sonar-3d/sonar-3d-15-software-update.md#offline-software-update). If needed, follow the steps to complete the upgrade. Upon completion, the Sonar will reset all settings back to factory default and restart. Firmware upgrade can take a couple of minutes. @@ -105,7 +105,7 @@ Submit a [support ticket](https://waterlinked.com/support) and attach the diagno ### Integration API -Change how the Sonar transmits data and at what address the integration API is available from. Options are Disabled, Multicast (Default) and Unicast. [Read more about the Integration API](/sonar-3d/sonar-3d-15-api). +Change how the Sonar transmits data and at what address the integration API is available from. Options are Disabled, Multicast (Default) and Unicast. [Read more about the Integration API](../sonar-3d/sonar-3d-15-api.md). ### Update Rate diff --git a/docs/sonar-3d/sonar-3d-15-networking.md b/docs/sonar-3d/sonar-3d-15-networking.md index 568ba91b..30ddaab0 100644 --- a/docs/sonar-3d/sonar-3d-15-networking.md +++ b/docs/sonar-3d/sonar-3d-15-networking.md @@ -15,7 +15,7 @@ The Sonar 3D-15 has several services available over ethernet: The Sonar 3D-15 runs a DHCP client which will attempt to obtain an IP address from a DHCP server (e.g. in a router) on the same network, and supports mDNS: the mDNS name of the Sonar 3D-15 is `waterlinked-sonar`. On a computer which supports mDNS, one can then simply access the web [GUI](sonar-3d-15-gui.md) at [http://waterlinked-sonar](http://waterlinked-sonar). !!! note - If no DHCP server is available on the network, it is recommended to use the [fallback IP](#fallback-ip) or configure a [static IP address](#via-the-gui), as the Sonar 3D-15 can spend up to 5 minutes searching for a DHCP server. + If no DHCP server is available on the network, it is recommended to use the [fallback IP](#fallback-ip) or configure a [static IP address](#user-set-ip), as the Sonar 3D-15 can spend up to 5 minutes searching for a DHCP server. ### Fallback IP diff --git a/docs/underwater-gps/integration/bluerov-integration-a1.md b/docs/underwater-gps/integration/bluerov-integration-a1.md index 24a57689..cffb5675 100644 --- a/docs/underwater-gps/integration/bluerov-integration-a1.md +++ b/docs/underwater-gps/integration/bluerov-integration-a1.md @@ -1,6 +1,6 @@ # Installation of Locator-A1 on BlueROV2 with integration kit -This guide describes the hardware modifications to the ROV, FXTI and UGPS Topside in order to integrate the [Locator-A1](../../locators/locator-a1). To summarize, two main changes are performed: A spare twisted wire pair in the tether is used to connect the Locator-A1 and the UGPS Topside. Secondly, the UGPS Topside is connected directly to the communication between ROV and topside computer. +This guide describes the hardware modifications to the ROV, FXTI and UGPS Topside in order to integrate the [Locator-A1](../locators/locator-a1.md). To summarize, two main changes are performed: A spare twisted wire pair in the tether is used to connect the Locator-A1 and the UGPS Topside. Secondly, the UGPS Topside is connected directly to the communication between ROV and topside computer. ## Required parts and tools @@ -291,7 +291,7 @@ Now that all hardware modifications are done, you will connect UGPS Topside, FXT * Set your topside computer to have a static IP address of 192.168.2.1 with subnet mask 255.255.255.0. The BlueROV2 typically has IP address 192.168.2.2, so you probably already have this set up. Make sure your firewall allows QGroundControl to communicate with the network. Look at the [Network Setup steps at Blue Robotics](https://bluerobotics.com/learn/bluerov2-software-setup/#network-setup) if you need more details. -* Set the [IP switch](../../network-settings/#ethernet) inside the UGPS Topside unit to `192.168.2.94` (the down position). This equips the G2 topside unit with the static IP address 192.168.2.94. +* Set the [IP switch](../network-settings.md#ethernet) inside the UGPS Topside unit to `192.168.2.94` (the down position). This equips the G2 topside unit with the static IP address 192.168.2.94. * Connect the Binder-connector named "Locator" at the UGPS Topside with the newly installed Binder-connector at the FXTI using the deck extension cable, which came with the BlueROV integration kit. (Power up the UGPS Topside)[https://waterlinked.github.io/underwater-gps/power-supply/]. It is on when the power button is lit. diff --git a/docs/underwater-gps/integration/bluerov-integration-u1.md b/docs/underwater-gps/integration/bluerov-integration-u1.md index c753495d..689259c6 100644 --- a/docs/underwater-gps/integration/bluerov-integration-u1.md +++ b/docs/underwater-gps/integration/bluerov-integration-u1.md @@ -1,6 +1,6 @@ # Installation of Locator-U1 on BlueROV2 -This guide contains instructions for installation of the [Locator-U1](../../locators/locator-u1) to a BlueROV2. The first part describes the mechanical installation and the second part describes how to establish a network bridge between UGPS Topside and FXTI/BlueROV2. +This guide contains instructions for installation of the [Locator-U1](../locators/locator-u1.md) to a BlueROV2. The first part describes the mechanical installation and the second part describes how to establish a network bridge between UGPS Topside and FXTI/BlueROV2. ## Mount the Locator-U1 to the BlueROV2 frame @@ -15,7 +15,7 @@ See the [general Locator-U instructions](../locators/locator-u1.md) for daily op In this guide it is described how to establish a network connection between UGPS Topside, FXTI/BlueROV2 and topside computer without hardware modifications to the UGPS Topside. This is opposed to the method used with the BlueROV integration kit for Locator-A1. To put it short, the connection between the three devices is established with a network bridge and a static IP address of 192.168.2.1 (subnet mask 255.255.255.0) for your computer. -1. Set the [IP switch](../../network-settings/#ethernet) inside the UGPS G2 topside unit to `192.168.2.94` (the down position). This equips the G2 topside unit with the static IP address 192.168.2.94. +1. Set the [IP switch](../network-settings.md#ethernet) inside the UGPS G2 topside unit to `192.168.2.94` (the down position). This equips the G2 topside unit with the static IP address 192.168.2.94. 2. [Connect power](https://waterlinked.github.io/underwater-gps/power-supply/) to the UGPS Topside and switch on the power, resulting in the power switch lighting up. diff --git a/docs/underwater-gps/integration/bluerov-integration.md b/docs/underwater-gps/integration/bluerov-integration.md index 085c3c4e..53a3ba54 100644 --- a/docs/underwater-gps/integration/bluerov-integration.md +++ b/docs/underwater-gps/integration/bluerov-integration.md @@ -4,26 +4,26 @@ The Water Linked Underwater GPS G2 (from now UGPS) system can be integrated with ## Most common integration methods -* We recommend you to use the [Locator-A1](../../locators/locator-a1) together with the [BlueROV2 Integration Kit](https://waterlinked.com/shop/underwater-gps-g2-bluerov2-integration-kit-103) when integrating the UGPS system with the BlueROV2. The integration steps are described in [BlueROV2 Integration Locator-A1](bluerov-integration-a1.md). Hardware modification must be carried out on the ROV, FXTI and UGPS Topside which serve two purposes: Firstly, a spare twisted wire pair in the tether is used to connect the Locator-A1 to the UGPS Topside. Secondly, the UGPS Topside is modified to connect directly to the communication between ROV and topside computer. The advantage of integrating using this method is that there is no additional topside computer configuration required, which can be challenging with different operating systems (i.e. Linux, iOS). +* We recommend you to use the [Locator-A1](../locators/locator-a1.md) together with the [BlueROV2 Integration Kit](https://waterlinked.com/shop/underwater-gps-g2-bluerov2-integration-kit-103) when integrating the UGPS system with the BlueROV2. The integration steps are described in [BlueROV2 Integration Locator-A1](bluerov-integration-a1.md). Hardware modification must be carried out on the ROV, FXTI and UGPS Topside which serve two purposes: Firstly, a spare twisted wire pair in the tether is used to connect the Locator-A1 to the UGPS Topside. Secondly, the UGPS Topside is modified to connect directly to the communication between ROV and topside computer. The advantage of integrating using this method is that there is no additional topside computer configuration required, which can be challenging with different operating systems (i.e. Linux, iOS). -* If you wish to avoid carrying out hardware changes to the ROV, as they are required to integrate the A1-Locator, then we recommend you to use the [Locator-U1](../../locators/locator-u1). The locator can simply be attached to the BlueROV2 in any convenient way. However some configuration steps in the topside computer are required to establish a network bridge, so the position calculated by the UGPS Topside is available in QGroundControl. These steps are described in [BlueROV2 Integration Locator-U1](bluerov-integration-u1.md). Be aware that setting up a network bridge in operating systems other than Windows can be challenging. +* If you wish to avoid carrying out hardware changes to the ROV, as they are required to integrate the A1-Locator, then we recommend you to use the [Locator-U1](../locators/locator-u1.md). The locator can simply be attached to the BlueROV2 in any convenient way. However some configuration steps in the topside computer are required to establish a network bridge, so the position calculated by the UGPS Topside is available in QGroundControl. These steps are described in [BlueROV2 Integration Locator-U1](bluerov-integration-u1.md). Be aware that setting up a network bridge in operating systems other than Windows can be challenging. ## Alternative integration methods -* If you wish to use a [Locator-A1](../../locators/locator-a1), however you wish to avoid purchasing the full integration kit then this can be done. The Locator-A1 must be installed on the ROV and connected to the G2 Topside and then it is necessary to set-up a network bridge. The steps in these sections are relevant +* If you wish to use a [Locator-A1](../locators/locator-a1.md), however you wish to avoid purchasing the full integration kit then this can be done. The Locator-A1 must be installed on the ROV and connected to the G2 Topside and then it is necessary to set-up a network bridge. The steps in these sections are relevant * [Modifications to the BlueROV2](bluerov-integration-a1.md#modifications-to-the-bluerov2) * [Modifications to the FXTI](bluerov-integration-a1.md#modifications-to-the-fxti) with the deviation that the blue/white twisted pair between Tether Connection PCB and Binder-connector-pigtail-assembly does not need to be connected. * [Establish a network connection with a network bridge](bluerov-integration-u1.md#establish-a-network-connection-between-ugps-topside-bluerov2-and-topside-computer) * [Final steps](#final-steps-of-integration-independent-of-locator) -* If you wish to use the [Locator-U1](../../locators/locator-u1), however you wish to avoid the complication in setting up a network bridge, it is possible to integrate by using the [BlueROV2 Integration Kit](https://waterlinked.com/shop/underwater-gps-g2-bluerov2-integration-kit-103). The steps in these sections are relevant +* If you wish to use the [Locator-U1](../locators/locator-u1.md), however you wish to avoid the complication in setting up a network bridge, it is possible to integrate by using the [BlueROV2 Integration Kit](https://waterlinked.com/shop/underwater-gps-g2-bluerov2-integration-kit-103). The steps in these sections are relevant * [Mount the Locator-U1 to the BlueROV2 frame](bluerov-integration-u1.md#mount-the-locator-u1-to-the-bluerov2-frame) * [Modifications to the UGPS Topside](bluerov-integration-a1.md#modifications-to-the-ugps-topside) * [Modifications to the FXTI](bluerov-integration-a1.md#modifications-to-the-fxti) with the deviation that the green/white twisted pair between tether and Binder-connector-pigtail-assembly does not need to be connected. * [Establish a network connection with powerline communication](bluerov-integration-a1.md#establish-a-network-connection-between-ugps-topside-bluerov2-and-topside-computer) * [Final steps](#final-steps-of-integration-independent-of-locator) -* If using a [Locator-D1](../../locators/locator-d1), use the D1's cable and attach the D1 locator to the BlueROV2 in any convenient way. No further hardware integration is then required. As with the Locator-U1, +* If using a [Locator-D1](../locators/locator-d1.md), use the D1's cable and attach the D1 locator to the BlueROV2 in any convenient way. No further hardware integration is then required. As with the Locator-U1, * [Establish a network connection with a network bridge](bluerov-integration-u1.md#establish-a-network-connection-between-ugps-topside-bluerov2-and-topside-computer) * and follow the [final steps](#final-steps-of-integration-independent-of-locator) @@ -119,4 +119,4 @@ The current draw by the FXTI can exceed 500 mA when connecting the Underwater GP ## Water Linked software updates -Keep the Water Linked software [up to date](../../sw-update). The GUI should notify when an update is available, but the current version can also be checked at [192.168.2.94/#/about](http://192.168.2.94/#/about). \ No newline at end of file +Keep the Water Linked software [up to date](../sw-update.md). The GUI should notify when an update is available, but the current version can also be checked at [192.168.2.94/#/about](http://192.168.2.94/#/about). \ No newline at end of file diff --git a/docs/underwater-gps/integration/external-gps.md b/docs/underwater-gps/integration/external-gps.md index e2a085d9..9835ab0a 100644 --- a/docs/underwater-gps/integration/external-gps.md +++ b/docs/underwater-gps/integration/external-gps.md @@ -2,16 +2,16 @@ In very dynamic conditions with rapid changes in angles, the IMU will drift too much to provide sufficient heading accuracy. In this case it is recommended to implement an external compass to provide updated heading information. ## Which compass to use -If the UGPS is permanently installed on a boat, the simple solution is to use the boats compass, if it provides the possibility to output the NMEA data. Otherwise it is possible to use any portable compass that provide NMEA0185 or NMEA2000 information. +If the UGPS is permanently installed on a boat, the simple solution is to use the boats compass, if it provides the possibility to output NMEA data. Otherwise it is possible to use any portable compass that provide NMEA0185 or NMEA2000 information. ## External compass on the UGPS: -To use an external compass with the UGPS it has to be integrated in the software on your computer. As for now there are no hardware connection. +To use an external compass with the UGPS it has to be integrated in the software on your computer. As for now there are no direct hardware connection available. The needed firmware can be installed by following this procedure: !!! Note This is valid only for compasses that provides NMEA0183 -- Go to: https://github.com/waterlinked/ugps-nmea-go under “Readme” and “Installation” and “Download the application”, choose v.1.7.1 +- Go to: https://github.com/waterlinked/ugps-nmea-go under “Readme” and “Installation” and “Download the application”, choose v.1.8.0 - Download the .zip-file. - In windows: run the file. Follow the instructions you get. (It is advisable to create a folder on your computer specifically for this configuration) - In linux, in the directory you saved the file in: use chmod +x (It is advisable to create a folder on your computer specifically for this configuration) diff --git a/docs/underwater-gps/interface/ugps-led.md b/docs/underwater-gps/interface/ugps-led.md index 87d4ef15..6798d560 100644 --- a/docs/underwater-gps/interface/ugps-led.md +++ b/docs/underwater-gps/interface/ugps-led.md @@ -1,7 +1,7 @@ # LED Indicators Only the topside box and the Locator U1 has LED indicators. -Here is a broken [link](http://example.com/feil) +Here is a broken [link](http://dennelinken.fungererikke) ## Topside diff --git a/docs/underwater-gps/interface/warnings.md b/docs/underwater-gps/interface/warnings.md index 169fa759..a8035acb 100644 --- a/docs/underwater-gps/interface/warnings.md +++ b/docs/underwater-gps/interface/warnings.md @@ -4,7 +4,7 @@ Warnings that you might experience while using the UGPS. | Message | Solution | |---------|----------| -| No external depth received. Is it being sent correctly? | The Underwater GPS is not receiving the depth of the Locator from the ROV. This normally means software on the ROV is not working correctly. Details on how the depth is sent to the system can be found [here](../integration/api.md#providing-depth-to-system-when-using-locator-a1). | +| No external depth received. Is it being sent correctly? | The Underwater GPS is not receiving the depth of the Locator from the ROV. This normally means software on the ROV is not working correctly. Depth is sent to the system through the [API](../integration/api.md). | | No signal from Locator-U1. Have you selected the correct channel? | Verify that the Locator-U1 is powered on and that it has GPS lock (See [LED signals](../locators/locator-u1.md#led-signals) ). Verify that the same channel is selected on the settings page and the Locator rotary switch. Verify that the Locator and Receivers are in the water | | Missing GPS lock/position. Please provide me with an unobstructed view of the sky | The Underwater GPS needs GPS lock for time sync purposes. Move the Topside to another location where it has better view of the sky. | | Locator-D1 not detected. Please verify connection. | Locator-D1 selected but not detected by the Master-D1. Verify connection. | diff --git a/docs/underwater-gps/introduction.md b/docs/underwater-gps/introduction.md index 982b3fd1..5f530b19 100644 --- a/docs/underwater-gps/introduction.md +++ b/docs/underwater-gps/introduction.md @@ -13,9 +13,9 @@ The [Underwater GPS G2](https://www.waterlinked.com/underwater-gps) is a robust !!! Tip We offer a live [demo](https://demo.waterlinked.com) of the GUI of the UGPS G2 system. It runs on simulated data designed to illustrate various GUI features; this data is not necessarily realistic in all aspects! -The Underwater GPS G2 system is based upon Short Baseline (SBL) acoustic positioning. A locator ([U1](../locators/locator-u1), [A1](../locators/locator-a1), or [D1](../locators/locator-d1)) is attached to the device to be positioned. It functions as a beacon, sending out acoustic signals. Near the surface, either an [antenna](antenna) containing four receivers is lowered into the water, or four loose [receivers](../receiver-d1) are lowered into the water. These listen for the beacon signals. +The Underwater GPS G2 system is based upon Short Baseline (SBL) acoustic positioning. A locator ([U1](../underwater-gps/locators/locator-u1.md), [A1](../underwater-gps/locators/locator-a1.md), or [D1](../underwater-gps/locators/locator-d1.md)) is attached to the device to be positioned. It functions as a beacon, sending out acoustic signals. Near the surface, either an [antenna](antenna.md) containing four receivers is lowered into the water, or four loose [receivers](../underwater-gps/receiver-d1.md) are lowered into the water. These listen for the beacon signals. -Time-of-flight from the locator to each of the four receivers is used in an innovative algorithm to calculate the position of the locator relative to the UGPS G2 topside unit. We refer to as the _acoustic position_. The UGPS G2 system obtains a _global position_ by combining this acoustic position with the global GPS coordinates of the topside unit. This may be provided by the topside unit's in-built GPS antenna, or, for greater precision, passed in externally by means of the UGPS G2 [API](../integration/api). This API provides output of both the acoustic and global positions calculated by the UGPS G2 system, as well as comprehensive programmatic configuration of the system. +Time-of-flight from the locator to each of the four receivers is used in an innovative algorithm to calculate the position of the locator relative to the UGPS G2 topside unit. We refer to as the _acoustic position_. The UGPS G2 system obtains a _global position_ by combining this acoustic position with the global GPS coordinates of the topside unit. This may be provided by the topside unit's in-built GPS antenna, or, for greater precision, passed in externally by means of the UGPS G2 [API](../underwater-gps/integration/api.md). This API provides output of both the acoustic and global positions calculated by the UGPS G2 system, as well as comprehensive programmatic configuration of the system. Compared to USBL systems, the UGPS G2 system has the advantage of working well in challenging environments, for example shallow water, or reflective environments such as near ship hulls, in fish cages, near harbour installations, inside water tanks, etc. One of our [FAQs](https://support.waterlinked.com/en/knowledge/why-choose-ugps-g2-over-a-usbl-system) elaborates further on this. @@ -25,7 +25,7 @@ Compared to USBL systems, the UGPS G2 system has the advantage of working well i * Quick deployment using an [antenna](antenna.md) * WiFi connectivity * Integrated global GPS antenna -* Interface supporting [BlueROV2 hardware integration](../integration/bluerov-integration) +* Interface supporting [BlueROV2 hardware integration](../underwater-gps/integration/bluerov-integration.md) * Simple and quick updating of firmware/software ## Kit content diff --git a/docs/underwater-gps/quickstart.md b/docs/underwater-gps/quickstart.md index 9a464e14..ff053cea 100644 --- a/docs/underwater-gps/quickstart.md +++ b/docs/underwater-gps/quickstart.md @@ -46,7 +46,7 @@ For alternative ways to connect to the topside, see [Networking](../underwater-g ### Locator -Attach the locator ([U1](../locators/locator-u1), [A1](../locators/locator-a1), or [D1](../locators/locator-d1)) to your vehicle. The [BlueROV2 integration guide](../integration/bluerov-integration) may be helpful if integrating an A1 or D1 locator with a vehicle tether. +Attach the locator ([U1](../underwater-gps/locators/locator-u1.md), [A1](../underwater-gps/locators/locator-a1.md), or [D1](../underwater-gps/locators/locator-d1.md)) to your vehicle. The [BlueROV2 integration guide](../underwater-gps/integration/bluerov-integration.md) may be helpful if integrating an A1 or D1 locator with a vehicle tether. If using an A1 or D1 locator, connect it to the 'Locator' bulkhead on the UGPS G2 topside box. The U1 connector is wireless, which means that this step can be omitted. @@ -54,7 +54,7 @@ If using an A1 or D1 locator, connect it to the 'Locator' bulkhead on the UGPS G ### Antenna -Unfold the [antenna](../../antenna) and lock the mast straight using the latches on the folding joints. Avoid the cable being pinched at the joints. Secure the three arms in place using the thumb screw. Place the antenna in water at the desired location. Secure the Antenna using the RAM Mount components included with the antenna. +Unfold the [antenna](../underwater-gps/antenna.md) and lock the mast straight using the latches on the folding joints. Avoid the cable being pinched at the joints. Secure the three arms in place using the thumb screw. Place the antenna in water at the desired location. Secure the Antenna using the RAM Mount components included with the antenna. Connect the antenna to the bulkhead marked 'Receiver 1/Antenna' on the UGPS G2 topside box (see the above picture). @@ -63,21 +63,21 @@ Connect the antenna to the bulkhead marked 'Receiver 1/Antenna' on the UGPS G2 t ### Loose receivers -Before deploying the [receivers](../../receiver-d1) in the water, add a piece of tape to each receiver cable at the desired depth, to make [configuration](#configure-antennareceiver-placement-and-search-range) easier. Place the receivers in the water at the desired location, and connect one to each of the four bulkheads 'Receiver 1', 'Receiver 2', 'Receiver 3', and 'Receiver 4' of the UGPS G2 topside box (see the above picture). +Before deploying the [receivers](../underwater-gps/receiver-d1.md) in the water, add a piece of tape to each receiver cable at the desired depth, to make [configuration](#configure-antennareceiver-placement-and-search-range) easier. Place the receivers in the water at the desired location, and connect one to each of the four bulkheads 'Receiver 1', 'Receiver 2', 'Receiver 3', and 'Receiver 4' of the UGPS G2 topside box (see the above picture). !!! Tip Add a weight just above each receiver to improve stability in the water. ## Select locator and channel in the GUI -Select the correct locator type in the [GUI settings](../gui/settings/), and choose which channel to listen on. Channel 2 is the default. If using a [Locator-U1](../locators/locator-u1/), ensure that its channel (set by completely unscrewing the lid and turning the dial inside) is set to the same channel as you configure in the GUI. +Select the correct locator type in the [GUI settings](../underwater-gps/interface/ugps-gui.md#settings), and choose which channel to listen on. Channel 2 is the default. If using a [Locator-U1](../underwater-gps/locators/locator-u1.md), ensure that its channel (set by completely unscrewing the lid and turning the dial inside) is set to the same channel as you configure in the GUI. !!! Note - If you are using the Locator-A1, depth information needs to be provided to the topside unit by means of the UGPS [API](../integration/api). You can ignore this if following the [BlueROV2 integration guide](../integration/bluerov-integration). + If you are using the Locator-A1, depth information needs to be provided to the topside unit by means of the UGPS [API](../underwater-gps/integration/api.md). You can ignore this if following the [BlueROV2 integration guide](../underwater-gps/integration/bluerov-integration.md). ## Configure antenna/receiver placement and search range -Provide the correct placement of the antenna/receivers relative to the topside box in the [GUI settings](../gui/settings/), and, if using an antenna, specify if it has been rotated from the default indicated in the GUI. +Provide the correct placement of the antenna/receivers relative to the topside box in the [GUI settings](../underwater-gps/interface/ugps-gui.md#settings), and, if using an antenna, specify if it has been rotated from the default indicated in the GUI. Specifically, for the antenna, enter the position and optionally the rotational angle manually under **Advanced settings**. diff --git a/docs/underwater-gps/reference-frames.md b/docs/underwater-gps/reference-frames.md index 7e8bcde6..f29831b8 100644 --- a/docs/underwater-gps/reference-frames.md +++ b/docs/underwater-gps/reference-frames.md @@ -40,4 +40,4 @@ The z-coordinate of the acoustic frame is always depth relative to the sea surfa The default origin is a point on the topside housing, but can be taken to be anywhere: it is entirely defined by the positioning of the antenna/receivers with respect to it. If using an antenna, it may help intuitively to take the origin to be the base of the antenna, which can be achieved by setting both *Distance to topside housing* fields to 0 under *Baseline -> Antenna configuration -> Advanced settings*. !!! Note - The axes of the acoustic frame in the first version of UGPS, the [Explorer Kit](../../explorer-kit/quickstart), were slightly different: it was the y-axis which was aligned with the forward direction of the topside housing, and the x-axis which was to the 'east' of this. + The axes of the acoustic frame in the first version of UGPS, the [Explorer Kit](../explorer-kit/quickstart.md), were slightly different: it was the y-axis which was aligned with the forward direction of the topside housing, and the x-axis which was to the 'east' of this. diff --git a/docs/underwater-gps/sw-update.md b/docs/underwater-gps/sw-update.md index 7f30bbf2..35fee7e0 100644 --- a/docs/underwater-gps/sw-update.md +++ b/docs/underwater-gps/sw-update.md @@ -4,9 +4,9 @@ It is recommended to always run the latest UGPS G2 software where possible. The ## Automatic software update -The G2's [GUI](../gui/position) automatically checks and indicates if a new software version is available. +The G2's [GUI](./interface/ugps-gui.md) automatically checks and indicates if a new software version is available. -* [Connect](../network-settings) the G2 topside unit over ethernet or wifi to a network connected to the internet. If on a personal computer, it may be necessary to make a network bridge between a network interface which has access to the internet and the interface through which the G2 topside is connected. +* [Connect](./network-settings.md) the G2 topside unit over ethernet or wifi to a network connected to the internet. If on a personal computer, it may be necessary to make a network bridge between a network interface which has access to the internet and the interface through which the G2 topside is connected. * Go to http://[IP_ADDRESS_OF_THE_G2_TOPSIDE]:9000 in a web browser. * The GUI will automatically check if there is a new version available, and if so, initiate installation of it with a single click. @@ -14,7 +14,7 @@ The G2's [GUI](../gui/position) automatically checks and indicates if a new soft If it is not possible to connect the G2 topside to the internet, one can proceed as follows. -* Find the current version and chip ID of the G2 topside unit at *Menu -> About* in the [GUI](../gui/position). +* Find the current version and chip ID of the G2 topside unit at *Menu -> About* in the [GUI](./interface/ugps-gui.md). * Manually download an update package (`.wlup`) from the [update server](https://update.waterlinked.com/) using the chip ID. * Verify if the downloaded version is newer than the currently running version. * Navigate to http://[IP_ADDRESS_OF_THE_G2_TOPSIDE]:9000 in a web browser. diff --git a/docs/underwater-gps/ugps-sys-setup.md b/docs/underwater-gps/ugps-sys-setup.md index 52fb9818..bdc2916b 100644 --- a/docs/underwater-gps/ugps-sys-setup.md +++ b/docs/underwater-gps/ugps-sys-setup.md @@ -15,9 +15,9 @@ The antenna can be placed anywhere up to 10m from the topside housing (limited b | | | | ------------------- | :------------------- | -| **Alignment** | Ensure that the 'Forward' direction of the antenna as defined by a label on one of its prongs (see also the figure below) is aligned with the 'Forward' direction of the topside housing (indicated by a label on the lid).

If it is not possible to physically align them, in *Baseline -> Antenna configuration -> Advanced settings*, specify the clockwise angle in degrees from the forward axis of the topside to the forward axis of the antenna.

If this alignment is not carried out, the [global](../../reference-frames#global) position outputted by UGPS G2 will be incorrect. +| **Alignment** | Ensure that the 'Forward' direction of the antenna as defined by a label on one of its prongs (see also the figure below) is aligned with the 'Forward' direction of the topside housing (indicated by a label on the lid).

If it is not possible to physically align them, in *Baseline -> Antenna configuration -> Advanced settings*, specify the clockwise angle in degrees from the forward axis of the topside to the forward axis of the antenna.

If this alignment is not carried out, the [global](../underwater-gps/reference-frames.md#global-frame) position outputted by UGPS G2 will be incorrect. | **Line-of-sight** | Ensure that there will be line-of-sight between the antenna and locator. | -| **Antenna depth** | Ensure that the base of the antenna is at a depth of at least one metre (as indicated by a label upon the top folding joint of the pole of the antenna), to avoid acoustic disturbance.

The depth of the antenna base (relative to the sea surface) must be specified in *Baseline -> Antenna configuration -> Advanced settings -> Antenna depth*. If it is not, both the [acoustic](../../reference-frames#acoustic) and [global](../../reference-frames#global) positions may be incorrect. | +| **Antenna depth** | Ensure that the base of the antenna is at a depth of at least one metre (as indicated by a label upon the top folding joint of the pole of the antenna), to avoid acoustic disturbance.

The depth of the antenna base (relative to the sea surface) must be specified in *Baseline -> Antenna configuration -> Advanced settings -> Antenna depth*. If it is not, both the [acoustic](./reference-frames.md#acoustic-frame) and [global](../underwater-gps/reference-frames.md#global-frame) positions may be incorrect. | | **Antenna stability** | Secure the antenna tightly to the vessel using the provided Ram Mount. |

@@ -31,7 +31,7 @@ The antenna can be placed anywhere up to 10m from the topside housing (limited b ## Receivers -Loose receivers can be placed anywhere up to 100m from the topside housing. Go through the following, and configure the placement of the receivers in the graphical pane at *Baseline -> Receiver and range configuration* so that their positions relative to the origin and their depths are correct. See[System Configuration](../underwater-gps/ugps-sysconfig.md#basline-settings) +Loose receivers can be placed anywhere up to 100m from the topside housing. Go through the following, and configure the placement of the receivers in the graphical pane at *Baseline -> Receiver and range configuration* so that their positions relative to the origin and their depths are correct. See [System Configuration](../underwater-gps/ugps-sysconfig.md#basline-settings) | | | | ------------------- | :------------------- | @@ -52,7 +52,7 @@ The figure below indicates a typical loose receiver configuration when the topsi ## Locator setup -Select the type of locator ([U1](../underwater-gps/locators/locator-u1.md), [A1](../underwater-gps/locators/locator-a1), or [D1](../underwater-gps/locators/locator-d1)) which you are using, and which [channel](#channel-overview) you wish to use. +Select the type of locator ([U1](../underwater-gps/locators/locator-u1.md), [A1](../underwater-gps/locators/locator-a1.md), or [D1](../underwater-gps/locators/locator-d1.md)) which you are using, and which [channel](../underwater-gps/ugps-sysconfig.md#channel-overview) you wish to use. No matter what locator that is in use, it always need to be placed within line of sight from the receivers. This will in most cases be somewere on top of the unit that is to be tracked. @@ -65,12 +65,12 @@ As the U1 is a wireless locator it can easily be mounted on your vehicle with th ### Locator A1 The A1 needs to be physically connected to the G2 Topside, either directly or through a full system integration.
-For wiring details of the A1, se [locator-A1](../underwater-gps/locators/locator-a1.md). +For wiring details of the A1, se [locator-A1][A1](../underwater-gps/locators/locator-a1.md). If you are using the A1 on a Bluerov, see [Bluerov integration](./integration/bluerov-integration-a1.md) !!! Note - If using the [A1](../../locators/locator-a1) locator, the depth of the locator must be inputted by means of the UGPS [API](../../integration/api). + If using the [A1](../underwater-gps/locators/locator-a1.md) locator, the depth of the locator must be inputted by means of the UGPS [API](../underwater-gps/integration/api.md). ### Locator D1 The D1 comes with 50m integrated cable that is coupled directly into the topside box. diff --git a/docs/underwater-gps/ugps-sysconfig.md b/docs/underwater-gps/ugps-sysconfig.md index 068d4afc..c49526f9 100644 --- a/docs/underwater-gps/ugps-sysconfig.md +++ b/docs/underwater-gps/ugps-sysconfig.md @@ -22,13 +22,13 @@ Cofigurations of the topside and locator settings is conducted in [Settings](../ ### Locator settings -Select the type of locator ([U1](../../locators/locator-u1), [A1](../../locators/locator-a1), or [D1](../../locators/locator-d1)) which you are using, and which [channel](#channel-overview) you wish to use. +Select the type of locator ([U1](./locators/locator-u1.md), [A1](./locators/locator-a1.md), or [D1](./locators/locator-d1.md)) which you are using, and which [channel](#channel-overview) you wish to use. !!! Note - If using the [U1](../../locators/locator-u1) locator, the channel must match the rotary switch at the back of the U1 (screw the lid completely off to access the switch). + If using the [U1](./locators/locator-u1.md) locator, the channel must match the rotary switch at the back of the U1 (screw the lid completely off to access the switch). !!! Note - If using the [A1](../../locators/locator-a1) locator, the depth of the locator must be inputted by means of the UGPS [API](../../integration/api). + If using the [A1](./locators/locator-a1.md) locator, the depth of the locator must be inputted by means of the UGPS [API](./integration/api.md). #### Channel overview @@ -46,18 +46,24 @@ The frequency bands of the available channels are as follows. Lower frequency ty ### Topside settings - The default source for the topside position and heading is *On-board*. This configuration should be chosen if the topside is located in any dynamic environment, like on a boat or similar. -!!! Note - Since version 3.3.0 of the software, the heading of the topside unit must be set periodically because only the gyroscope of the built-in IMU is used, not the magnetometer. In the on-board mode for heading you will be prompted to enter the heading manually after startup (using an analogue compass, a mobile phone, etc). - -For best performance on boats or similar, with a moving topside unit, we recommend to use an exteranl input of heading data (e.g. from a GPS compass) as well as global position data. An external device will likely be more accurate than the topside unit's built-in GPS receiver and IMU. For a thorough description on how to do this, see [External Compass](../underwater-gps/integration/external-gps.md) - If the topside unit/antenna is at a globally stationary position (like a jetty) the *static* configuration of position and heading will give best accuracy of the system. Below you can see how the position and heading is set to static. Clicking on the map button opens a map window to help you input the static position. ![gui_settings_topside_setup_static_pos_marked](../img/gui_settings_topside_setup_static_pos_marked.png) + +#### IMU calibration +The link "Onboard IMU calibration" takes you to a window where you can reset the gyros and set the heading manually. +![IMU calibration](../img/ugps-img/ugps-imu-calibration.png) +It is advisable to reset the gyros before every use. Place the topside on a static horisontal area and press "Reset gyros. + +The topsides heading has to be set manually. Use a decent compass and enter the heading in the heading filed, and press "set current heading". + +!!! Note + When you are using On-board positioning the heading has to be set periodically, as the IMU will drift over time. + +For best performance on boats or similar, with a moving topside unit, we recommend to use an exteranl input of heading data (e.g. from a GPS compass) as well as global position data. An external device will likely be more accurate than the topside unit's built-in GPS receiver and IMU. For a thorough description on how to do this, see [External Compass](../underwater-gps/integration/external-gps.md) #### User preferences Select whether to use metric or imperial units, and/or if you would like a dummy boat to be displayed on the map and receiver configuration pages. diff --git a/hooks/pre-push b/hooks/pre-push index c3d8cafd..bf1a0d53 100755 --- a/hooks/pre-push +++ b/hooks/pre-push @@ -1,13 +1,66 @@ #!/bin/bash -# Pre-push hook: run MkDocs linkcheck +# Pre-push hook: build MkDocs locally and run LinkChecker +set -e -echo "Running MkDocs linkcheck..." -python -m mkdocs build --config-file mkdocs-linkcheck.yml +# === Paths === +PROJECT_ROOT="$(cd "$(dirname "$0")"/.. && pwd)" +VENV_BIN="$PROJECT_ROOT/venv/bin" +TMP_BUILD_DIR="$PROJECT_ROOT/.tmp-mkdocs-build" +DOCS_DIR="$PROJECT_ROOT/docs" -if [ $? -ne 0 ]; then - echo "Linkcheck failed! Push aborted." + +#Checking internal links in markdown files only +echo "Checking internal links in markdown files..." +set +e +#Using custom python script for internal link checking: +"$VENV_BIN/python" "$PROJECT_ROOT/checklinks.py" "$DOCS_DIR" +RESULT_INTERNAL=$? +set -e + +if [ $RESULT_INTERNAL -ne 0 ]; then + echo "Internal linkcheck failed! Please fix Markdown links before pushing." + exit 1 +fi + +echo "Internal linkcheck passed!" + +# Check if linkchecker exists +if [ ! -x "$VENV_BIN/linkchecker" ]; then + echo "Error: linkchecker executable not found in $VENV_BIN" + exit 1 +fi + +# Remove old temp build if it exists +rm -rf "$TMP_BUILD_DIR" + +# Build MkDocs into temporary directory +echo "Building MkDocs locally into $TMP_BUILD_DIR..." +"$VENV_BIN/python" -m mkdocs build -d "$TMP_BUILD_DIR" + +echo "Running LinkChecker on external links against local build..." +set +e +# Only report broken links +"$VENV_BIN/linkchecker" "file://$TMP_BUILD_DIR/index.html" \ + --no-status \ + --check-extern \ + --recursion-level=2 \ + --ignore-url='sitemap\.xml\.gz' \ + --ignore-url='https://github.com/.*/edit/' \ + --ignore-url='https://www.youtube.com/' \ + --ignore-url='.*/assets/.*' \ + --ignore-url='.*/images/.*' + + +RESULT_EXTERNAL=$? +set -e + +# Clean up +rm -rf "$TMP_BUILD_DIR" + +if [ $RESULT_EXTERNAL -ne 0 ]; then + echo "External linkcheck failed! Please fix broken links before pushing." exit 1 fi -echo "Linkcheck passed. Proceeding with push." +echo "External linkcheck passed!" exit 0 \ No newline at end of file diff --git a/mkdocs-linkcheck.yml b/mkdocs-linkcheck.yml deleted file mode 100644 index 5ef0bfb7..00000000 --- a/mkdocs-linkcheck.yml +++ /dev/null @@ -1,4 +0,0 @@ -site_name: build linkcheck -plugins: - - linkcheck: - fail_on_warning: true \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index b90aa740..7e17494b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,9 +1,6 @@ site_name: Documentation -site_url: "https://waterlinked.github.io" -repo_url: https://github.com/waterlinked/waterlinked.github.io -plugins: - - linkcheck: - fail_on_warning: true +site_url: https://docs.waterlinked.com +repo_url: https://github.com/waterlinked/docs theme: name: material theme_dir: docstheme/material @@ -73,7 +70,7 @@ nav: - Baseline: - Antenna: underwater-gps/antenna.md - Receiver-D1: underwater-gps/receiver-d1.md - - Locator: + - Locators: - Locator-A1: underwater-gps/locators/locator-a1.md - Locator-D1: underwater-gps/locators/locator-d1.md - Locator-U1: underwater-gps/locators/locator-u1.md From 0b0cebb2d06729a727bb0f67c011c3f82341d283 Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:07:26 +0200 Subject: [PATCH 4/9] Reapply "Added automatic link-checking and fixed plenty of links" This reverts commit 46d1f5f70e9def3f01e4f4cc8b8fd51741803d39. --- hooks/pre-push | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hooks/pre-push b/hooks/pre-push index bf1a0d53..2c954d93 100755 --- a/hooks/pre-push +++ b/hooks/pre-push @@ -1,20 +1,33 @@ #!/bin/bash -# Pre-push hook: build MkDocs locally and run LinkChecker +# Pre-push hook: Custom linkchecker for local links, Build MkDocs locally and run LinkChecker on external links + set -e # === Paths === -PROJECT_ROOT="$(cd "$(dirname "$0")"/.. && pwd)" +PROJECT_ROOT="$(git rev-parse --show-toplevel)" VENV_BIN="$PROJECT_ROOT/venv/bin" TMP_BUILD_DIR="$PROJECT_ROOT/.tmp-mkdocs-build" DOCS_DIR="$PROJECT_ROOT/docs" +echo "PROJECT_ROOT=$PROJECT_ROOT" +echo "DOCS_DIR=$DOCS_DIR" +echo "VENV_BIN=$VENV_BIN" +"$VENV_BIN/python" --version + +# Activate venv if not already activated +if [ -f "$VENV_BIN/activate" ]; then + . "$VENV_BIN/activate" +fi + #Checking internal links in markdown files only echo "Checking internal links in markdown files..." + set +e #Using custom python script for internal link checking: "$VENV_BIN/python" "$PROJECT_ROOT/checklinks.py" "$DOCS_DIR" RESULT_INTERNAL=$? + set -e if [ $RESULT_INTERNAL -ne 0 ]; then From ea72ddc1f58f7674d613a1bbc2f1a51b19bee73b Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:07:29 +0200 Subject: [PATCH 5/9] Reapply "minor change, removed echo paths used for testing linkchecker" This reverts commit 5eba0487fae4130a1e2b99c42e00a35bba7134f8. --- hooks/pre-push | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hooks/pre-push b/hooks/pre-push index 2c954d93..97840d46 100755 --- a/hooks/pre-push +++ b/hooks/pre-push @@ -9,17 +9,11 @@ VENV_BIN="$PROJECT_ROOT/venv/bin" TMP_BUILD_DIR="$PROJECT_ROOT/.tmp-mkdocs-build" DOCS_DIR="$PROJECT_ROOT/docs" -echo "PROJECT_ROOT=$PROJECT_ROOT" -echo "DOCS_DIR=$DOCS_DIR" -echo "VENV_BIN=$VENV_BIN" -"$VENV_BIN/python" --version - # Activate venv if not already activated if [ -f "$VENV_BIN/activate" ]; then . "$VENV_BIN/activate" fi - #Checking internal links in markdown files only echo "Checking internal links in markdown files..." From a10f07e70590421944cb4b401fee37797d428e74 Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:46:14 +0200 Subject: [PATCH 6/9] Revert requirements to same as master --- requirements.txt | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/requirements.txt b/requirements.txt index 845505f3..b5917eb5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,39 +1,3 @@ -aiohappyeyeballs==2.6.1 -aiohttp==3.12.15 -aiosignal==1.4.0 -async-timeout==5.0.1 -attrs==25.3.0 -cfgv==3.4.0 -click==8.2.1 -distlib==0.4.0 -filelock==3.19.1 -frozenlist==1.7.0 -ghp-import==2.1.0 -identify==2.6.13 -idna==3.10 -importlib_metadata==8.7.0 -Jinja2==3.0.3 -Markdown==3.8 -MarkupSafe==3.0.2 -mergedeep==1.3.4 mkdocs==1.2.3 -mkdocs-linkcheck==1.0.6 mkdocs-material==7.2.0 -mkdocs-material-extensions==1.3.1 -multidict==6.6.4 -nodeenv==1.9.1 -packaging==25.0 -platformdirs==4.4.0 -pre_commit==4.3.0 -propcache==0.3.2 -Pygments==2.19.1 -pymdown-extensions==10.15 -python-dateutil==2.9.0.post0 -PyYAML==6.0.2 -pyyaml_env_tag==1.1 -six==1.17.0 -typing_extensions==4.15.0 -virtualenv==20.34.0 -watchdog==6.0.0 -yarl==1.20.1 -zipp==3.22.0 +jinja2<3.1.0 From 36fdb3eb0a7d948c909cbd07e8ae08d565f6575e Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:05:53 +0200 Subject: [PATCH 7/9] Fixes after review --- .github/workflows/build.yml | 1 + README.md | 22 ++++++++++++++-------- checklinks.py => check-internal-links.py | 0 hooks/pre-push => check-links.sh | 3 ++- install-hooks.sh | 2 +- requirements.txt | 1 + 6 files changed, 19 insertions(+), 10 deletions(-) rename checklinks.py => check-internal-links.py (100%) rename hooks/pre-push => check-links.sh (95%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7728bfaf..b6da3eee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,6 +26,7 @@ jobs: - name: Build docs run: | mkdocs build --strict + ./check-links.sh # Only deploy on master - name: Deploy docs diff --git a/README.md b/README.md index cbce33ef..716e60ce 100644 --- a/README.md +++ b/README.md @@ -14,27 +14,33 @@ This is done by creating a pull request. Make sure you have Python3 installed. ``` -git clone https://github.com/waterlinked/waterlinked.github.io -cd waterlinked.github.io +git clone https://github.com/waterlinked/docs.git +cd docs python -m venv venv source venv/bin/activate (Linux) venv\Scripts\activate.bat (Windows) pip install -r requirements.txt -./install-hooks.sh -mkdocs serve +./install-hooks.sh # (Optional) To automatically check links on git push ``` 2. Make changes using your favorite editor 3. Test them +``` +mkdocs serve # Allow you to view the changes on your browser +``` * Fire up your browser and go to localhost:8000 -## Deploy changes to server -After the changes have been tested and they work, push the changes to the master branch and Github will build the website and publish it on https://docs.waterlinked.com. +Verify links are valid: -## Automatic link-checker -When you push to git, all links are automatically checked. Any errors will be listed in your terminal. If you want to check links before pushing, use > ./hooks/pre-push +``` +./check-links.sh +``` + +## Deploy changes to server +After the changes have been tested and they work, push the changes to a branch, and make a merge request. The documentation site will built automatically and links will be verified. +Once the pull request is merged the documentation will be automatically built and published to https://docs.waterlinked.com. diff --git a/checklinks.py b/check-internal-links.py similarity index 100% rename from checklinks.py rename to check-internal-links.py diff --git a/hooks/pre-push b/check-links.sh similarity index 95% rename from hooks/pre-push rename to check-links.sh index 97840d46..06311e8f 100755 --- a/hooks/pre-push +++ b/check-links.sh @@ -1,6 +1,7 @@ #!/bin/bash # Pre-push hook: Custom linkchecker for local links, Build MkDocs locally and run LinkChecker on external links +# Exit on error set -e # === Paths === @@ -19,7 +20,7 @@ echo "Checking internal links in markdown files..." set +e #Using custom python script for internal link checking: -"$VENV_BIN/python" "$PROJECT_ROOT/checklinks.py" "$DOCS_DIR" +"$VENV_BIN/python" "$PROJECT_ROOT/check-internal-links.py" "$DOCS_DIR" RESULT_INTERNAL=$? set -e diff --git a/install-hooks.sh b/install-hooks.sh index 194a88b3..25887b78 100755 --- a/install-hooks.sh +++ b/install-hooks.sh @@ -1,4 +1,4 @@ #!/bin/bash mkdir -p .git/hooks -ln -sf ../../hooks/pre-push .git/hooks/pre-push +ln -sf check-links.sh .git/hooks/pre-push echo "Pre-push hook installed!" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index b5917eb5..0342ff1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ mkdocs==1.2.3 mkdocs-material==7.2.0 jinja2<3.1.0 +LinkChecker==10.3.0 From 69231731e18cf9282f17d835528b2427b374789c Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:12:29 +0200 Subject: [PATCH 8/9] Fix script for github action --- check-links.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/check-links.sh b/check-links.sh index 06311e8f..402711df 100755 --- a/check-links.sh +++ b/check-links.sh @@ -20,7 +20,7 @@ echo "Checking internal links in markdown files..." set +e #Using custom python script for internal link checking: -"$VENV_BIN/python" "$PROJECT_ROOT/check-internal-links.py" "$DOCS_DIR" +python "$PROJECT_ROOT/check-internal-links.py" "$DOCS_DIR" RESULT_INTERNAL=$? set -e @@ -33,8 +33,8 @@ fi echo "Internal linkcheck passed!" # Check if linkchecker exists -if [ ! -x "$VENV_BIN/linkchecker" ]; then - echo "Error: linkchecker executable not found in $VENV_BIN" +if ! command -v linkchecker >/dev/null 2>&1; then + echo "Error: linkchecker executable not found in PATH" exit 1 fi @@ -43,12 +43,12 @@ rm -rf "$TMP_BUILD_DIR" # Build MkDocs into temporary directory echo "Building MkDocs locally into $TMP_BUILD_DIR..." -"$VENV_BIN/python" -m mkdocs build -d "$TMP_BUILD_DIR" +python -m mkdocs build -d "$TMP_BUILD_DIR" echo "Running LinkChecker on external links against local build..." set +e # Only report broken links -"$VENV_BIN/linkchecker" "file://$TMP_BUILD_DIR/index.html" \ +linkchecker "file://$TMP_BUILD_DIR/index.html" \ --no-status \ --check-extern \ --recursion-level=2 \ From cb4c4756c1a8b0b16d4d5cb1f5891a744759a1aa Mon Sep 17 00:00:00 2001 From: wlkh <32092934+wlkh@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:16:37 +0200 Subject: [PATCH 9/9] Rename build job to be less confusing --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6da3eee..95d9b511 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Deploy Water Linked Docs +name: Build Docs on: push: