kopia lustrzana https://github.com/ogre/pizero_tracker
Porównaj commity
14 Commity
Autor | SHA1 | Data |
---|---|---|
Michal Fratczak | 5be2df2e68 | |
Michal Fratczak | 42cb4efc45 | |
Michal | 546eed4244 | |
Michal Fratczak | 1127777f86 | |
Michal Fratczak | 43a409a0fb | |
Michal Fratczak | b6bce14496 | |
Michal Fratczak | cb6bb631e2 | |
Michal Fratczak | 1d7058455b | |
Michal Fratczak | 206e484462 | |
Michal Fratczak | 8f6d03f1b7 | |
Michal Fratczak | 15c2b81d6e | |
Michal Fratczak | cf2317fe6a | |
Michal Fratczak | 6ffcfdb1cd | |
Michal Fratczak | 285a2bf80a |
28
Readme.md
28
Readme.md
|
@ -1,6 +1,6 @@
|
|||
## I2C
|
||||
|
||||
|
||||
You need to use software driver to I2c, and therefore, disable bluetooth. This is for rPI 3 and up.
|
||||
You need to use software driver to I2C, and therefore, disable bluetooth. This is for rPI 3 and up.
|
||||
|
||||
[https://raspberrypi.stackexchange.com/questions/45570/how-do-i-make-serial-work-on-the-raspberry-pi3-or-later-model]
|
||||
|
||||
|
@ -19,26 +19,46 @@ dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3
|
|||
```
|
||||
|
||||
|
||||
dependencies
|
||||
## Dependencies
|
||||
|
||||
SSDV:
|
||||
|
||||
git submodule update --init --recursive
|
||||
|
||||
---
|
||||
sudo apt-get install libboost-program-options-dev
|
||||
|
||||
---
|
||||
git clone https://github.com/zeromq/libzmq.git
|
||||
|
||||
build with cmake
|
||||
|
||||
---
|
||||
git clone https://github.com/zeromq/cppzmq.git
|
||||
|
||||
build with cmake
|
||||
|
||||
---
|
||||
http://abyz.me.uk/rpi/pigpio/download.html
|
||||
```
|
||||
wget https://github.com/joan2937/pigpio/archive/master.zip
|
||||
unzip master.zip
|
||||
cd pigpio-master
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
---
|
||||
pip3 install zmq exifread picamera psutil
|
||||
|
||||
sudo apt-get install imagemagick
|
||||
|
||||
run on one thread:
|
||||
## Run on one thread:
|
||||
|
||||
```
|
||||
taskset -c 1 ./tracker
|
||||
```
|
||||
|
||||
|
||||
## MTX2 datasheet
|
||||
http://www.radiometrix.com/files/additional/mtx2.pdf
|
||||
|
|
|
@ -173,20 +173,24 @@ def SetCameraExif(camera, state):
|
|||
|
||||
|
||||
def StateLoop(port):
|
||||
'''
|
||||
query tracker over ZMQ
|
||||
ask for: nmea_current, dynamics, flight_state
|
||||
save in global STATE dictionary
|
||||
'''
|
||||
REQUEST_TIMEOUT = 3000
|
||||
REQUEST_RETRIES = 1e30
|
||||
SERVER_ENDPOINT = "tcp://localhost:" + str(port)
|
||||
|
||||
global STATE
|
||||
|
||||
|
||||
print("Connecting to " + SERVER_ENDPOINT)
|
||||
context = zmq.Context(1)
|
||||
client = context.socket(zmq.REQ)
|
||||
client.connect(SERVER_ENDPOINT)
|
||||
poll = zmq.Poller()
|
||||
poll.register(client, zmq.POLLIN)
|
||||
query_msgs = ['nmea', 'dynamics', 'flight_state']
|
||||
query_msgs = ['nmea_current', 'dynamics', 'flight_state']
|
||||
|
||||
retries_left = REQUEST_RETRIES
|
||||
while THREADS_RUN and retries_left:
|
||||
|
@ -231,7 +235,6 @@ def StateLoop(port):
|
|||
context.term()
|
||||
|
||||
|
||||
|
||||
def SSDV_DeliverLoop(callsign, out_ssdv_path, res):
|
||||
'''
|
||||
picks last image from PHOTO_ARR, converts to SSDV and copies to output
|
||||
|
@ -251,6 +254,7 @@ def SSDV_DeliverLoop(callsign, out_ssdv_path, res):
|
|||
time.sleep(5)
|
||||
|
||||
if not PHOTO_ARR:
|
||||
print('SSDV_DeliverLoop - PHOTO_ARR empty.')
|
||||
continue
|
||||
|
||||
if os.path.isfile(out_ssdv_path):
|
||||
|
@ -270,7 +274,11 @@ def SSDV_DeliverLoop(callsign, out_ssdv_path, res):
|
|||
pass
|
||||
|
||||
|
||||
def next_path(i_base, ext = ''): # get next subdir/subfile
|
||||
def next_path(i_base, ext = ''):
|
||||
'''
|
||||
for a directory filled with subdirs or files named like: 000001, 000002, 000003
|
||||
get next dir/file that does not exist yet
|
||||
'''
|
||||
if ext and ext[0] != '.':
|
||||
ext = '.' + ext
|
||||
i = 1
|
||||
|
@ -313,39 +321,67 @@ def CameraLoop(session_dir, opts):
|
|||
global PHOTO_ARR
|
||||
|
||||
snapshot_time = datetime.fromtimestamp(0)
|
||||
hires_photo_time = datetime.fromtimestamp(0)
|
||||
|
||||
alt = 0
|
||||
dAlt = 0
|
||||
dAltAvg = 0
|
||||
global THREADS_RUN
|
||||
while(THREADS_RUN):
|
||||
|
||||
# camera can cause interference to GPS resulting in FIX loss
|
||||
# monitor FIX age and disable camera for 5 minutes
|
||||
if 'nmea_current' in STATE and 'fixAge' in STATE['nmea_current']:
|
||||
fixage = int( STATE['nmea_current']['fixAge'] )
|
||||
if fixage > 180:
|
||||
print('GPS FIX lost. Stop Camera and wait.')
|
||||
CAMERA.stop_preview()
|
||||
while fixage > 180:
|
||||
print('fixage', fixage)
|
||||
time.sleep(5)
|
||||
fixage = int( STATE['nmea_current']['fixAge'] )
|
||||
print("GPS fix reacquired. Waiting 5 minutes to start camera.")
|
||||
time.sleep(5 * 60)
|
||||
|
||||
disk_use_percent = int( psutil.disk_usage('/').percent )
|
||||
if disk_use_percent > 95:
|
||||
CAMERA.stop_preview()
|
||||
print("Free disk space left: ", disk_use_percent, '% . Waiting.')
|
||||
CAMERA.stop_preview()
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
if 'flight_state' in STATE and STATE['flight_state']['flight_state'] == 'kLanded':
|
||||
CAMERA.stop_preview()
|
||||
print("flight_state::klanded - stop camera and wait.")
|
||||
CAMERA.stop_preview()
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
CAMERA.start_preview()
|
||||
|
||||
# full res photo
|
||||
print("Photo HI")
|
||||
CAMERA.resolution = (3280, 2464)
|
||||
SetCameraExif(CAMERA, STATE)
|
||||
CAMERA.annotate_text = ''
|
||||
CAMERA.capture( next_path(photo_hi_dir, 'jpeg'))
|
||||
# make full res photo before recording next clip. not more often than 60 secs.
|
||||
hires_photo_path = None
|
||||
if seconds_since(hires_photo_time) > 60:
|
||||
print("Photo HI")
|
||||
CAMERA.start_preview()
|
||||
CAMERA.resolution = (2592 , 1944 ) # v1
|
||||
# CAMERA.resolution = (3280, 2464) # v2
|
||||
SetCameraExif(CAMERA, STATE)
|
||||
CAMERA.annotate_text = ''
|
||||
hires_photo_path = next_path(photo_hi_dir, 'jpeg')
|
||||
CAMERA.capture( hires_photo_path )
|
||||
CAMERA.stop_preview()
|
||||
hires_photo_time = utcnow()
|
||||
|
||||
# do not record video in standby mode
|
||||
# instead send hires_photo_path to SSDV
|
||||
if 'flight_state' in STATE and STATE['flight_state']['flight_state'] == 'kStandBy':
|
||||
CAMERA.stop_preview()
|
||||
print("flight_state::kStandBy - skip video recording. Send HiRes to SSDV.")
|
||||
PHOTO_ARR.append( hires_photo_path )
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
# video clip
|
||||
print("Video")
|
||||
video_duration_secs = int( opts['cam_video_dur'] )
|
||||
snapshot_interval_secs = int( opts['cam_snapshot_interval'] )
|
||||
CAMERA.start_preview()
|
||||
CAMERA.resolution = (1280, 720)
|
||||
CAMERA.start_recording( next_path(video_dir, 'h264'))
|
||||
|
||||
|
@ -355,12 +391,23 @@ def CameraLoop(session_dir, opts):
|
|||
if not THREADS_RUN:
|
||||
break
|
||||
|
||||
disk_use_percent = int( psutil.disk_usage('/').percent )
|
||||
if disk_use_percent > 95:
|
||||
fixage = 0
|
||||
if 'nmea_current' in STATE and 'fixAge' in STATE['nmea_current']:
|
||||
fixage = int( STATE['nmea_current']['fixAge'] )
|
||||
if fixage > 180:
|
||||
print("GPS FIX lost - stop camera.")
|
||||
CAMERA.stop_preview()
|
||||
print("Free disk low - abort camera.")
|
||||
break
|
||||
|
||||
disk_use_percent = int( psutil.disk_usage('/').percent )
|
||||
if disk_use_percent > 95:
|
||||
print("Free disk low - abort camera.")
|
||||
CAMERA.stop_preview()
|
||||
break
|
||||
|
||||
alt = 0
|
||||
dAlt = 0
|
||||
dAltAvg = 0
|
||||
if 'dynamics' in STATE and 'alt' in STATE['dynamics']:
|
||||
alt = STATE['dynamics']['alt']['val']
|
||||
dAlt = STATE['dynamics']['alt']['dVdT']
|
||||
|
@ -372,9 +419,10 @@ def CameraLoop(session_dir, opts):
|
|||
|
||||
if seconds_since(snapshot_time) > snapshot_interval_secs:
|
||||
print("Photo LO")
|
||||
PHOTO_ARR.append( next_path(photo_lo_dir, 'jpg') )
|
||||
CAMERA.capture( PHOTO_ARR[-1] , use_video_port = True )
|
||||
img_path = next_path(photo_lo_dir, 'jpg')
|
||||
CAMERA.capture( img_path , use_video_port = True )
|
||||
snapshot_time = utcnow()
|
||||
PHOTO_ARR.append( img_path )
|
||||
|
||||
time.sleep(1)
|
||||
CAMERA.stop_recording()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
IMPORTANT:
|
||||
Powering to 3.3V from a regulator does not work here.
|
||||
Instead, use 5V regulator and connect to 5V pin.
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE eagle SYSTEM "eagle.dtd">
|
||||
<eagle version="9.4.2">
|
||||
<eagle version="9.6.2">
|
||||
<drawing>
|
||||
<settings>
|
||||
<setting alwaysvectorfont="no"/>
|
||||
|
@ -1629,7 +1629,7 @@ design rules under a new name.</description>
|
|||
<param name="PrefDir.13" value="0"/>
|
||||
<param name="PrefDir.14" value="0"/>
|
||||
<param name="PrefDir.15" value="0"/>
|
||||
<param name="PrefDir.16" value="0"/>
|
||||
<param name="PrefDir.16" value="a"/>
|
||||
<param name="cfVia" value="8"/>
|
||||
<param name="cfNonPref" value="5"/>
|
||||
<param name="cfChangeDir" value="2"/>
|
||||
|
@ -1704,9 +1704,9 @@ design rules under a new name.</description>
|
|||
</pass>
|
||||
</autorouter>
|
||||
<elements>
|
||||
<element name="3V3_REGULATOR" library="pinhead" library_urn="urn:adsk.eagle:library:325" package="1X03" package3d_urn="urn:adsk.eagle:package:22458/2" value="3.3" x="27.94" y="11.43" smashed="yes">
|
||||
<attribute name="POPULARITY" value="92" x="53.34" y="-36.83" size="1.778" layer="27" display="off"/>
|
||||
<attribute name="VALUE" x="31.75" y="9.525" size="1.27" layer="27"/>
|
||||
<element name="3V3_REGULATOR" library="pinhead" library_urn="urn:adsk.eagle:library:325" package="1X03" package3d_urn="urn:adsk.eagle:package:22458/2" value="3.3" x="29.94" y="11.43" smashed="yes">
|
||||
<attribute name="POPULARITY" value="92" x="55.34" y="-36.83" size="1.778" layer="27" display="off"/>
|
||||
<attribute name="VALUE" x="31.75" y="13.525" size="1.27" layer="27"/>
|
||||
</element>
|
||||
<element name="BATT" library="pinhead" library_urn="urn:adsk.eagle:library:325" package="1X02" package3d_urn="urn:adsk.eagle:package:22435/2" value="5" x="21.59" y="22.86" smashed="yes" rot="R90">
|
||||
<attribute name="POPULARITY" value="98" x="69.85" y="67.31" size="1.778" layer="27" rot="R90" display="off"/>
|
||||
|
@ -1780,9 +1780,6 @@ design rules under a new name.</description>
|
|||
<wire x1="50.8" y1="29.21" x2="54.61" y2="33.02" width="0.508" layer="16"/>
|
||||
<wire x1="43.815" y1="29.21" x2="50.8" y2="29.21" width="0.508" layer="16"/>
|
||||
<wire x1="54.61" y1="33.02" x2="54.77" y2="33.39" width="0.508" layer="16"/>
|
||||
<wire x1="27.94" y1="22.86" x2="27.94" y2="11.43" width="0.508" layer="16"/>
|
||||
<wire x1="23.495" y1="22.86" x2="27.94" y2="22.86" width="0.508" layer="16"/>
|
||||
<wire x1="22.225" y1="24.13" x2="23.495" y2="22.86" width="0.508" layer="16"/>
|
||||
<wire x1="72.39" y1="33.02" x2="68.58" y2="29.21" width="0.508" layer="16"/>
|
||||
<wire x1="68.58" y1="29.21" x2="67.31" y2="27.94" width="0.508" layer="16"/>
|
||||
<wire x1="72.39" y1="33.02" x2="72.55" y2="33.39" width="0.508" layer="16"/>
|
||||
|
@ -1799,19 +1796,21 @@ design rules under a new name.</description>
|
|||
<wire x1="59.055" y1="29.21" x2="55.245" y2="33.02" width="0.508" layer="16"/>
|
||||
<wire x1="68.58" y1="29.21" x2="59.055" y2="29.21" width="0.508" layer="16"/>
|
||||
<wire x1="55.245" y1="33.02" x2="54.77" y2="33.39" width="0.508" layer="16"/>
|
||||
<wire x1="29.6672" y1="16.6624" x2="29.6672" y2="11.7856" width="0.508" layer="16"/>
|
||||
<wire x1="22.352" y1="23.9776" x2="29.6672" y2="16.6624" width="0.508" layer="16"/>
|
||||
<wire x1="29.6672" y1="11.7856" x2="29.94" y2="11.43" width="0.508" layer="16"/>
|
||||
<wire x1="22.352" y1="23.9776" x2="21.59" y2="24.13" width="0.508" layer="16"/>
|
||||
<polygon width="0.1524" layer="1">
|
||||
<vertex x="13.97" y="41.91"/>
|
||||
<vertex x="13.97" y="6.35"/>
|
||||
<vertex x="83.82" y="6.35"/>
|
||||
<vertex x="85.09" y="7.62"/>
|
||||
<vertex x="85.09" y="41.91"/>
|
||||
<vertex x="15" y="42"/>
|
||||
<vertex x="15" y="7"/>
|
||||
<vertex x="82" y="7"/>
|
||||
<vertex x="82" y="42"/>
|
||||
</polygon>
|
||||
<polygon width="0.1524" layer="16">
|
||||
<vertex x="13.97" y="41.91"/>
|
||||
<vertex x="13.97" y="6.35"/>
|
||||
<vertex x="83.82" y="6.35"/>
|
||||
<vertex x="85.09" y="7.62"/>
|
||||
<vertex x="85.09" y="41.91"/>
|
||||
<vertex x="14" y="43"/>
|
||||
<vertex x="14" y="6"/>
|
||||
<vertex x="83" y="6"/>
|
||||
<vertex x="83" y="43"/>
|
||||
</polygon>
|
||||
</signal>
|
||||
<signal name="SDA">
|
||||
|
@ -1926,21 +1925,24 @@ design rules under a new name.</description>
|
|||
<wire x1="44.45" y1="24.765" x2="42.545" y2="24.765" width="0.508" layer="16"/>
|
||||
<wire x1="45.085" y1="24.765" x2="48.26" y2="27.94" width="0.508" layer="16"/>
|
||||
<wire x1="44.45" y1="24.765" x2="45.085" y2="24.765" width="0.508" layer="16"/>
|
||||
<wire x1="30.48" y1="21.59" x2="30.48" y2="11.43" width="0.508" layer="16"/>
|
||||
<wire x1="39.37" y1="21.59" x2="34.29" y2="21.59" width="0.508" layer="16"/>
|
||||
<wire x1="34.29" y1="21.59" x2="30.48" y2="21.59" width="0.508" layer="16"/>
|
||||
<wire x1="34.29" y1="21.59" x2="34.29" y2="24.13" width="0.508" layer="16"/>
|
||||
<wire x1="34.29" y1="24.13" x2="34.29" y2="26.67" width="0.508" layer="16"/>
|
||||
<wire x1="24.765" y1="24.13" x2="24.765" y2="33.02" width="0.508" layer="16"/>
|
||||
<wire x1="34.29" y1="24.13" x2="24.765" y2="24.13" width="0.508" layer="16"/>
|
||||
<wire x1="24.765" y1="33.02" x2="24.29" y2="33.39" width="0.508" layer="16"/>
|
||||
<wire x1="32.512" y1="19.9136" x2="32.512" y2="11.7856" width="0.508" layer="16"/>
|
||||
<wire x1="34.1376" y1="21.5392" x2="32.512" y2="19.9136" width="0.508" layer="16"/>
|
||||
<wire x1="32.512" y1="11.7856" x2="32.48" y2="11.43" width="0.508" layer="16"/>
|
||||
<wire x1="34.1376" y1="21.5392" x2="34.29" y2="21.59" width="0.508" layer="16"/>
|
||||
</signal>
|
||||
<signal name="5V">
|
||||
<contactref element="3V3_REGULATOR" pad="1"/>
|
||||
<contactref element="BATT" pad="1"/>
|
||||
<wire x1="25.4" y1="20.955" x2="25.4" y2="11.43" width="0.508" layer="16"/>
|
||||
<wire x1="22.225" y1="20.955" x2="25.4" y2="20.955" width="0.508" layer="16"/>
|
||||
<wire x1="21.59" y1="21.59" x2="22.225" y2="20.955" width="0.508" layer="16"/>
|
||||
<wire x1="21.9456" y1="17.0688" x2="21.9456" y2="21.5392" width="0.508" layer="1"/>
|
||||
<wire x1="27.2288" y1="11.7856" x2="21.9456" y2="17.0688" width="0.508" layer="1"/>
|
||||
<wire x1="21.9456" y1="21.5392" x2="21.59" y2="21.59" width="0.508" layer="1"/>
|
||||
<wire x1="27.2288" y1="11.7856" x2="27.4" y2="11.43" width="0.508" layer="1"/>
|
||||
</signal>
|
||||
<signal name="N$7">
|
||||
<contactref element="R5" pad="2"/>
|
||||
|
|
Plik binarny nie jest wyświetlany.
|
@ -1,25 +1,25 @@
|
|||
EAGLE AutoRouter Statistics:
|
||||
|
||||
Job : /home/mfratczak/dev/Eagle/HabTrackerPiZero/HabTrackerPiZero_Shield_v304.brd
|
||||
|
||||
Start at : 21:19:28 (15.01.2020)
|
||||
End at : 21:19:30 (15.01.2020)
|
||||
Elapsed time : 00:00:01
|
||||
|
||||
Signals : 13 RoutingGrid: 16 mil Layers: 1
|
||||
Connections : 31 predefined: 28 ( 0 Vias )
|
||||
|
||||
Router memory : 104140
|
||||
|
||||
Passname : TopRouter Route Optimize1 Optimize2 Optimize3 Optimize4
|
||||
|
||||
Time per pass : 00:00:01 00:00:00 00:00:00 00:00:00 00:00:00 00:00:00
|
||||
Number of Ripups : 0 0 0 0 0 0
|
||||
max. Level : 0 0 0 0 0 0
|
||||
max. Total : 0 0 0 0 0 0
|
||||
|
||||
Routed : 3 3 3 3 3 3
|
||||
Vias : 0 0 0 0 0 0
|
||||
Resolution : 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 %
|
||||
|
||||
Final : 100.0% finished
|
||||
EAGLE AutoRouter Statistics:
|
||||
|
||||
Job : D:/dev/Projects/pizero_tracker/pizero_tracker/pcb/eagle/HabTrackerPiZero_Shield.brd
|
||||
|
||||
Start at : 22:29:04 (7/22/2020)
|
||||
End at : 22:29:09 (7/22/2020)
|
||||
Elapsed time : 00:00:02
|
||||
|
||||
Signals : 13 RoutingGrid: 16 mil Layers: 2
|
||||
Connections : 31 predefined: 28 ( 0 Vias )
|
||||
|
||||
Router memory : 208280
|
||||
|
||||
Passname : TopRouter Route Optimize1 Optimize2 Optimize3 Optimize4
|
||||
|
||||
Time per pass : 00:00:02 00:00:00 00:00:00 00:00:00 00:00:00 00:00:00
|
||||
Number of Ripups : 0 0 0 0 0 0
|
||||
max. Level : 0 0 0 0 0 0
|
||||
max. Total : 0 0 0 0 0 0
|
||||
|
||||
Routed : 3 3 3 3 3 3
|
||||
Vias : 0 0 0 0 0 0
|
||||
Resolution : 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 %
|
||||
|
||||
Final : 100.0% finished
|
||||
|
|
Plik binarny nie jest wyświetlany.
|
@ -32,6 +32,7 @@ private:
|
|||
GLOB& operator=( const GLOB& ) = delete; // non copyable
|
||||
|
||||
std::atomic<nmea_t> nmea_; // GPS data
|
||||
std::atomic<nmea_t> nmea_last_valid_; // GPS data - last valid
|
||||
std::chrono::steady_clock::time_point gps_fix_timestamp_;
|
||||
|
||||
// sensors dynamics
|
||||
|
@ -73,8 +74,16 @@ public:
|
|||
dynamics_t dynamics_get(const std::string& name) const;
|
||||
std::vector<std::string> dynamics_keys() const; // names in dynamics_
|
||||
|
||||
void nmea_set(const nmea_t& in_nmea) { get().nmea_ = in_nmea; }
|
||||
nmea_t nmea_get() { nmea_t ret = get().nmea_; return ret; }
|
||||
void nmea_set(const nmea_t& in_nmea) {
|
||||
get().nmea_ = in_nmea;
|
||||
if(in_nmea.valid()) {
|
||||
get().nmea_last_valid_ = in_nmea;
|
||||
get().gps_fix_now();
|
||||
}
|
||||
}
|
||||
|
||||
nmea_t nmea_current() { nmea_t ret = get().nmea_; return ret; }
|
||||
nmea_t nmea_last_valid() { nmea_t ret = get().nmea_last_valid_; return ret; }
|
||||
|
||||
void gps_fix_now() { gps_fix_timestamp_ = std::chrono::steady_clock::now(); }
|
||||
int gps_fix_age() const { return (std::chrono::steady_clock::now() - gps_fix_timestamp_).count() / 1e9; }
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "glob.h"
|
||||
#include "GLOB.h"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <algorithm>
|
||||
|
||||
|
||||
// utc_seconds is HHMMSS converted to seconds. return true if sample was accepted
|
||||
void dynamics_t::add(const tp timestamp, const float val)
|
||||
{
|
||||
val_ = val;
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
|
||||
bool initialised() const { return initialised_; }
|
||||
|
||||
void add(const tp timestamp, const float val); // utc_seconds is HHMMSS converted to seconds. return true if sample was accepted
|
||||
void add(const tp timestamp, const float val);
|
||||
|
||||
float val() const { return val_; }
|
||||
float min() const { return val_min_; }
|
||||
|
|
|
@ -78,8 +78,16 @@ std::string CRC(std::string i_str)
|
|||
zmq::message_t make_zmq_reply(const std::string& i_msg_str)
|
||||
{
|
||||
auto& G = GLOB::get();
|
||||
if(i_msg_str == "nmea") {
|
||||
std::string reply_str = G.nmea_get().json();
|
||||
if(i_msg_str == "nmea_current") {
|
||||
std::string reply_str = G.nmea_current().json();
|
||||
reply_str.pop_back();
|
||||
reply_str += ",'fixAge':" + std::to_string(G.gps_fix_age()) + "}";
|
||||
zmq::message_t reply( reply_str.size() );
|
||||
memcpy( (void*) reply.data(), reply_str.c_str(), reply_str.size() );
|
||||
return reply;
|
||||
}
|
||||
else if(i_msg_str == "nmea_last_valid") {
|
||||
std::string reply_str = G.nmea_last_valid().json();
|
||||
reply_str.pop_back();
|
||||
reply_str += ",'fixAge':" + std::to_string(G.gps_fix_age()) + "}";
|
||||
zmq::message_t reply( reply_str.size() );
|
||||
|
@ -270,21 +278,18 @@ int main1(int argc, char** argv)
|
|||
LOG.log("nmea.log", nmea_str);
|
||||
|
||||
nmea_t current_nmea;
|
||||
// REUSE LAT,LON,ALT FROM LAST VALID SENTENCE
|
||||
// if currently parsed NMEA string has valid lat/lon/alt
|
||||
// they will be stored in current_nmea
|
||||
// otherwise we keep last valid
|
||||
const nmea_t valid_nmea = GLOB::get().nmea_get();
|
||||
current_nmea.lat = valid_nmea.lat;
|
||||
current_nmea.lon = valid_nmea.lon;
|
||||
current_nmea.alt = valid_nmea.alt;
|
||||
if( NMEA_parse(nmea_str.c_str(), current_nmea) /*and current_nmea.valid()*/ ) {
|
||||
// RMC has no altitude, copy from last known value
|
||||
if( current_nmea.nmea_msg_type_ == nmea_t::nmea_msg_type_t::kRMC )
|
||||
current_nmea.alt = GLOB::get().nmea_current().alt;
|
||||
|
||||
if( NMEA_parse(nmea_str.c_str(), current_nmea) and current_nmea.valid() ) {
|
||||
GLOB::get().nmea_set(current_nmea);
|
||||
GLOB::get().gps_fix_now(); // typical time since uBlox msg read to here is under 1 millisecond
|
||||
GLOB::get().dynamics_add("alt", std::chrono::steady_clock::now(), current_nmea.alt);
|
||||
|
||||
if(current_nmea.valid())
|
||||
GLOB::get().dynamics_add("alt", std::chrono::steady_clock::now(), current_nmea.alt);
|
||||
// cout<<C_MAGENTA<<"alt "<<GLOB::get().dynamics_get("alt").str()<<C_OFF<<endl;
|
||||
}
|
||||
// else - parse error or no lock (even no time)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -293,7 +298,7 @@ int main1(int argc, char** argv)
|
|||
auto fake_gps_loop = [uBlox_i2c_fd]() {
|
||||
cout<<"Using FAKE GPS Coordinates !!!"<<endl;
|
||||
while(G_RUN) {
|
||||
const nmea_t valid_nmea = GLOB::get().nmea_get();
|
||||
const nmea_t valid_nmea = GLOB::get().nmea_current();
|
||||
nmea_t current_nmea;
|
||||
current_nmea.lat = valid_nmea.lat;
|
||||
current_nmea.lon = valid_nmea.lon;
|
||||
|
@ -363,7 +368,7 @@ int main1(int argc, char** argv)
|
|||
this_thread::sleep_for( chrono::seconds(1) );
|
||||
|
||||
GLOB::get().runtime_secs_ = chrono::duration_cast<chrono::seconds>(chrono::steady_clock::now() - START_TIME).count();
|
||||
const nmea_t nmea = GLOB::get().nmea_get();
|
||||
const nmea_t nmea = GLOB::get().nmea_last_valid();
|
||||
const auto dist_from_home = calc_gps_distance( nmea.lat, nmea.lon, nmea.alt,
|
||||
GLOB::get().cli.lat, GLOB::get().cli.lon, 0);
|
||||
const auto alt = GLOB::get().dynamics_get("alt");
|
||||
|
@ -373,14 +378,14 @@ int main1(int argc, char** argv)
|
|||
if(nmea.valid()) {
|
||||
if( abs(dist_from_home.dist_line_) < 200 and abs(dAltAvg) <= 3 )
|
||||
flight_state = flight_state_t::kStandBy;
|
||||
else if(dAltAvg < -8)
|
||||
flight_state = flight_state_t::kFreefall;
|
||||
else if(dAltAvg < -3)
|
||||
flight_state = flight_state_t::kDescend;
|
||||
else if(dAltAvg > 3)
|
||||
flight_state = flight_state_t::kAscend;
|
||||
else if( abs(dist_from_home.dist_line_) > 2000 and abs(dAltAvg) <= 3 and alt.val() < 2000 )
|
||||
flight_state = flight_state_t::kLanded;
|
||||
else if(dAltAvg < -15)
|
||||
flight_state = flight_state_t::kFreefall;
|
||||
else if(dAltAvg < 0)
|
||||
flight_state = flight_state_t::kDescend;
|
||||
else if(dAltAvg >= 0)
|
||||
flight_state = flight_state_t::kAscend;
|
||||
}
|
||||
// cout<<alt.val()<<" "<<alt.dVdT()<<" "<<alt.dVdT_avg()<<" "<<dist_from_home.dist_line_<<endl;
|
||||
GLOB::get().flight_state_set( flight_state );
|
||||
|
@ -466,14 +471,14 @@ int main1(int argc, char** argv)
|
|||
stringstream tlmtr_stream;
|
||||
|
||||
// Callsign, ID, UTC:
|
||||
const nmea_t valid_nmea = G.nmea_get();
|
||||
const nmea_t current_nmea = G.nmea_current();
|
||||
tlmtr_stream<<G.cli.callsign;
|
||||
tlmtr_stream<<","<<msg_id;
|
||||
tlmtr_stream<<","<<valid_nmea.utc;
|
||||
tlmtr_stream<<","<<current_nmea.utc;
|
||||
|
||||
// !! ONLY VALID LAT,LON,ALT ARE BEING SENT. LOOK INTO uBLOX THREAD.
|
||||
tlmtr_stream<<","<<valid_nmea.lat<<","<<valid_nmea.lon<<","<<valid_nmea.alt;
|
||||
tlmtr_stream<<","<<valid_nmea.sats<<","<<GLOB::get().gps_fix_age();
|
||||
tlmtr_stream<<","<<current_nmea.lat<<","<<current_nmea.lon<<","<<current_nmea.alt;
|
||||
tlmtr_stream<<","<<current_nmea.sats<<","<<GLOB::get().gps_fix_age();
|
||||
|
||||
// runtime
|
||||
tlmtr_stream<<","<<static_cast<int>(GLOB::get().runtime_secs_);
|
||||
|
|
|
@ -134,6 +134,8 @@ bool NMEA_parse(const char* Buffer, nmea_t& o_nmea)
|
|||
|
||||
if (strncmp(Buffer + 3, "GGA", 3) == 0) // Global positioning system fix data
|
||||
{
|
||||
o_nmea.nmea_msg_type_ = nmea_t::nmea_msg_type_t::kGGA;
|
||||
|
||||
int scanned_positions =
|
||||
sscanf(Buffer + 7, "%f,%f,%c,%f,%c,%d,%d,%f,%f,%c", &
|
||||
utc, &lat, &ns, &lon, &ew, &quality, &sats, &hdop, &alt, &alt_units);
|
||||
|
@ -175,6 +177,7 @@ bool NMEA_parse(const char* Buffer, nmea_t& o_nmea)
|
|||
o_nmea.fix_quality = nmea_t::fix_quality_t::kEstimated;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(scanned_positions > 0 && utc != 0)
|
||||
|
@ -191,6 +194,8 @@ bool NMEA_parse(const char* Buffer, nmea_t& o_nmea)
|
|||
} // GGA
|
||||
else if (strncmp(Buffer+3, "RMC", 3) == 0)
|
||||
{
|
||||
o_nmea.nmea_msg_type_ = nmea_t::nmea_msg_type_t::kRMC;
|
||||
|
||||
speedstring[0] = '\0';
|
||||
coursestring[0] = '\0';
|
||||
int scanned_positions =
|
||||
|
@ -338,8 +343,9 @@ int nmea_t::utc_as_seconds() const
|
|||
|
||||
bool nmea_t::valid() const
|
||||
{
|
||||
// only one at a time can be valid.
|
||||
// fix_status is from RMC, fix_quality is from GGA
|
||||
return fix_status == fix_status_t::kValid
|
||||
or fix_quality != fix_quality_t::kNoFix;
|
||||
if(nmea_msg_type_ == nmea_msg_type_t::kGGA and fix_quality != fix_quality_t::kNoFix)
|
||||
return true;
|
||||
if(nmea_msg_type_ == nmea_msg_type_t::kRMC and fix_status == fix_status_t::kValid)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,26 +5,23 @@
|
|||
|
||||
|
||||
// keep data parsed from GGA __and__ RMC messages
|
||||
// http://aprs.gids.nl/nmea/#rmc
|
||||
// http://aprs.gids.nl/nmea/#gga
|
||||
|
||||
class nmea_t
|
||||
{
|
||||
public:
|
||||
// fields provided by both GGA and RMC messages:
|
||||
//
|
||||
char utc[6] = {'0', '0', '0', '0', '0', '0'}; // HHMMSS
|
||||
|
||||
float lat = 0; // degree
|
||||
float lon = 0; // degree
|
||||
|
||||
// GGA message fields:
|
||||
//
|
||||
float alt = 0; // meters
|
||||
|
||||
float speed_over_ground_mps = 0;
|
||||
float course_over_ground_deg = 0;
|
||||
|
||||
int sats = 0;
|
||||
|
||||
enum class fix_status_t : int {
|
||||
kInvalid=0, // V
|
||||
kValid=1 // A
|
||||
};
|
||||
fix_status_t fix_status = fix_status_t::kInvalid;
|
||||
|
||||
enum class fix_quality_t : int {
|
||||
kNoFix = 0,
|
||||
kAutonomous = 1,
|
||||
|
@ -35,6 +32,25 @@ public:
|
|||
};
|
||||
fix_quality_t fix_quality = fix_quality_t::kNoFix;
|
||||
|
||||
|
||||
// RMC message fields:
|
||||
//
|
||||
float speed_over_ground_mps = 0;
|
||||
float course_over_ground_deg = 0;
|
||||
enum class fix_status_t : int {
|
||||
kInvalid=0, // V
|
||||
kValid=1 // A
|
||||
};
|
||||
fix_status_t fix_status = fix_status_t::kInvalid;
|
||||
|
||||
enum class nmea_msg_type_t : int {
|
||||
kUnknown = 0,
|
||||
kGGA = 1,
|
||||
kRMC = 2
|
||||
};
|
||||
nmea_msg_type_t nmea_msg_type_ = nmea_msg_type_t::kUnknown;
|
||||
|
||||
|
||||
std::string str() const;
|
||||
std::string json() const;
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# tracker options
|
||||
#
|
||||
callsign = setcallsign
|
||||
freq = 434.5
|
||||
baud = 300
|
||||
port = 6666
|
||||
ssdv = /tracker/ssdv.bin
|
||||
logsdir = /tracker/logs/
|
||||
# number of telemetry packets to send before SSDV packet
|
||||
msg_num = 3
|
||||
# launch location
|
||||
latlonalt = 52.1120009
|
||||
latlonalt = 19.957789
|
||||
latlonalt = 100
|
||||
# enable watchdog
|
||||
watchdog = 1
|
||||
|
||||
# hardware configuration
|
||||
#
|
||||
hw_pin_radio_on = 22
|
||||
hw_radio_serial = /dev/serial0
|
||||
#pi4
|
||||
#hw_ublox_device = /dev/i2c-7
|
||||
#pi0
|
||||
hw_ublox_device = /dev/i2c-3
|
||||
|
||||
# camera
|
||||
#
|
||||
cam_dir = /tracker/camera
|
||||
cam_flip_h = 0
|
||||
cam_flip_v = 0
|
||||
# SSDV image resolution
|
||||
cam_ssdv_res = 128
|
||||
# video clip duration in minutes
|
||||
cam_video_dur = 15
|
||||
# photo snapshot interval in seconds
|
||||
cam_snapshot_interval = 30
|
Ładowanie…
Reference in New Issue