IMU eingebaut
This commit is contained in:
@@ -16,12 +16,17 @@ Die Software liegt in diesem Repository direkt an der Wurzel. Nicht zur Software
|
|||||||
| **Hostname** | `cuno` |
|
| **Hostname** | `cuno` |
|
||||||
| **Benutzer** | `pi` |
|
| **Benutzer** | `pi` |
|
||||||
| **SSH-Passwort** | `Sonneberg` |
|
| **SSH-Passwort** | `Sonneberg` |
|
||||||
| **LAN-IP** | `192.168.1.83` |
|
| **LAN-IP (`eskimue.de`)** | `192.168.1.83` |
|
||||||
| **WLAN-IP** | `192.168.1.9` |
|
| **WLAN-IP (`eskimue.de`)** | `192.168.1.9` |
|
||||||
|
| **WLAN-IP (`4pi`, SSH)** | `10.42.44.150` |
|
||||||
| **Fallback-AP** | SSID `CUNO`, IP `192.168.50.1`, Passwort `astr0cun042` |
|
| **Fallback-AP** | SSID `CUNO`, IP `192.168.50.1`, Passwort `astr0cun042` |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# im WLAN "eskimue.de"
|
||||||
ssh pi@192.168.1.9
|
ssh pi@192.168.1.9
|
||||||
|
|
||||||
|
# im WLAN "4pi"
|
||||||
|
ssh pi@10.42.44.150
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -134,6 +139,8 @@ ssh pi@192.168.1.9 "docker cp /home/pi/ExoMy_Software/src/meine_datei.py exomy_a
|
|||||||
ssh pi@192.168.1.9 "docker restart exomy_autostart"
|
ssh pi@192.168.1.9 "docker restart exomy_autostart"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Im WLAN `4pi` dieselben Befehle jeweils mit `10.42.44.150` statt `192.168.1.9` verwenden.
|
||||||
|
|
||||||
GUI-Dateien:
|
GUI-Dateien:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -96,6 +96,49 @@
|
|||||||
<strong id="service_exomy" class="sr-val service_state state_unknown">-</strong>
|
<strong id="service_exomy" class="sr-val service_state state_unknown">-</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="p-hdr">
|
||||||
|
<div class="p-dot"></div>
|
||||||
|
<span class="p-lbl">IMU BNO085</span>
|
||||||
|
<span class="p-tag">I2C 0x4A</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Status</span>
|
||||||
|
<strong id="imu_state" class="sr-val service_state state_unknown">-</strong>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-off"></span>
|
||||||
|
<span class="sr-key">Adresse</span>
|
||||||
|
<strong id="imu_address" class="sr-val">-</strong>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-off"></span>
|
||||||
|
<span class="sr-key">Accel</span>
|
||||||
|
<strong id="imu_acceleration" class="sr-val">-</strong>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-off"></span>
|
||||||
|
<span class="sr-key">Gyro</span>
|
||||||
|
<strong id="imu_gyro" class="sr-val">-</strong>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-off"></span>
|
||||||
|
<span class="sr-key">Mag</span>
|
||||||
|
<strong id="imu_magnetic" class="sr-val">-</strong>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-off"></span>
|
||||||
|
<span class="sr-key">Quaternion</span>
|
||||||
|
<strong id="imu_quaternion" class="sr-val">-</strong>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-off"></span>
|
||||||
|
<span class="sr-key">Hinweis</span>
|
||||||
|
<strong id="imu_error" class="sr-val">-</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="admin-col">
|
<div class="admin-col">
|
||||||
@@ -934,6 +977,13 @@
|
|||||||
setServiceState('camera_service_state', '-');
|
setServiceState('camera_service_state', '-');
|
||||||
setServiceState('service_admin_api', '-');
|
setServiceState('service_admin_api', '-');
|
||||||
setServiceState('service_exomy', '-');
|
setServiceState('service_exomy', '-');
|
||||||
|
setStateText('imu_state', 'unknown', '-');
|
||||||
|
setText('imu_address', '--');
|
||||||
|
setText('imu_acceleration', '--');
|
||||||
|
setText('imu_gyro', '--');
|
||||||
|
setText('imu_magnetic', '--');
|
||||||
|
setText('imu_quaternion', '--');
|
||||||
|
setText('imu_error', '--');
|
||||||
var bar = document.getElementById('bar-temp-adm');
|
var bar = document.getElementById('bar-temp-adm');
|
||||||
if (bar) bar.style.width = '0%';
|
if (bar) bar.style.width = '0%';
|
||||||
}
|
}
|
||||||
@@ -1147,6 +1197,16 @@
|
|||||||
node.classList.add('state_unknown');
|
node.classList.add('state_unknown');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setStateText(id, state, text) {
|
||||||
|
var node = document.getElementById(id);
|
||||||
|
if (!node) return;
|
||||||
|
node.textContent = text || '-';
|
||||||
|
node.classList.remove('state_active', 'state_inactive', 'state_unknown');
|
||||||
|
if (state === 'active' || state === 'running') { node.classList.add('state_active'); return; }
|
||||||
|
if (state === 'inactive' || state === 'failed' || state === 'exited') { node.classList.add('state_inactive'); return; }
|
||||||
|
node.classList.add('state_unknown');
|
||||||
|
}
|
||||||
|
|
||||||
function formatNumber(value, digits) {
|
function formatNumber(value, digits) {
|
||||||
return Number(value || 0).toLocaleString('de-DE', {
|
return Number(value || 0).toLocaleString('de-DE', {
|
||||||
minimumFractionDigits: digits,
|
minimumFractionDigits: digits,
|
||||||
@@ -2428,6 +2488,7 @@
|
|||||||
function renderStatus(data) {
|
function renderStatus(data) {
|
||||||
var system = data.system || {};
|
var system = data.system || {};
|
||||||
var services = data.services || {};
|
var services = data.services || {};
|
||||||
|
var imu = data.imu || {};
|
||||||
setAdminStatus(data.status || 'Bereit');
|
setAdminStatus(data.status || 'Bereit');
|
||||||
setText('info_ips', system.ips);
|
setText('info_ips', system.ips);
|
||||||
setText('info_wifi', system.wifi);
|
setText('info_wifi', system.wifi);
|
||||||
@@ -2463,6 +2524,13 @@
|
|||||||
setServiceState('camera_service_state', services.camera);
|
setServiceState('camera_service_state', services.camera);
|
||||||
setServiceState('service_admin_api', services.admin_api);
|
setServiceState('service_admin_api', services.admin_api);
|
||||||
setServiceState('service_exomy', services.exomy);
|
setServiceState('service_exomy', services.exomy);
|
||||||
|
setStateText('imu_state', imu.state || 'unknown', imu.status || '-');
|
||||||
|
setText('imu_address', imu.address);
|
||||||
|
setText('imu_acceleration', imu.acceleration);
|
||||||
|
setText('imu_gyro', imu.gyro);
|
||||||
|
setText('imu_magnetic', imu.magnetic);
|
||||||
|
setText('imu_quaternion', imu.quaternion);
|
||||||
|
setText('imu_error', imu.error || '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchStatus() {
|
async function fetchStatus() {
|
||||||
|
|||||||
+133
-1
@@ -14,6 +14,7 @@ import subprocess
|
|||||||
import termios
|
import termios
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
PORT = 8082
|
PORT = 8082
|
||||||
@@ -66,6 +67,11 @@ CAMERA_PROFILE_MAP = {profile['id']: profile for profile in CAMERA_PROFILES}
|
|||||||
DEFAULT_CAMERA_PROFILE_ID = '1296x972'
|
DEFAULT_CAMERA_PROFILE_ID = '1296x972'
|
||||||
CAMERA_FPS_OPTIONS = [1, 2, 3, 4, 5, 7, 10, 20]
|
CAMERA_FPS_OPTIONS = [1, 2, 3, 4, 5, 7, 10, 20]
|
||||||
DEFAULT_CAMERA_FPS = 10
|
DEFAULT_CAMERA_FPS = 10
|
||||||
|
IMU_I2C_ADDRESS = '0x4A'
|
||||||
|
IMU_LOCK = threading.Lock()
|
||||||
|
IMU_SENSOR = None
|
||||||
|
IMU_LAST_ERROR = None
|
||||||
|
IMU_WORKAROUND_APPLIED = False
|
||||||
|
|
||||||
|
|
||||||
class ReusableThreadingTCPServer(socketserver.ThreadingTCPServer):
|
class ReusableThreadingTCPServer(socketserver.ThreadingTCPServer):
|
||||||
@@ -77,6 +83,130 @@ def run_command(command):
|
|||||||
return result.stdout.strip(), result.stderr.strip(), result.returncode
|
return result.stdout.strip(), result.stderr.strip(), result.returncode
|
||||||
|
|
||||||
|
|
||||||
|
def _format_vector(values, unit, decimals=2):
|
||||||
|
if not values:
|
||||||
|
return 'unbekannt'
|
||||||
|
return 'X {0:.{d}f} | Y {1:.{d}f} | Z {2:.{d}f} {u}'.format(
|
||||||
|
values[0], values[1], values[2], d=decimals, u=unit
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _format_quaternion(values):
|
||||||
|
if not values:
|
||||||
|
return 'unbekannt'
|
||||||
|
return 'I {0:.3f} | J {1:.3f} | K {2:.3f} | R {3:.3f}'.format(
|
||||||
|
values[0], values[1], values[2], values[3]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _apply_bno08x_workaround(module):
|
||||||
|
global IMU_WORKAROUND_APPLIED
|
||||||
|
|
||||||
|
if IMU_WORKAROUND_APPLIED:
|
||||||
|
return
|
||||||
|
|
||||||
|
original_handle_packet = module.BNO08X._handle_packet
|
||||||
|
|
||||||
|
def safe_handle_packet(self, packet):
|
||||||
|
try:
|
||||||
|
return original_handle_packet(self, packet)
|
||||||
|
except KeyError as exc:
|
||||||
|
# Some BNO085 firmwares emit undocumented reports that the Adafruit
|
||||||
|
# library cannot decode yet. Ignore those packets and keep known
|
||||||
|
# sensor reports flowing.
|
||||||
|
if len(exc.args) == 1 and isinstance(exc.args[0], int):
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
|
||||||
|
module.BNO08X._handle_packet = safe_handle_packet
|
||||||
|
IMU_WORKAROUND_APPLIED = True
|
||||||
|
|
||||||
|
|
||||||
|
def _create_imu_sensor():
|
||||||
|
global IMU_LAST_ERROR
|
||||||
|
|
||||||
|
try:
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.filterwarnings(
|
||||||
|
'ignore',
|
||||||
|
message='I2C frequency is not settable in python, ignoring!',
|
||||||
|
category=RuntimeWarning,
|
||||||
|
)
|
||||||
|
import adafruit_bno08x
|
||||||
|
import board
|
||||||
|
import busio
|
||||||
|
from adafruit_bno08x import (
|
||||||
|
BNO_REPORT_ACCELEROMETER,
|
||||||
|
BNO_REPORT_GYROSCOPE,
|
||||||
|
BNO_REPORT_MAGNETOMETER,
|
||||||
|
BNO_REPORT_ROTATION_VECTOR,
|
||||||
|
)
|
||||||
|
from adafruit_bno08x.i2c import BNO08X_I2C
|
||||||
|
|
||||||
|
_apply_bno08x_workaround(adafruit_bno08x)
|
||||||
|
|
||||||
|
i2c = busio.I2C(board.SCL, board.SDA, frequency=400000)
|
||||||
|
sensor = BNO08X_I2C(i2c)
|
||||||
|
for feature in (
|
||||||
|
BNO_REPORT_ACCELEROMETER,
|
||||||
|
BNO_REPORT_GYROSCOPE,
|
||||||
|
BNO_REPORT_MAGNETOMETER,
|
||||||
|
BNO_REPORT_ROTATION_VECTOR,
|
||||||
|
):
|
||||||
|
sensor.enable_feature(feature)
|
||||||
|
time.sleep(0.2)
|
||||||
|
IMU_LAST_ERROR = None
|
||||||
|
return sensor
|
||||||
|
except Exception as exc:
|
||||||
|
IMU_LAST_ERROR = str(exc)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def read_imu_status():
|
||||||
|
global IMU_SENSOR, IMU_LAST_ERROR
|
||||||
|
|
||||||
|
with IMU_LOCK:
|
||||||
|
if IMU_SENSOR is None:
|
||||||
|
IMU_SENSOR = _create_imu_sensor()
|
||||||
|
|
||||||
|
if IMU_SENSOR is None:
|
||||||
|
return {
|
||||||
|
'state': 'unknown',
|
||||||
|
'status': 'Nicht bereit',
|
||||||
|
'address': IMU_I2C_ADDRESS,
|
||||||
|
'acceleration': 'unbekannt',
|
||||||
|
'gyro': 'unbekannt',
|
||||||
|
'magnetic': 'unbekannt',
|
||||||
|
'quaternion': 'unbekannt',
|
||||||
|
'error': IMU_LAST_ERROR or 'BNO085 nicht verfugbar',
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
'state': 'active',
|
||||||
|
'status': 'Verbunden',
|
||||||
|
'address': IMU_I2C_ADDRESS,
|
||||||
|
'acceleration': _format_vector(IMU_SENSOR.acceleration, 'm/s^2'),
|
||||||
|
'gyro': _format_vector(IMU_SENSOR.gyro, 'rad/s', 3),
|
||||||
|
'magnetic': _format_vector(IMU_SENSOR.magnetic, 'uT'),
|
||||||
|
'quaternion': _format_quaternion(IMU_SENSOR.quaternion),
|
||||||
|
'error': '',
|
||||||
|
}
|
||||||
|
except Exception as exc:
|
||||||
|
IMU_SENSOR = None
|
||||||
|
IMU_LAST_ERROR = str(exc)
|
||||||
|
return {
|
||||||
|
'state': 'unknown',
|
||||||
|
'status': 'Lesefehler',
|
||||||
|
'address': IMU_I2C_ADDRESS,
|
||||||
|
'acceleration': 'unbekannt',
|
||||||
|
'gyro': 'unbekannt',
|
||||||
|
'magnetic': 'unbekannt',
|
||||||
|
'quaternion': 'unbekannt',
|
||||||
|
'error': IMU_LAST_ERROR,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def read_cpu_temperature():
|
def read_cpu_temperature():
|
||||||
try:
|
try:
|
||||||
with open('/sys/class/thermal/thermal_zone0/temp', 'r', encoding='utf-8') as handle:
|
with open('/sys/class/thermal/thermal_zone0/temp', 'r', encoding='utf-8') as handle:
|
||||||
@@ -523,6 +653,7 @@ def collect_status():
|
|||||||
wifi_details = get_wifi_details()
|
wifi_details = get_wifi_details()
|
||||||
time_details = get_system_time_details()
|
time_details = get_system_time_details()
|
||||||
container_details = get_container_details(EXOMY_CONTAINER)
|
container_details = get_container_details(EXOMY_CONTAINER)
|
||||||
|
imu_details = read_imu_status()
|
||||||
return {
|
return {
|
||||||
'status': 'Bereit',
|
'status': 'Bereit',
|
||||||
'system': {
|
'system': {
|
||||||
@@ -563,7 +694,8 @@ def collect_status():
|
|||||||
'exomy': get_container_state(EXOMY_CONTAINER),
|
'exomy': get_container_state(EXOMY_CONTAINER),
|
||||||
'exomy_uptime': container_details['uptime'],
|
'exomy_uptime': container_details['uptime'],
|
||||||
'exomy_restarts': container_details['restarts'],
|
'exomy_restarts': container_details['restarts'],
|
||||||
}
|
},
|
||||||
|
'imu': imu_details,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user