Vom Kopter aus unter die Erde schauen

#1
Zur Zeit baue und programmiere ich einen Detektor, der Anomalien im Erdmagnetfeld vom Kopter aus aufzeichnen soll. Ich hatte schon im Kopterforum darüber berichtet. Da es aber stetig abbaut werde ich ab jetzt auch hier berichten.

Das wichtigste Bauteil ist ein Fluxgate Magnetometer. Seine Daten erfasse ich mit einem AD Wandler und trage sie als Farbfleck in Echtzeit in einen Videofeed ein. Die Position in der Landschaft wird durch ein relativ genaues GPS Modul bestimmt.
Zur Zeit ist die Konstruktion zum Löten und Programmieren auf einem Campingtisch angeordnet, den ich dann zum Testen durch die Gegend trage.
Die (Kurzzeit) Genauigkeit ist schon ganz gut, wie an den Screenshots zu sehen ist. Dazu trage ich den Tisch wenige Meter durch unsere Straße über eine Metallabdeckung von Regenrinnen, s. grüne Linie. Die beiden Screenshots unterscheiden sich durch die Art des (Brachial)- Differentiators. Auf dem Kopter werde ich es an einer unterirdischen Gaspipeline und Rohren zur Feldbewässerung testen.
Einen schönen Sonntag noch und
viele Grüße,
Wilhelm
 

Anhänge

Mayday

Expert somehow
#3
Coole Sache. Berichte mal weiter. Auch darüber, was Du damit vor hast.
Habe vor ein paar Jahren mehrer Copter gebaut, die auch Magnetometer durch die Gegend getragen haben. Allerdings Einsatz in ganz anderen Gebieten auf der Weltkugel...
Die Einheit wurde dann mit ein paar Metern Abstand unter dem Copter herumgeflogen. War wohl am besten und genauesten.
Aber letztlich kam von mir nur die fliegerische Plattform.
 
#4
Danke!
In erster Linie ist es mein Interesse an moderner Technik, das Projekt umzusetzen. So viel ich weis können die kommerziellen Geräte nur loggen und nicht die Daten in Echtzeit anzeigen. Ob und wie gut es funktioniert, muss sich noch zeigen.
Hier in der Gegend gibt es zum Testen eine dicke Gasleitung in ein paar Metern Tiefe, aber auch die unten gezeigten Strukturen unbekannter Herkunft werde ich dann überfliegen.
Viele Grüße,
Wilhelm
 

Anhänge

#5
Die Einheit wurde dann mit ein paar Metern Abstand unter dem Copter herumgeflogen. War wohl am besten und genauesten.
Darauf wird es wohl hinauflaufen.
Heute ist der Kopter mit montierter GPS Antenne und horizontalem Ausleger mit Dummy geflogen. Das GPS Modul ist mechanisch stabil. Die Stange vibriert im Schwebeflug leicht, wenn das Gewicht ganz außen sitzt.

Die horizontale Variante gefällt mir nun auch nicht mehr. Der Abstand zu den Motoren ist doch recht kurz. Nun probiere ich die Stange mit einem Tiltservo nach unten klappbar zu machen. Ein Problem ist nur, dass die Fernsteuerung beim Hochfahren einen Ruck macht. Ein Meter scheint mir auch etwas zu lang, s. Bild mit gelber Tonne. Das wird auch schwingen und ev zum Absturz führen.
Habt Ihr noch andere Vorschläge?

Ein Vorteil der Montage des Sensors unterhalb des Kopters ist noch, dass der horizontale Abstand zur GPS Antenne sehr gering wird.
Viele Grüße,
Wilhelm
 

Anhänge

LSG

Erfahrener Benutzer
#6
Sehr interessantes Projekt!

Warum den Sensor nicht einfach frei herunterhängend an einem Seil? Mit einem Federball/einer Windfahne stabilisiert er sich dann selbst im Vorwärtsflug.

Hast du eigentlich mal gemessen, welches Mangetfeld der Kopter erzeugt? Wie weit musst du davon entfernt sein, um störungsfrei messen zu können?

Die GPS-Koordinaten lassen sich doch nachträglich per Software korrigieren, wenn es wirklich so Zentimetergenau sein soll. Alternativ das Magnetfeld des GPS-Sensors vermessen und in geringstmöglichem Abstand zum Magnetometer montieren.

Was willst du eigentlich durch die Magnetfeldanomaliemessungen herausfinden/was kann man damit anstellen?

