sgslib 1.7.1 → 1.8.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e111aaff75b5c948f935ac6f76747487c2a6acf2c4e661e07b5e670aa48024b
4
- data.tar.gz: 8b0dae14c6a69c2222e38522d3f7e562b45c33e754cf5019a9f0b081d6191fc6
3
+ metadata.gz: 5b772fccd0d24dd037a52734c72ef29a5203f5e32bbad85a47b4d8b16985c507
4
+ data.tar.gz: f717f8defef045a95408bbe34217bb8bf60f6ae802e5ddf95d4ff08dc223b8ff
5
5
  SHA512:
6
- metadata.gz: 101b2c3581effba8bc0fae32d4c68030649104862101336409fdeb4679ff25236adf0b67dfeac588eceb0196a7616175cc1112d1d926ee6d528c95c60cbeed60
7
- data.tar.gz: 981bf2364b073ae0d25e0fea03341b289db890836af399c4cee4079d0dcde1ceef20f9669d3fdeb36d2ea143b6566830bcc676ea705bf9bb6439dc8162234e52
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
- MISSION_SWITCH = 0
50
- RUDDSRV_FAULT = 1
51
- SAILSRV_FAULT = 2
52
- VBATT_CRITICAL = 3
53
- VBATT_UNDERVOLTAGE = 4
54
- VBATT_OVERVOLTAGE = 5
55
- IBATT_INRUSH = 6
56
- IBATT_DRAIN = 7
57
- VSOLAR_OVERVOLTAGE = 8
58
- COMPASS_ERROR = 9
59
- COMPASS_NOREAD = 10
60
- WDI_STUCK = 11
61
- WDI_NOREAD = 12
62
- RUDDER_NOZERO = 13
63
- SAIL_NOZERO = 14
64
- MOTHER_UNRESP = 15
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
- OTTO_RESTART = 16
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 Servo Fault",
78
- "Sail Servo Fault",
79
- "Battery voltage is critically low",
80
- "Battery voltage is low",
81
- "Battery voltage is too high",
82
- "Battery inrush current",
83
- "Battery drain current",
84
- "Solar voltage is too high",
85
- "Compass module error",
86
- "Compass not responding",
87
- "WDI reading is misaligned",
88
- "Cannot read from the WDI",
89
- "Cannot zero the rudder position",
90
- "Cannot zero the sail position",
91
- "Mother is unresponsive",
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);
@@ -41,7 +41,7 @@ module SGS
41
41
  #
42
42
  # Main daemon function (called from executable)
43
43
  def self.daemon
44
- puts "Diagnostics subsystem starting up..."
44
+ puts "Diagnostics subsystem starting up. Version #{SGS::VERSION}"
45
45
  loop do
46
46
  sleep 300
47
47
  end
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
- nmea = NMEA.parse sp.readline
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
- @latitude and @longitude
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
- new_course = nav.navigate
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(new_course.heading)
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
- hash
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
- # Pull the latest GPS data...
71
- @gps = GPS.load
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 nil unless active?
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
@@ -58,7 +58,7 @@ module SGS
58
58
  end
59
59
  nmea
60
60
  end
61
-
61
+
62
62
  #
63
63
  # Parse an NMEA string into its component parts.
64
64
  def parse(str)
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
- cmd = "R%d=%X\r\n" % params
256
- puts "Command: #{cmd}"
257
- @serial_port.write cmd
258
- puts "> Sending command: #{str}"
259
- @serial_port.puts "#{str}"
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
@@ -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 == Fixnum
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
@@ -33,5 +33,5 @@
33
33
  # ABSTRACT
34
34
  #
35
35
  module SGS
36
- VERSION = "1.7.1"
36
+ VERSION = "1.8.5"
37
37
  end
data/lib/sgs/waypoint.rb CHANGED
@@ -137,7 +137,7 @@ module SGS
137
137
  hash["name"] = @name
138
138
  hash["normal"] = @normal
139
139
  hash["range"] = @range
140
- hash
140
+ return hash
141
141
  end
142
142
 
143
143
  #
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.7.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-05-31 00:00:00.000000000 Z
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.1.6
207
+ rubygems_version: 3.3.5
208
208
  signing_key:
209
209
  specification_version: 4
210
210
  summary: Sailboat Guidance System