sgslib 1.7.1 → 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/sgs/alarm.rb +34 -34
- data/lib/sgs/bearing.rb +1 -1
- data/lib/sgs/diagnostics.rb +1 -1
- data/lib/sgs/gps.rb +7 -2
- data/lib/sgs/location.rb +3 -3
- data/lib/sgs/mission.rb +9 -6
- data/lib/sgs/navigate.rb +52 -26
- data/lib/sgs/nmea.rb +1 -1
- data/lib/sgs/otto.rb +24 -9
- data/lib/sgs/redis_base.rb +2 -2
- data/lib/sgs/report.rb +1 -1
- data/lib/sgs/version.rb +1 -1
- data/lib/sgs/waypoint.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b772fccd0d24dd037a52734c72ef29a5203f5e32bbad85a47b4d8b16985c507
|
4
|
+
data.tar.gz: f717f8defef045a95408bbe34217bb8bf60f6ae802e5ddf95d4ff08dc223b8ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 739c91c93129d8da5e9271d10d9debe893746c10601fa206efa734498d6cc991ebcf0da3b9462d0f1a0a99eaf054e2ffa5e1b984832445b161b39026fcab8396
|
7
|
+
data.tar.gz: f546060ce3000f7d1c65ca079095863431bcd7b9ed2b2f997a30ac238cdfb8acfb28e1ca2822d586b9eab5058e711528619ab7f171daa60e4f304d1ed4d8197d
|
data/lib/sgs/alarm.rb
CHANGED
@@ -46,25 +46,25 @@ module SGS
|
|
46
46
|
|
47
47
|
#
|
48
48
|
# Alarms generated by Otto.
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
49
|
+
OTTO_RESTART = 0
|
50
|
+
MISSION_SWITCH = 1
|
51
|
+
RUDDER_FAULT = 2
|
52
|
+
SAIL_FAULT = 3
|
53
|
+
BATTERY_FAULT = 4
|
54
|
+
SOLAR_FAULT = 5
|
55
|
+
COMPASS_FAULT = 6
|
56
|
+
ACCEL_FAULT = 7
|
57
|
+
WDI_FAULT = 8
|
58
|
+
MOTHER_UNRESP = 9
|
59
|
+
RESERVED1 = 10
|
60
|
+
RESERVED2 = 11
|
61
|
+
RESERVED3 = 12
|
62
|
+
RESERVED4 = 13
|
63
|
+
RESERVED5 = 14
|
64
|
+
RESERVED6 = 15
|
65
65
|
#
|
66
66
|
# Alarms generated by Mother.
|
67
|
-
|
67
|
+
OTTO_FAULT = 16
|
68
68
|
MISSION_COMMENCE = 17
|
69
69
|
MISSION_COMPLETE = 18
|
70
70
|
MISSION_ABORT = 19
|
@@ -73,23 +73,23 @@ module SGS
|
|
73
73
|
INSIDE_FENCE = 22
|
74
74
|
|
75
75
|
ALARM_NAMES = [
|
76
|
+
"OTTO Restarted Unexpectedly",
|
76
77
|
"Mission Activation Switch",
|
77
|
-
"Rudder
|
78
|
-
"Sail
|
79
|
-
"Battery
|
80
|
-
"
|
81
|
-
"
|
82
|
-
"
|
83
|
-
"
|
84
|
-
"
|
85
|
-
"
|
86
|
-
"
|
87
|
-
"
|
88
|
-
"
|
89
|
-
"
|
90
|
-
"
|
91
|
-
"
|
92
|
-
"OTTO Restarted",
|
78
|
+
"Fault in Rudder Control System",
|
79
|
+
"Fault in Sail Control System",
|
80
|
+
"Battery Failure",
|
81
|
+
"Failure in Solar Array",
|
82
|
+
"Fault in Electronic Compass",
|
83
|
+
"Fault in Accelerometer",
|
84
|
+
"Fault in Wind Direction Indicator",
|
85
|
+
"Mother is Unresponsive",
|
86
|
+
"** Reserved 1 **",
|
87
|
+
"** Reserved 2 **",
|
88
|
+
"** Reserved 3 **",
|
89
|
+
"** Reserved 4 **",
|
90
|
+
"** Reserved 5 **",
|
91
|
+
"** Reserved 6 **",
|
92
|
+
"Fault with OTTO Communications",
|
93
93
|
"Mission has commenced",
|
94
94
|
"Mission is completed",
|
95
95
|
"*** MISSION ABORT ***",
|
@@ -108,7 +108,7 @@ module SGS
|
|
108
108
|
#
|
109
109
|
# Main daemon function (called from executable)
|
110
110
|
def self.daemon
|
111
|
-
puts "Alarm daemon starting up
|
111
|
+
puts "Alarm daemon starting up. VERSION: #{SGS::VERSION}"
|
112
112
|
otto = RPCClient.new(:otto)
|
113
113
|
loop do
|
114
114
|
#puts "Check for any alarms..."
|
data/lib/sgs/bearing.rb
CHANGED
@@ -113,7 +113,7 @@ module SGS
|
|
113
113
|
# This code was derived from formulae on the Movable Type site:
|
114
114
|
# http://www.movable-type.co.uk/scripts/latlong.html
|
115
115
|
#
|
116
|
-
# var d = Math.acos(Math.sin(lat1)*Math.sin(lat2) +
|
116
|
+
# var d = Math.acos(Math.sin(lat1)*Math.sin(lat2) +
|
117
117
|
# Math.cos(lat1)*Math.cos(lat2) *
|
118
118
|
# Math.cos(lon2-lon1)) * R;
|
119
119
|
# var y = Math.sin(dLon) * Math.cos(lat2);
|
data/lib/sgs/diagnostics.rb
CHANGED
data/lib/sgs/gps.rb
CHANGED
@@ -53,17 +53,22 @@ module SGS
|
|
53
53
|
#
|
54
54
|
# Main daemon function (called from executable)
|
55
55
|
def self.daemon
|
56
|
-
puts "GPS reader starting up
|
56
|
+
puts "GPS reader starting up. Version #{SGS::VERSION}"
|
57
57
|
config = Config.load
|
58
58
|
|
59
59
|
sp = SerialPort.new config.gps_device, config.gps_speed
|
60
60
|
sp.read_timeout = 10000
|
61
61
|
|
62
62
|
loop do
|
63
|
-
|
63
|
+
line = sp.readline
|
64
|
+
nmea = NMEA.parse line
|
64
65
|
if nmea.is_gprmc?
|
65
66
|
gps = nmea.parse_gprmc
|
66
67
|
p gps
|
68
|
+
if gps.cmg < 0.0
|
69
|
+
puts "CMG ERROR?!? #{gps.cmg}"
|
70
|
+
p line
|
71
|
+
end
|
67
72
|
gps.save_and_publish if gps and gps.valid?
|
68
73
|
end
|
69
74
|
end
|
data/lib/sgs/location.rb
CHANGED
@@ -75,9 +75,9 @@ module SGS
|
|
75
75
|
# This code was derived from formulae on the Movable Type site:
|
76
76
|
# http://www.movable-type.co.uk/scripts/latlong.html
|
77
77
|
#
|
78
|
-
# var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
|
78
|
+
# var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
|
79
79
|
# Math.cos(lat1)*Math.sin(d/R)*Math.cos(angle) );
|
80
|
-
# var lon2 = lon1 + Math.atan2(Math.sin(angle)*Math.sin(d/R)*Math.cos(lat1),
|
80
|
+
# var lon2 = lon1 + Math.atan2(Math.sin(angle)*Math.sin(d/R)*Math.cos(lat1),
|
81
81
|
# Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));
|
82
82
|
def +(bearing)
|
83
83
|
loc = Location.new
|
@@ -144,7 +144,7 @@ module SGS
|
|
144
144
|
#
|
145
145
|
# Is this location valid?
|
146
146
|
def valid?
|
147
|
-
|
147
|
+
!@latitude.nil? and !@longitude.nil?
|
148
148
|
end
|
149
149
|
|
150
150
|
#
|
data/lib/sgs/mission.rb
CHANGED
@@ -69,7 +69,7 @@ module SGS
|
|
69
69
|
#
|
70
70
|
# Main daemon function (called from executable)
|
71
71
|
def self.daemon
|
72
|
-
puts "Mission management system starting up
|
72
|
+
puts "Mission management system starting up. Version #{SGS::VERSION}"
|
73
73
|
#
|
74
74
|
# Load the mission data from Redis and augment it with the
|
75
75
|
# contents of the mission file.
|
@@ -87,14 +87,14 @@ module SGS
|
|
87
87
|
# a compass course), and set the Otto register accordingly.
|
88
88
|
# Repeat until we run out of waypoints.
|
89
89
|
GPS.subscribe do |count|
|
90
|
-
puts "Mission received new GPS count: #{count}"
|
91
|
-
|
92
|
-
if new_course.nil?
|
90
|
+
puts "\n***** Mission received new GPS count: #{count} *****"
|
91
|
+
if nav.navigate
|
93
92
|
mission.status.completed!
|
94
93
|
break
|
95
94
|
end
|
96
95
|
mission.status.save
|
97
|
-
compass = Bearing.rtox(
|
96
|
+
compass = Bearing.rtox(nav.course.heading)
|
97
|
+
puts "Proposed compass course: #{compass}xd"
|
98
98
|
otto.set_register(Otto::COMPASS_HEADING_REGISTER, compass)
|
99
99
|
end
|
100
100
|
else
|
@@ -166,7 +166,10 @@ module SGS
|
|
166
166
|
hash["attractors"] << waypt.to_hash
|
167
167
|
end
|
168
168
|
hash["repellors"] = []
|
169
|
-
|
169
|
+
@repellors.each do |waypt|
|
170
|
+
hash["repellors"] << waypt.to_hash
|
171
|
+
end
|
172
|
+
return hash
|
170
173
|
end
|
171
174
|
end
|
172
175
|
end
|
data/lib/sgs/navigate.rb
CHANGED
@@ -49,16 +49,20 @@
|
|
49
49
|
#
|
50
50
|
module SGS
|
51
51
|
class Navigate
|
52
|
+
attr_reader :course, :gps, :otto, :waypoint
|
53
|
+
|
52
54
|
#
|
53
55
|
# Initialize the navigational parameters
|
54
56
|
def initialize(mission)
|
55
57
|
@mission = mission
|
58
|
+
@course = nil
|
56
59
|
@swing = 45
|
57
60
|
end
|
58
61
|
|
59
62
|
#
|
60
63
|
# Compute the best heading based on our current position and the position
|
61
|
-
# of the current attractor. This is where the heavy-lifting happens
|
64
|
+
# of the current attractor. This is where the heavy-lifting happens.
|
65
|
+
# Returns TRUE if we're done.
|
62
66
|
def navigate
|
63
67
|
if @mission.status.current_waypoint == -1
|
64
68
|
@mission.status.current_waypoint = 0
|
@@ -66,35 +70,29 @@ module SGS
|
|
66
70
|
end
|
67
71
|
set_waypoint
|
68
72
|
puts "Attempting to navigate to #{@waypoint}..."
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
puts "GPS: #{@gps}"
|
73
|
-
return unless @gps.valid?
|
74
|
-
#
|
75
|
-
# Pull the latest Otto data...
|
76
|
-
@otto = Otto.load
|
77
|
-
puts "OTTO:"
|
78
|
-
p @otto
|
79
|
-
puts "Compass: #{@otto.compass}"
|
80
|
-
puts "AWA: #{@otto.awa}"
|
81
|
-
puts "Wind: #{@otto.wind}"
|
82
|
-
#
|
83
|
-
# Update our local copy of the course based on what Otto says.
|
84
|
-
puts "Course:"
|
85
|
-
@course = Course.new
|
86
|
-
@course.heading = @otto.compass
|
87
|
-
@course.awa = @otto.awa
|
88
|
-
@course.compute_wind
|
89
|
-
#
|
90
|
-
# Compute a new course from the parameter set
|
91
|
-
compute_new_course
|
73
|
+
pull_gps_data
|
74
|
+
pull_otto_data
|
75
|
+
return compute_new_course
|
92
76
|
end
|
93
77
|
|
94
78
|
#
|
95
79
|
# Compute a new course based on our position and other information.
|
96
80
|
def compute_new_course
|
81
|
+
#
|
82
|
+
# Update our local copy of the course based on what Otto says.
|
97
83
|
puts "Compute new course..."
|
84
|
+
unless @course
|
85
|
+
#
|
86
|
+
# First time through, the current course is whichever way the boat
|
87
|
+
# is pointing.
|
88
|
+
@course = Course.new
|
89
|
+
@course.heading = @otto.compass
|
90
|
+
end
|
91
|
+
#
|
92
|
+
# Really it's the AWA we're interested in, not the boat heading.
|
93
|
+
@course.awa = @otto.awa
|
94
|
+
@course.compute_wind
|
95
|
+
p @course
|
98
96
|
#
|
99
97
|
# First off, compute distance and bearing from our current location
|
100
98
|
# to every attractor and repellor. We only look at forward attractors,
|
@@ -107,7 +105,7 @@ module SGS
|
|
107
105
|
while active? and reached?
|
108
106
|
next_waypoint!
|
109
107
|
end
|
110
|
-
return
|
108
|
+
return true unless active?
|
111
109
|
puts "Angle to next waypoint: #{@waypoint.bearing.angle_d}d"
|
112
110
|
puts "Adjusted distance to waypoint is #{@waypoint.distance}"
|
113
111
|
#
|
@@ -142,10 +140,13 @@ module SGS
|
|
142
140
|
best_course = new_course
|
143
141
|
end
|
144
142
|
end
|
143
|
+
puts "Best course: AWA: #{best_course.awa_d} degrees, Course: #{best_course.heading_d} degrees, Speed: #{best_course.speed} knots"
|
144
|
+
p best_course
|
145
145
|
if best_course.tack != @course.tack
|
146
146
|
puts "TACKING!!!!"
|
147
147
|
end
|
148
|
-
best_course
|
148
|
+
@course = best_course
|
149
|
+
return false
|
149
150
|
end
|
150
151
|
|
151
152
|
#
|
@@ -253,6 +254,31 @@ module SGS
|
|
253
254
|
dist
|
254
255
|
end
|
255
256
|
|
257
|
+
#
|
258
|
+
# Pull the latest GPS data. Failure is not an option.
|
259
|
+
def pull_gps_data
|
260
|
+
loop do
|
261
|
+
@gps = GPS.load
|
262
|
+
puts "GPS: #{@gps}"
|
263
|
+
break if @gps.valid?
|
264
|
+
puts "Retrying GPS..."
|
265
|
+
sleep 1
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
#
|
270
|
+
# Pull the latest Otto data.
|
271
|
+
def pull_otto_data
|
272
|
+
#
|
273
|
+
# Pull the latest Otto data...
|
274
|
+
@otto = Otto.load
|
275
|
+
puts "OTTO:"
|
276
|
+
p @otto
|
277
|
+
puts "Compass: #{@otto.compass}"
|
278
|
+
puts "AWA: #{@otto.awa}"
|
279
|
+
puts "Wind: #{@otto.wind}"
|
280
|
+
end
|
281
|
+
|
256
282
|
#
|
257
283
|
# Navigate a course up to a windward mark which is one nautical mile
|
258
284
|
# upwind of the start position. From there, navigate downwind to the
|
data/lib/sgs/nmea.rb
CHANGED
data/lib/sgs/otto.rb
CHANGED
@@ -53,6 +53,14 @@ module SGS
|
|
53
53
|
attr_reader :actual_rudder, :actual_sail
|
54
54
|
attr_reader :otto_mode, :otto_timestamp, :telemetry
|
55
55
|
|
56
|
+
MISSION_SWITCH = 1
|
57
|
+
RUDDER_FAULT = 2
|
58
|
+
SAIL_FAULT = 3
|
59
|
+
BATTERY_FAULT = 4
|
60
|
+
SOLAR_FAULT = 5
|
61
|
+
COMPASS_FAULT = 6
|
62
|
+
ACCEL_FAULT = 7
|
63
|
+
WDI_FAULT = 8
|
56
64
|
#
|
57
65
|
# Updates to Otto are done by setting an 8bit register value, as below.
|
58
66
|
ALARM_CLEAR_REGISTER = 0
|
@@ -112,10 +120,13 @@ module SGS
|
|
112
120
|
|
113
121
|
#
|
114
122
|
# Set up some useful defaults. We assume rudder goes from 0 to 255 as does
|
115
|
-
# the sail angle.
|
123
|
+
# the sail angle.
|
116
124
|
def initialize
|
117
125
|
serial_port = nil
|
118
126
|
#
|
127
|
+
# Keep a local copy of the register set to avoid duplication.
|
128
|
+
@registers = Array.new(MAX_REGISTER)
|
129
|
+
#
|
119
130
|
# Set some defaults for the read-back parameters
|
120
131
|
# The following five parameters are reported back by Otto with a status
|
121
132
|
# message, and are read-only. @alarm_status is 16 bits while the other
|
@@ -148,7 +159,7 @@ module SGS
|
|
148
159
|
# to do an initial sync with the device as it will ignore the
|
149
160
|
# usual serial console boot-up gumph awaiting our sync message.
|
150
161
|
def self.daemon
|
151
|
-
puts "Low-level (Otto) communication subsystem starting up
|
162
|
+
puts "Low-level (Otto) communication subsystem starting up. Version #{SGS::VERSION}"
|
152
163
|
otto = new
|
153
164
|
config = Config.load
|
154
165
|
otto.serial_port = SerialPort.new config.otto_device, config.otto_speed
|
@@ -250,13 +261,17 @@ module SGS
|
|
250
261
|
request = MessagePack.unpack(request)
|
251
262
|
puts "Req:[#{request.inspect}]"
|
252
263
|
params = request['params']
|
253
|
-
next if request['method'] != "set_local_register"
|
254
264
|
puts "PARAMS: #{params}"
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
265
|
+
case request['method']
|
266
|
+
when "set_local_register"
|
267
|
+
reg, value = params
|
268
|
+
if @registers[reg] != value
|
269
|
+
cmd = "R%d=%X\r\n" % [reg, value]
|
270
|
+
puts "Command: #{cmd}"
|
271
|
+
@serial_port.write cmd
|
272
|
+
@registers[reg] = value
|
273
|
+
end
|
274
|
+
end
|
260
275
|
end
|
261
276
|
end
|
262
277
|
|
@@ -294,7 +309,7 @@ module SGS
|
|
294
309
|
# representing the elapsed seconds since Otto restarted.
|
295
310
|
def parse_tstamp(tstamp)
|
296
311
|
newval = tstamp.to_i(16)
|
297
|
-
if newval < @otto_timestamp
|
312
|
+
if @otto_timestamp.nil? or newval < @otto_timestamp
|
298
313
|
puts "ALARM! Otto rebooted (or something)..."
|
299
314
|
end
|
300
315
|
@otto_timestamp = newval
|
data/lib/sgs/redis_base.rb
CHANGED
@@ -96,7 +96,7 @@ module SGS
|
|
96
96
|
# It's an array - iterate and read the values.
|
97
97
|
lval.size.times do |idx|
|
98
98
|
idx_val = lval[idx]
|
99
|
-
lval[idx] = redis_read_var var, idx_val.class, :idx => idx
|
99
|
+
lval[idx] = redis_read_var var, idx_val.class, :idx => idx
|
100
100
|
end
|
101
101
|
elsif lval.kind_of? Location
|
102
102
|
#
|
@@ -206,7 +206,7 @@ module SGS
|
|
206
206
|
case
|
207
207
|
when klass == Time
|
208
208
|
redis_val = Time.at(redis_val.to_f).gmtime
|
209
|
-
when klass ==
|
209
|
+
when klass == Integer
|
210
210
|
redis_val = redis_val.to_i
|
211
211
|
when klass == Float
|
212
212
|
redis_val = redis_val.to_f
|
data/lib/sgs/report.rb
CHANGED
@@ -42,7 +42,7 @@ module SGS
|
|
42
42
|
#
|
43
43
|
# Main daemon function (called from executable)
|
44
44
|
def self.daemon
|
45
|
-
puts "Reporting subsystem starting up
|
45
|
+
puts "Reporting subsystem starting up. Version #{SGS::VERSION}"
|
46
46
|
config = Config.load
|
47
47
|
sp = SerialPort.new config.comm_device, config.comm_speed
|
48
48
|
sp.read_timeout = 10000
|
data/lib/sgs/version.rb
CHANGED
data/lib/sgs/waypoint.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sgslib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dermot Tynan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -204,7 +204,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
204
204
|
- !ruby/object:Gem::Version
|
205
205
|
version: '0'
|
206
206
|
requirements: []
|
207
|
-
rubygems_version: 3.
|
207
|
+
rubygems_version: 3.3.5
|
208
208
|
signing_key:
|
209
209
|
specification_version: 4
|
210
210
|
summary: Sailboat Guidance System
|