Und wieso macht die Fernsteuerung beim Hochfahren der Stange einen Ruck? Schlägt die Stange beim Hochfahren gegen deinen Kopf und du lässt die Fernsteuerung dann immer fallen? :D
 
#7
Danke,
du hast ja viele Fragen.
Zu 1) Ein Seil ist mir zu gefährlich. Ein Kopterbauer / Flieger, der damit Erfahrung hat, hat davon abgeraten. Man kann damit auch nicht schnell oder bei Wind fliegen.

Zu 2) Der Sensor war noch nicht am Kopter, aber ich werde verschiedene Konfigurationen (in der Luft) testen. Als erstes wird er unten am Landegestell montiert werden. Es braucht noch ein paar Tage…

Zu 3) Im Moment reicht mir die GPS Genauigkeit. Vielleicht beschäftige ich mich später mit RTK. Das GPS Modul beherrscht das, s. Link.
SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic) - GPS-16481 - SparkFun Electronics

Zu 4) siehe #4 oder Blindgänger könnte man damit suchen.

Zu 5) Mein N3 Controller macht nun mal einen Ruck, was ev. zur Zerstörung des Sensors oder des Kopters führen würde. Mein Kopf würde das überstehen.

Viele Grüße,
Wilhelm
 

Elyot

Erfahrener Benutzer
#8
Zu 5) Servo nicht an den N3, sondern direkt an den Empfänger? Alternativ einen Arduino dazwischen, der das Signal für das Servo in eine Softrampe umwandelt.
 

LSG

Erfahrener Benutzer
#9
Zu 5) Ach so, der Flight Controller. Fernsteuerung ist ja nicht gleich Flugsteuerung, hatte ich falsch verstanden. Macht er den Ruck wegen elektrischer Störung oder wegen Schwerpunktverschiebung? Könntest den Servo entweder an ein BEC anschließen oder, falls mechanischer Urpsrung, mit einem kurzen Gegengewicht am anderen Ende der Stange arbeiten, dann sollte das bei passendem Schwerpunkt nicht mehr auftreten.

Zu 4) Ja da interessiert mich noch mehr. Wusste gar nicht, dass das geht. Werde mal noch im Netz schauen.

Zu 1) Such mal nach Paragliding Chase Cam. Da gibt es gute Beispiele, wie stabil so ein Gewicht am Seil in der Luft hängen kann, selbst bei sehr langen Seilen und langsamen Geschwindigkeiten. Die Geschwindigkeit von Gleitschirmen entspricht ja ungefähr den Betriebsgeschwindigkeiten deines Kopters. Bei schnellen Geschwindigkeiten wird es dann ja eher noch stabiler. Hab ich auch schon am Kopter getestet. Sehe da keine Gefahr. Entscheidend ist die richtige Masse im Verhältnis zur Seillänge. Ist natürlich nicht die optimalse Lösung und nur für den Fall gedacht, dass der Kopter zu starke Magnetfelder erzeugt und du große Abstände brauchst.
 
#10
Danke für Eure Tipps.
Der Empfänger ist die Lightbridge 2. Nur der N3 hat Ports.
Der N3 fährt in eine Endposition und dann auf den eingestellten Wert, wenn ich das richtig in Erinnerung habe. Das Servo bekommt einen eigenen BEC.
Viele Grüße,
Wilhelm
 
#11
Hier ist mein aktueller Code. Vielleicht möchte ja jemand einsteigen. Es ist eine Mischung aus Gstreamer, Python3 und Opencv. Das GPS Modul wird über die serielle Schnittstelle eingelesen, der ADC über I2C.
Meine (Programmier)Devise ist 80/20. Mit 20% Aufwand 80% Erfolg erzielen.
Viele Grüße,
Wilhelm


Code:
import numpy as np
import cv2
import pylibi2c
import time
import serial


i2c = pylibi2c.I2CDevice('/dev/i2c-1', 0x48)

##########Testprogramm für i2c Schnittstelle und ADS1015 12-Bit ADC - 4 Channel with Programmable Gain Amplifier
# Set delay
i2c.delay = 10

# Set flags
i2c.flags = pylibi2c.I2C_M_IGNORE_NAK


data = i2c.ioctl_read(0, 2)
print (data)
data = i2c.ioctl_read(1, 2)
print (data)
data = i2c.ioctl_read(2, 2)
print (data)
data = i2c.ioctl_read(3, 2)
print (data)
print('#######################')


i2c.write(1, b'\xc2\x83')     #Mode Control
i2c.delay = 10
c_data = i2c.ioctl_read(0, 2)
red = int.from_bytes(c_data, byteorder = 'big')
red = red // 128
print ('red  ', red)

