sgslib 1.5.0 → 1.5.1
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/exe/sgs_otto +0 -0
- data/lib/sgs/alarm.rb +20 -10
- data/lib/sgs/bearing.rb +1 -0
- data/lib/sgs/diagnostics.rb +1 -0
- data/lib/sgs/gps.rb +14 -1
- data/lib/sgs/logger.rb +0 -7
- data/lib/sgs/mission.rb +1 -0
- data/lib/sgs/mission_status.rb +4 -5
- data/lib/sgs/navigate.rb +21 -2
- data/lib/sgs/otto.rb +173 -4
- data/lib/sgs/report.rb +5 -0
- data/lib/sgs/version.rb +1 -1
- data/lib/sgslib.rb +1 -4
- data/sgslib.gemspec +5 -3
- metadata +52 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5dffcc970035c48e2b6026c72884b6ab97cc14ac43ba255cb4386244b46287c
|
4
|
+
data.tar.gz: 347c958575c0e9510047c75b997426083d4e3abf8ee479ff9b407c3395bbe118
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdee04756fe59509497bc455f7874e9c05ecca6c9031f55133460a28ea987d9a0dd788588e2b449b9fe0630f734f23b6c968722361153b9130fa0362c354b67c
|
7
|
+
data.tar.gz: de267f01e59622938cfb1ad3ebbcb7c08c72bb02a625f1de72c93255b5e3be868cae29a1625383890c4c4aa57292b27942d735adb0abb4f36763dd481ca62893
|
data/exe/sgs_otto
CHANGED
File without changes
|
data/lib/sgs/alarm.rb
CHANGED
@@ -44,7 +44,9 @@ module SGS
|
|
44
44
|
class Alarm < RedisBase
|
45
45
|
attr_accessor :last_report, :time
|
46
46
|
|
47
|
-
|
47
|
+
#
|
48
|
+
# Alarms generated by Otto.
|
49
|
+
MISSION_SWITCH = 0
|
48
50
|
RUDDSRV_FAULT = 1
|
49
51
|
SAILSRV_FAULT = 2
|
50
52
|
VBATT_CRITICAL = 3
|
@@ -60,16 +62,18 @@ module SGS
|
|
60
62
|
RUDDER_NOZERO = 13
|
61
63
|
SAIL_NOZERO = 14
|
62
64
|
MOTHER_UNRESP = 15
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
#
|
66
|
+
# Alarms generated by Mother.
|
67
|
+
OTTO_RESTART = 16
|
68
|
+
MISSION_COMMENCE = 17
|
69
|
+
MISSION_COMPLETE = 18
|
70
|
+
MISSION_ABORT = 19
|
71
|
+
WAYPOINT_REACHED = 20
|
72
|
+
CROSS_TRACK_ERROR = 21
|
73
|
+
INSIDE_FENCE = 22
|
70
74
|
|
71
75
|
ALARM_NAMES = [
|
72
|
-
"
|
76
|
+
"Mission Activation Switch",
|
73
77
|
"Rudder Servo Fault",
|
74
78
|
"Sail Servo Fault",
|
75
79
|
"Battery voltage is critically low",
|
@@ -85,6 +89,7 @@ module SGS
|
|
85
89
|
"Cannot zero the rudder position",
|
86
90
|
"Cannot zero the sail position",
|
87
91
|
"Mother is unresponsive",
|
92
|
+
"OTTO Restarted",
|
88
93
|
"Mission has commenced",
|
89
94
|
"Mission is completed",
|
90
95
|
"*** MISSION ABORT ***",
|
@@ -103,8 +108,13 @@ module SGS
|
|
103
108
|
#
|
104
109
|
# Main daemon function (called from executable)
|
105
110
|
def self.daemon
|
111
|
+
puts "Alarm daemon starting up..."
|
112
|
+
otto = SGS::RPCClient.new(:otto)
|
106
113
|
loop do
|
107
|
-
|
114
|
+
#puts "Check for any alarms..."
|
115
|
+
#resp = otto.command "A?"
|
116
|
+
#puts "Response: #{resp}"
|
117
|
+
sleep 30
|
108
118
|
end
|
109
119
|
end
|
110
120
|
|
data/lib/sgs/bearing.rb
CHANGED
data/lib/sgs/diagnostics.rb
CHANGED
data/lib/sgs/gps.rb
CHANGED
@@ -32,6 +32,8 @@
|
|
32
32
|
#
|
33
33
|
# ABSTRACT
|
34
34
|
#
|
35
|
+
require 'serialport'
|
36
|
+
|
35
37
|
module SGS
|
36
38
|
class GPS < RedisBase
|
37
39
|
attr_accessor :time, :location, :sog, :cmg, :magvar
|
@@ -49,8 +51,19 @@ module SGS
|
|
49
51
|
#
|
50
52
|
# Main daemon function (called from executable)
|
51
53
|
def self.daemon
|
54
|
+
puts "GPS reader starting up..."
|
55
|
+
config = SGS::Config.load
|
56
|
+
|
57
|
+
sp = SerialPort.new config.gps_device, config.gps_speed
|
58
|
+
sp.read_timeout = 10000
|
59
|
+
|
52
60
|
loop do
|
53
|
-
|
61
|
+
nmea = SGS::NMEA.parse sp.readline
|
62
|
+
if nmea.is_gprmc?
|
63
|
+
gps = nmea.parse_gprmc
|
64
|
+
p gps
|
65
|
+
gps.save_and_publish if gps and gps.valid?
|
66
|
+
end
|
54
67
|
end
|
55
68
|
end
|
56
69
|
|
data/lib/sgs/logger.rb
CHANGED
data/lib/sgs/mission.rb
CHANGED
data/lib/sgs/mission_status.rb
CHANGED
@@ -73,7 +73,6 @@ module SGS
|
|
73
73
|
@state = STATE_AWAITING
|
74
74
|
@current_waypoint = 0
|
75
75
|
@start_time = @end_time = nil
|
76
|
-
@logger = Logger.new(STDOUT)
|
77
76
|
end
|
78
77
|
|
79
78
|
#
|
@@ -91,7 +90,7 @@ module SGS
|
|
91
90
|
#
|
92
91
|
# Commence a mission...
|
93
92
|
def start_test!(time = nil)
|
94
|
-
|
93
|
+
puts "***** Starting test phase *****"
|
95
94
|
@start_time = time || Time.now
|
96
95
|
@state = STATE_START_TEST
|
97
96
|
@current_waypoint = 0
|
@@ -104,7 +103,7 @@ module SGS
|
|
104
103
|
@end_time = time || Time.now
|
105
104
|
@state = STATE_COMPLETE
|
106
105
|
save_and_publish
|
107
|
-
|
106
|
+
puts "***** Mission completed! *****"
|
108
107
|
end
|
109
108
|
|
110
109
|
#
|
@@ -113,7 +112,7 @@ module SGS
|
|
113
112
|
@end_time = time || Time.now
|
114
113
|
@state = STATE_TERMINATED
|
115
114
|
save_and_publish
|
116
|
-
|
115
|
+
puts "***** Mission terminated! *****"
|
117
116
|
end
|
118
117
|
|
119
118
|
#
|
@@ -122,7 +121,7 @@ module SGS
|
|
122
121
|
@end_time = time || Time.now
|
123
122
|
@state = STATE_FAILURE
|
124
123
|
save_and_publish
|
125
|
-
|
124
|
+
puts "***** Mission failure! *****"
|
126
125
|
end
|
127
126
|
end
|
128
127
|
end
|
data/lib/sgs/navigate.rb
CHANGED
@@ -71,8 +71,27 @@ module SGS
|
|
71
71
|
#
|
72
72
|
# Main daemon function (called from executable)
|
73
73
|
def self.daemon
|
74
|
-
|
75
|
-
|
74
|
+
puts "Navigation system starting up..."
|
75
|
+
#
|
76
|
+
# Load the mission data from Redis and augment it with the
|
77
|
+
# contents of the mission file.
|
78
|
+
config = SGS::Config.load
|
79
|
+
mission = SGS::Mission.file_load config.mission_file
|
80
|
+
#
|
81
|
+
# Now listen for GPS data...
|
82
|
+
SGS::GPS.subscribe do |count|
|
83
|
+
puts "Received new GPS count: #{count}"
|
84
|
+
case SGS::MissionStatus.state
|
85
|
+
when STATE_COMPASS_FOLLOW
|
86
|
+
when STATE_WIND_FOLLOW
|
87
|
+
mission.navigate
|
88
|
+
when STATE_COMPLETE
|
89
|
+
when STATE_TERMINATED
|
90
|
+
when STATE_FAILURE
|
91
|
+
mission.hold_station
|
92
|
+
end
|
93
|
+
gps = SGS::GPS.load
|
94
|
+
p gps
|
76
95
|
end
|
77
96
|
end
|
78
97
|
|
data/lib/sgs/otto.rb
CHANGED
@@ -32,6 +32,8 @@
|
|
32
32
|
#
|
33
33
|
# ABSTRACT
|
34
34
|
#
|
35
|
+
require 'serialport'
|
36
|
+
require 'msgpack'
|
35
37
|
|
36
38
|
##
|
37
39
|
# Routines for interfacing with the low-level microcontroller.
|
@@ -41,6 +43,9 @@ module SGS
|
|
41
43
|
attr_accessor :raw_rudder, :raw_sail, :raw_compass, :raw_awa, :raw_tc, :raw_ta
|
42
44
|
attr_accessor :mode, :rudder_m, :rudder_c, :sail_m, :sail_c
|
43
45
|
attr_accessor :bv_m, :bv_c, :bi_m, :bi_c, :bt_m, :bt_c, :sv_m, :sv_c
|
46
|
+
attr_accessor :serial_port
|
47
|
+
attr_reader :alarm_status, :wind, :compass, :actual_rudder, :actual_sail
|
48
|
+
attr_reader :otto_mode, :otto_timestamp, :telemetry
|
44
49
|
|
45
50
|
MODE_INERT = 0
|
46
51
|
MODE_DIAGNOSTICS = 1
|
@@ -57,8 +62,9 @@ module SGS
|
|
57
62
|
# Set up some useful defaults. We assume rudder goes from 0 to 200 as does
|
58
63
|
# the sail angle.
|
59
64
|
def initialize
|
65
|
+
serial_port = nil
|
60
66
|
#
|
61
|
-
|
67
|
+
# Configure the Mx + C values for sail and rudder
|
62
68
|
@rudder_m = 2.5
|
63
69
|
@rudder_c = 100.0
|
64
70
|
@sail_m = 2.0
|
@@ -68,6 +74,12 @@ module SGS
|
|
68
74
|
rudder = 0.0
|
69
75
|
sail = 0.0
|
70
76
|
#
|
77
|
+
# Set some defaults for the read-back parameters
|
78
|
+
@alarm_status = @wind = @compass = @actual_rudder = @actual_sail = 0
|
79
|
+
@otto_mode = 0
|
80
|
+
@otto_timestamp = 1000
|
81
|
+
@telemetry = Array.new(16)
|
82
|
+
#
|
71
83
|
# Set up some basic parameters for battery/solar readings
|
72
84
|
@bv_m = @bi_m = @bt_m = @sv_m = 1.0
|
73
85
|
@bv_c = @bi_c = @bt_c = @sv_c = 0.0
|
@@ -75,13 +87,170 @@ module SGS
|
|
75
87
|
end
|
76
88
|
|
77
89
|
#
|
78
|
-
# Main daemon function (called from executable)
|
90
|
+
# Main daemon function (called from executable). The job of
|
91
|
+
# this daemon is to accept commands from the Redis pub/sub
|
92
|
+
# stream and send them to the low-level device, recording the
|
93
|
+
# response and sending it back to the caller. Note that we need
|
94
|
+
# to do an initial sync with the device as it will ignore the
|
95
|
+
# usual serial console boot-up gumph awaiting our sync message.
|
79
96
|
def self.daemon
|
80
|
-
|
81
|
-
|
97
|
+
puts "Low-level (Otto) communication subsystem starting up..."
|
98
|
+
otto = new
|
99
|
+
config = SGS::Config.load
|
100
|
+
otto.serial_port = SerialPort.new config.otto_device, config.otto_speed
|
101
|
+
otto.serial_port.read_timeout = 10000
|
102
|
+
#
|
103
|
+
# Start by getting a sync message from Otto.
|
104
|
+
otto.synchronize()
|
105
|
+
#
|
106
|
+
# Run the communications service with Otto. Two threads are used, one for
|
107
|
+
# reading and one for writing. Don't let the command stack get too big.
|
108
|
+
t1 = Thread.new { otto.reader_thread }
|
109
|
+
t2 = Thread.new { otto.writer_thread }
|
110
|
+
t1.join
|
111
|
+
t2.join
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Synchronize with the low-level board by sending CQ messages until
|
116
|
+
# they respond.
|
117
|
+
def synchronize
|
118
|
+
index = 0
|
119
|
+
backoffs = [1, 1, 1, 1, 2, 2, 3, 5, 10, 10, 20, 30, 60]
|
120
|
+
puts "Attempting to synchronize with Otto..."
|
121
|
+
while true do
|
122
|
+
begin
|
123
|
+
@serial_port.puts "@@CQ!"
|
124
|
+
resp = read_data
|
125
|
+
break if resp =~ /^\+CQOK/ or resp =~ /^\+OK/
|
126
|
+
sleep backoffs[index]
|
127
|
+
index += 1 if index < (backoffs.count - 1)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
puts "Synchronization complete!"
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Thread to read status messages from Otto and handle them
|
135
|
+
def reader_thread
|
136
|
+
puts "Starting OTTO reader thread..."
|
137
|
+
while true
|
138
|
+
data = read_data
|
139
|
+
next if data.nil? or data.length == 0
|
140
|
+
case data[0]
|
141
|
+
when '$'
|
142
|
+
#
|
143
|
+
# Status message (every second)
|
144
|
+
parse_status(data[1..])
|
145
|
+
when '@'
|
146
|
+
#
|
147
|
+
# Otto elapsed time (every four seconds)
|
148
|
+
parse_tstamp(data[1..])
|
149
|
+
when '!'
|
150
|
+
#
|
151
|
+
# Otto mode state (every four seconds)
|
152
|
+
parse_mode(data[1..])
|
153
|
+
when '>'
|
154
|
+
#
|
155
|
+
# Telemetry data (every two seconds)
|
156
|
+
parse_telemetry(data[1..])
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Thread to write commands direct to Otto.
|
163
|
+
def writer_thread
|
164
|
+
puts "Starting OTTO writer thread..."
|
165
|
+
#
|
166
|
+
# Now listen for Redis PUB/SUB requests and act on each one.
|
167
|
+
while true
|
168
|
+
channel, request = SGS::RedisBase.redis.brpop("otto")
|
169
|
+
request = MessagePack.unpack(request)
|
170
|
+
puts "Req:[#{request.inspect}]"
|
171
|
+
cmd = {
|
172
|
+
id: request['id'],
|
173
|
+
args: request['params'].unshift(request['method'])
|
174
|
+
}
|
175
|
+
puts "CMD:#{cmd.inspect}"
|
176
|
+
#
|
177
|
+
# Don't let the command stack get too big.
|
178
|
+
while @command_stack.length > 5
|
179
|
+
sleep 5
|
180
|
+
end
|
181
|
+
|
182
|
+
puts "> Sending command: #{str}"
|
183
|
+
@serial_port.puts "#{str}"
|
184
|
+
|
185
|
+
reply = {
|
186
|
+
'id' => id,
|
187
|
+
'jsonrpc' => '2.0',
|
188
|
+
'result' => result
|
189
|
+
}
|
190
|
+
SGS::RedisBase.redis.rpush(id, MessagePack.pack(reply))
|
191
|
+
SGS::RedisBase.redis.expire(id, 30)
|
82
192
|
end
|
83
193
|
end
|
84
194
|
|
195
|
+
#
|
196
|
+
# Read data from the serial port
|
197
|
+
def read_data
|
198
|
+
begin
|
199
|
+
data = @serial_port.readline.chomp
|
200
|
+
rescue EOFError => error
|
201
|
+
puts "Otto Read Timeout!"
|
202
|
+
data = nil
|
203
|
+
end
|
204
|
+
data
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# Parse a status message from Otto. In the form:
|
209
|
+
# 0001:C000:0000
|
210
|
+
def parse_status(status)
|
211
|
+
puts "Parse status: #{status}"
|
212
|
+
args = status.split /:/
|
213
|
+
@alarm_status = args[0].to_i(16)
|
214
|
+
wc = args[1].to_i(16)
|
215
|
+
rs = args[2].to_i(16)
|
216
|
+
@wind = (wc >> 8) & 0xff
|
217
|
+
@compass = (wc & 0xff)
|
218
|
+
@actual_rudder = (rs >> 8) & 0xff
|
219
|
+
@actual_sail = (rs & 0xff)
|
220
|
+
p self
|
221
|
+
self.save_and_publish
|
222
|
+
end
|
223
|
+
|
224
|
+
#
|
225
|
+
# Parse a timestamp message from Otto. In the form: "000FE2" 24 bits
|
226
|
+
# representing the elapsed seconds since Otto restarted.
|
227
|
+
def parse_tstamp(tstamp)
|
228
|
+
puts "Parse timestamp: #{tstamp}"
|
229
|
+
newval = tstamp.to_i(16)
|
230
|
+
if newval < @otto_timestamp
|
231
|
+
puts "ALARM! Otto rebooted (or something)..."
|
232
|
+
end
|
233
|
+
@otto_timestamp = newval
|
234
|
+
end
|
235
|
+
|
236
|
+
#
|
237
|
+
# Parse a mode state message from Otto. In the form: "00". An eight bit
|
238
|
+
# quantity.
|
239
|
+
def parse_mode(mode)
|
240
|
+
puts "Parse Otto Mode State: #{mode}"
|
241
|
+
@otto_mode = mode.to_i(16)
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Parse a telemetry message from Otto. In the form: "7327" where the first
|
246
|
+
# character is the channel (0->9) and the remaining 12 bits are the value.
|
247
|
+
def parse_telemetry(telemetry)
|
248
|
+
puts "Parse Otto Telemetry Data: #{telemetry}"
|
249
|
+
data = telemetry.to_i(16)
|
250
|
+
chan = (data >> 12) & 0xf
|
251
|
+
@telemetry[chan] = data & 0xff
|
252
|
+
end
|
253
|
+
|
85
254
|
#
|
86
255
|
# Set the required rudder angle. Input values range from +/- 40.0 degrees
|
87
256
|
def rudder=(val)
|
data/lib/sgs/report.rb
CHANGED
@@ -32,6 +32,7 @@
|
|
32
32
|
#
|
33
33
|
# ABSTRACT
|
34
34
|
#
|
35
|
+
require 'serialport'
|
35
36
|
|
36
37
|
##
|
37
38
|
# Routines for handling sailboat navigation and route planning.
|
@@ -41,6 +42,10 @@ module SGS
|
|
41
42
|
#
|
42
43
|
# Main daemon function (called from executable)
|
43
44
|
def self.daemon
|
45
|
+
puts "Reporting subsystem starting up..."
|
46
|
+
config = SGS::Config.load
|
47
|
+
sp = SerialPort.new config.comm_device, config.comm_speed
|
48
|
+
sp.read_timeout = 10000
|
44
49
|
loop do
|
45
50
|
sleep 300
|
46
51
|
end
|
data/lib/sgs/version.rb
CHANGED
data/lib/sgslib.rb
CHANGED
@@ -31,13 +31,10 @@
|
|
31
31
|
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
32
|
#
|
33
33
|
# ABSTRACT
|
34
|
-
#
|
34
|
+
# Include all of the various components.
|
35
35
|
|
36
36
|
##
|
37
37
|
#
|
38
|
-
require 'date'
|
39
|
-
require 'logger'
|
40
|
-
|
41
38
|
require "sgs/version"
|
42
39
|
require 'sgs/redis_base'
|
43
40
|
require 'sgs/config'
|
data/sgslib.gemspec
CHANGED
@@ -40,8 +40,10 @@ Gem::Specification.new do |spec|
|
|
40
40
|
spec.add_development_dependency "rake", ">= 12.3.3"
|
41
41
|
spec.add_development_dependency "rspec", "~> 3.0"
|
42
42
|
|
43
|
-
spec.add_runtime_dependency "
|
43
|
+
spec.add_runtime_dependency "redis", "~> 4.7"
|
44
|
+
spec.add_runtime_dependency "serialport", "~> 1.3"
|
44
45
|
spec.add_runtime_dependency "msgpack", "~> 1.3"
|
45
|
-
|
46
|
-
spec.
|
46
|
+
spec.add_runtime_dependency "json"
|
47
|
+
spec.add_runtime_dependency "securerandom"
|
48
|
+
spec.add_runtime_dependency "yaml"
|
47
49
|
end
|
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.5.
|
4
|
+
version: 1.5.1
|
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-01-
|
11
|
+
date: 2023-01-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -53,21 +53,21 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: redis
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '4.7'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '4.7'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: serialport
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
@@ -81,19 +81,61 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.3'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: msgpack
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '1.3'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '1.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: json
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: securerandom
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yaml
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
97
139
|
description: Sailboat Guidance System - an autonomous navigation and control system
|
98
140
|
for robotic sailboats.
|
99
141
|
email:
|
@@ -164,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
206
|
- !ruby/object:Gem::Version
|
165
207
|
version: '0'
|
166
208
|
requirements: []
|
167
|
-
rubygems_version: 3.
|
209
|
+
rubygems_version: 3.1.6
|
168
210
|
signing_key:
|
169
211
|
specification_version: 4
|
170
212
|
summary: Sailboat Guidance System
|