i2c.write(1, b'\xd2\x83')     #Mode Control
i2c.delay = 10
d_data = i2c.ioctl_read(0, 2)
green = int.from_bytes(d_data, byteorder = 'big')
green = green // 128
print ('green  ', green)

i2c.write(1, b'\xe2\x83')     #Mode Control
i2c.delay = 10
e_data = i2c.ioctl_read(0, 2)
blue = int.from_bytes(e_data, byteorder = 'big')
blue = blue // 128
print ('blue  ', blue)

i2c.write(1, b'\xf2\x83')     #Mode Control
i2c.delay = 10
f_data = i2c.ioctl_read(0, 2)
switch = int.from_bytes(f_data, byteorder = 'big')
switch = switch //128
print ('switch  ', switch)

print('#######################')

i2c.write(1, b'\x85\x83')     #Mode Control
i2c.delay = 10
data = i2c.ioctl_read(0, 2)
print (data)
data = i2c.ioctl_read(1, 2)
print (data)
data = i2c.ioctl_read(2, 2)
print (data)
data = i2c.ioctl_read(3, 2)
print (data)

########################## Ende Testprogramm #########################################



cap0 = cv2.VideoCapture("videotestsrc pattern = 2 ! video/x-raw, framerate=1/1, width=1920, height=1080 ! nvvidconv ! videoconvert ! video/x-raw, format=(string)BGR ! appsink", cv2.CAP_GSTREAMER)

winname = "Resultat"
#cv2.namedWindow(winname, cv2.WND_PROP_FULLSCREEN)
#cv2.moveWindow(winname, 0, 0)
#cv2.setWindowProperty(winname, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

#ser = serial.Serial("/dev/ttyUSB0",9600,8)      # UART - USB Adapter
ser = serial.Serial("/dev/ttyACM0", 9600)        # UART - USB Kabel 
#ser = serial.Serial("/dev/ttyTHS1", 9600)       # UART über Pins
ret, bg = cap0.read()

alt_center_coordinate = (0, 0)  9.9.2020
black = (0, 0, 0)
savered = 0
savegreen = 0
saveblue = 0
f = 8
counter = 0

altx=0
alty=0
i=0
gain=500.0

anzsat =('AN')
anzsatgl =('AL')
anzsatga =('AG')
anzsatgb =('AB')
ser.close()

ser.open()
ser.flushOutput()
ser.flushInput()
for j in range (1,10):
    data = ser.readline()     #Flush, Buffer leeren
    print (data)

while cap0.isOpened():

    data = ser.readline()
  #  print (data)
  #  Testzeile für FPS
  #  data = (b'$GNRMC,113312.50,A,515n.nnnnn,N,0065n.nnnnn,E,0.059,,090820,,,A,V*12\r\n') Koordinaten verändert
    c = data[1:6]
    cc = c.decode('UTF-8')
    if (cc == 'GPGSV'):     #Anzahl Satelliten GPS
        anz = data[11:13]
        anzsat = anz.decode('UTF-8')
#       print (data)
    if (cc == 'GLGSV'):     ##Anzahl Satelliten GLONASS
        anzgl = data[11:13]
        anzsatgl = anzgl.decode('UTF-8')
#       print (data)
    if (cc == 'GAGSV'):     ##Anzahl Satelliten Galileo
        anzga = data[11:13]
        anzsatga = anzga.decode('UTF-8')
  #      print (data)
    if (cc == 'GBGSV'):     ##Anzahl Satelliten BeiDou
        anzgb = data[11:13]
        anzsatgb = anzgb.decode('UTF-8')
  #      print (data)
    if (cc == 'GNRMC'):   # Datenzeile Uhrzeit, Koordinaten
        A = data[19:29]
        N = data[32:43]
        s = A.decode('UTF-8')
        try:
            x= float(s)
        except:
             x =10
        s = N.decode('UTF-8')
        try:
            y= float(s)
        except:
            y = 10
        x = x *111.3
        y = y * 71.5
#        print (x,' float A, N  ',y)
    
        i = i+1
        if (i == 2):               #Homepunkt, Startpunkt speichern
            altx = x
            alty = y

        if (i > 2):
            nx = (altx - x) * gain + 540      # ~Mitte
            ny = (y - alty) * gain + 900
#           print (nx, '  nx, ny  ',ny)
            inx = int (nx)
            iny = int (ny)
  #          print (inx, '  inx, iny  ',iny)
            if (iny > 1900):                        #Margins y = x-Achse!!
                iny = 1900
            if (iny < 1):
                iny = 1     
            if (inx > 1060):
                inx = 1060
            if (inx < 1):
                inx = 1
  #############################
            i2c.write(1, b'\xc2\x83')     #Mode Control    C
            i2c.delay = 1
            c_data = i2c.ioctl_read(0, 2)
            red = int.from_bytes(c_data, byteorder = 'big')
            red = red // 128

            i2c.write(1, b'\xd2\x83')     #Mode Control   D
            i2c.delay = 1
            d_data = i2c.ioctl_read(0, 2)
            green = int.from_bytes(d_data, byteorder = 'big')
            green = green // 128

            i2c.write(1, b'\xe2\x83')     #Mode Control  E
            i2c.delay = 1
            e_data = i2c.ioctl_read(0, 2)
            blue = int.from_bytes(e_data, byteorder = 'big')
            blue = blue // 128

            i2c.write(1, b'\xf2\x83')     #Mode Control  F
            i2c.delay = 1
            f_data = i2c.ioctl_read(0, 2)
            switch = int.from_bytes(f_data, byteorder = 'big')
            switch = switch //128
   #         print (red,'  ',green,'  ',blue,'  ', switch)
            if (switch  > 150):   # > 150 ok
                while switch > 150:
                    i2c.write(1, b'\xf2\x83')     #Mode Control  F
                    i2c.delay = 1
                    f_data = i2c.ioctl_read(0, 2)
                    switch = int.from_bytes(f_data, byteorder = 'big')
                    switch = switch //128         
#                altx = x
#                alty = y
                i = 0
                print(' Neustart ')
                ret, bg = cap0.read()
                if (gain == 5000):
                    gain = 500
                    center_coordinate = (1000,150)      # Kreis
                    radius = 60
                    color = (0,0,255)
                    thickness = -1
                    bg = cv2.circle(bg, center_coordinate, radius, color, thickness)
                else:
                    gain = 5000
                    center_coordinate = (1000,150)      # Kreis
                    radius = 60
                    color = (0,255,0)
                    thickness = -1
                    bg = cv2.circle(bg, center_coordinate, radius, color, thickness)
      
  #############################
            center_coordinate = (iny, inx)      # Kreis
            radius = 10
            thickness = -1
            if (i == 3):               # Differenzierer reset
                savered = red
                savegreen = green
                saveblue = blue         
            
            mod_red=(savered-red) * f +128
            if mod_red > 255 or mod_red < 0:
                savered = red
                print (' rot neu ')
            mod_green=(savegreen-green) * f +128
            if mod_green > 255 or mod_green < 0:
                savegreen = green
                print (' grün neu ')
            mod_blue =(saveblue-blue) * f +128
            if mod_blue > 255 or mod_blue < 0:
                saveblue = blue
                print (' blau neu ')

  #          print (mod_red,'  ',mod_green,'  ',mod_blue,' Mod ')
            if (switch  < 10): # Spur löschen, nur aktuellen Punkt zeigen
                bg = cv2.circle(bg, alt_center_coordinate, radius, black, thickness)
                # hier Differenzierer reset ?
            color = (mod_green, mod_red, mod_blue)
            bg = cv2.circle(bg, center_coordinate, radius, color, thickness)       #plot aktuellen Punkt

            alt_center_coordinate = center_coordinate

            start_point = (1160, 50) # Hintergrund Anz Sat
            end_point = (1500, 270)
            color = (0, 100, 150)
            thickness = -1
            bg = cv2.rectangle(bg, start_point, end_point, color, thickness)

            font = cv2.FONT_HERSHEY_SIMPLEX
            org = (1180, 100)
            fontScale = 1.5
            color = (255, 255, 255)
            thickness = 3
            sats = str(anzsat)
            satsout = ('GPS: ' + sats)
            bg = cv2.putText(bg, satsout , org, font, fontScale, color, thickness, cv2.LINE_AA)

            org = (1180, 150)
            fontScale = 1.5
            color = (255, 255, 255)
            thickness = 3
            sats = str(anzsatgl)
            satsout = ('GLONASS: ' + sats)
            bg = cv2.putText(bg, satsout , org, font, fontScale, color, thickness, cv2.LINE_AA)

            org = (1180, 200)
            fontScale = 1.5
            color = (255, 255, 255)
            thickness = 3
            sats = str(anzsatga)
            satsout = ('Galileo: ' + sats)
            bg = cv2.putText(bg, satsout , org, font, fontScale, color, thickness, cv2.LINE_AA)

            org = (1180, 250)
            fontScale = 1.5
            color = (255, 255, 255)
            thickness = 3
            sats = str(anzsatgb)
            satsout = ('Beidou: ' + sats)
            bg = cv2.putText(bg, satsout , org, font, fontScale, color, thickness, cv2.LINE_AA)
            counter += 1
            print("Sekunde: ", time.strftime("%S"),"Count:",counter)

    cv2.imshow(winname, bg)
    keyCode = cv2.waitKey(30) & 0xFF
    if keyCode == 27:
        break

        cap0.release()
        cap1.release()
        cv2.destroyAllWindows()
 
Zuletzt bearbeitet:
#12
Ein kleines Update zur Stange. Sie läuft nun unten am Landegestell an. Dadurch wird sie stabilisiert und schwingt nicht mehr. So sind auch Sensor und GPS horizontal gesehen nahe beieinander. Der Abstand zum Kopter sollte erst mal reichen. Auf YT habe ich ein Video gesehen, wonach auch mit kürzerem Abstand geflogen wird.
Die Stange wird über ein Poti gesteuert, so dass sich auch (in Grenzen) der Einfluss des Abstandes testen läßt.
Viele Grüße,
Wilhelm
 

Anhänge

#13
Ein wirklich spannendes Projekt! Vielen dank fürs teilen. Ich hätte auch Bock sowas umzusetzen, hauptsächlich um Hohlräume unter der Erde aufzudecken. Leider befürchte ich dass mir die Zeit dafür fehlt. Umso mehr freue ich mich dein Projekt verfolgen zu können.
 
#14
Danke Matthias.
Wenn es gut funktioniert und jemand möchte es nachbauen, helfe ich gerne. Viel Zeit hat das Einarbeiten in den Gstreamer für ein anders Projekt (s. Bild und Link Seite 9 und 10) gekostet, so dass es hier relativ schnell ging. Eigentlich sollte es ein Winterprojekt werden, aber es hat mir keine Ruhe gelassen.
Viele Grüße,
Wilhelm
NIR-FPV (Nahes InfraRot) mit dem Kopter
 

Anhänge

#15
Nun habe ich ein paar Tests gemacht und auch neue Erkenntnisse für Änderungen gewonnen. Der lange Stab war noch nicht montiert und man braucht ihn auch wohl nicht. Scheinbar stören die Motoren und die Elektronik nicht.
Da Geschwindigkeitsänderungen Drehungen um die Nick-Achse verursachen und damit bei starrem Sensor Magnetfeldänderungen vortäuschen, ist es in meinem Fall wohl wichtiger, die Nick-Achse des Sensors zu stabilisieren. Das probiere ich dann als Nächstes.
Die Screenshots zeigen einmal Überflüge über unserem Flugplatz und zweimal über eine Wiese mit einer Gaspipeline in geschätzt 3-4 m Tiefe. Sie läuft von Süd-Ost nach Nord-West, etwa wie eingezeichnet.
Mit einem Schalter lässt sich zwischen 2 Suchfeldgrößen umschalten. Dabei wird der Bildschirm gelöscht und der Homepunkt neu gesetzt.
Mit einem weiteren Schalter lässt sich die Spur abschalten. Man sieht dann nur den Punkt, der allerdings wie ein Radiergummi wirkt. Mit der Funktion kann man zB neu ansetzen, ohne dass der Rückflug sichtbar ist.
Viele Grüße,
Wilhelm
 

Anhänge

#16
Kleines Update:
Die nächste Revision ist zur Zeit in Arbeit: Die Antenne wird durch eine leichtere ersetzt und anstatt des Servos für die Stange baue ich nun ein Tiltservo für den Sensor ein.
Dazu kam heute ein kleines, schnelles Servo an, dass zur Ansteuerung lediglich eine alte NAZA V2 und 5 V benötigt, s. Bild. Die NAZA muss man natürlich vorher einstellen.
Ich hoffe, dass ich so vorwärts, rückwärts und mit wechselnder Geschwindigkeit fliegen kann, ohne dass sich die Messwerte (Farben) groß ändern. Einen Tiltwinkel wie auf dem Schnappschuss von heute muss die Regelung aber nicht ausgleichen können.
Den Homepunkt will ich noch wählbar machen, so dass er nicht nur in der Bildmitte, sondern auch an beliebigen Rändern des Suchfelds liegen kann.
Viele Grüße,
Wilhelm
 

Anhänge

RCLogger

FPV1

Banggood

Banggood

Oben