2026-07-04 23:49:20 -06:00
|
|
|
extends BaseSensorNode
|
|
|
|
|
class_name VehicleSensorNode
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Vehicle sensor can provide the following data fields:
|
|
|
|
|
- GPS
|
|
|
|
|
- Contributing satellites
|
|
|
|
|
- Accelerometer
|
|
|
|
|
- Magnetometer
|
|
|
|
|
- Gyroscope
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var max_data_length: int = 10
|
|
|
|
|
var gps_timestamps = []
|
|
|
|
|
var coordinates = []
|
|
|
|
|
var gps_positions = []
|
|
|
|
|
var altitudes = []
|
2026-07-06 13:57:09 -06:00
|
|
|
var alt_coefficients = []
|
2026-07-04 23:49:20 -06:00
|
|
|
var altitude_m:
|
|
|
|
|
get:
|
|
|
|
|
return _get_current_altitude()
|
|
|
|
|
var speed_data = []
|
2026-07-06 13:57:09 -06:00
|
|
|
var speed_coefficients = []
|
2026-07-04 23:49:20 -06:00
|
|
|
var speed_kmh:
|
|
|
|
|
get:
|
|
|
|
|
return _get_current_speed()
|
|
|
|
|
|
|
|
|
|
static var DOWN = Vector2(0, -1.)
|
|
|
|
|
var accel_timestamps = []
|
|
|
|
|
var g_vecs = []
|
|
|
|
|
var linear_vecs = []
|
|
|
|
|
var pitch_data = []
|
|
|
|
|
var pitch_rad: float
|
|
|
|
|
var roll_data = []
|
|
|
|
|
var roll_rad: float
|
2026-07-06 13:57:09 -06:00
|
|
|
var lateral_g_data = []
|
|
|
|
|
var x_coefficients = []
|
|
|
|
|
var y_coefficients = []
|
|
|
|
|
var lateral_accel:
|
|
|
|
|
get:
|
|
|
|
|
return _get_current_gs()
|
2026-07-04 23:49:20 -06:00
|
|
|
|
|
|
|
|
var mag_timestamps = []
|
|
|
|
|
var mag_vecs = []
|
|
|
|
|
var heading_data = []
|
|
|
|
|
var heading_rad: float
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
2026-07-08 20:58:21 -06:00
|
|
|
super._ready()
|
2026-07-04 23:49:20 -06:00
|
|
|
DataSignals.gps_data_received.connect(_on_gps_data_received)
|
|
|
|
|
#DataSignals.sat_data_received.connect(_on_sat_data_received)
|
|
|
|
|
DataSignals.accelerometer_data_received.connect(_on_accel_data_received)
|
|
|
|
|
DataSignals.magnetometer_data_received.connect(_on_mag_data_received)
|
|
|
|
|
#DataSignals.gyroscope_data_received.connect(_on_gyro_data_received)
|
|
|
|
|
|
|
|
|
|
func _get_sensor_class():
|
|
|
|
|
return "VEHICLE"
|
|
|
|
|
|
|
|
|
|
func _on_gps_data_received(source_ip: String, timestamp_list: Array, new_coordinates: Array, speed_kmh: float, dop: Array):
|
|
|
|
|
# coordinates = [lat rad, lon rad, alt m, geoid diff m]
|
|
|
|
|
# dop = [pdop, hdop, vdop]
|
|
|
|
|
if source_ip != ip_address:
|
|
|
|
|
return
|
|
|
|
|
var timestamp: float = 3600.*timestamp_list[0] + 60.*timestamp_list[1] + timestamp_list[2] + timestamp_list[3]
|
2026-07-08 20:58:21 -06:00
|
|
|
if gps_timestamps.size() > 0 and (timestamp - gps_timestamps[-1]) < -1:
|
|
|
|
|
gps_timestamps.clear()
|
|
|
|
|
coordinates.clear()
|
|
|
|
|
gps_positions.clear()
|
|
|
|
|
altitudes.clear()
|
|
|
|
|
speed_data.clear()
|
2026-07-04 23:49:20 -06:00
|
|
|
if gps_timestamps.size() == max_data_length and not TimeHelpers.is_timestamp_newer_24h(gps_timestamps[-1], timestamp):
|
|
|
|
|
return
|
2026-07-06 13:57:09 -06:00
|
|
|
var insert_idx = Bisect.reverse_bisect(gps_timestamps, timestamp)
|
2026-07-04 23:49:20 -06:00
|
|
|
var altitude_m = new_coordinates[2] + new_coordinates[3]
|
|
|
|
|
var radius_km = (new_coordinates[2] + new_coordinates[3] + Constants.EARTH_RADIUS_M) / 1000.
|
|
|
|
|
var pos_x = radius_km * sin(new_coordinates[1]) * cos(new_coordinates[0])
|
|
|
|
|
var pos_z = radius_km * sin(new_coordinates[1]) * sin(new_coordinates[0])
|
|
|
|
|
var pos_y = radius_km * cos(new_coordinates[1])
|
|
|
|
|
gps_timestamps.insert(insert_idx, timestamp)
|
|
|
|
|
coordinates.insert(insert_idx, [new_coordinates[0], new_coordinates[1]])
|
|
|
|
|
gps_positions.insert(insert_idx, Vector3(pos_x, pos_y, pos_z))
|
|
|
|
|
altitudes.insert(insert_idx, altitude_m)
|
|
|
|
|
speed_data.insert(insert_idx, speed_kmh)
|
|
|
|
|
if gps_timestamps.size() > max_data_length:
|
2026-07-06 13:57:09 -06:00
|
|
|
gps_timestamps.pop_back()
|
|
|
|
|
coordinates.pop_back()
|
|
|
|
|
gps_positions.pop_back()
|
|
|
|
|
altitudes.pop_back()
|
|
|
|
|
speed_data.pop_back()
|
|
|
|
|
_update_alt_coefficients()
|
|
|
|
|
_update_speed_coefficients()
|
2026-07-04 23:49:20 -06:00
|
|
|
|
|
|
|
|
func _on_sat_data_received(source_ip: String, timestamp: float):
|
|
|
|
|
if source_ip != ip_address:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
func _on_accel_data_received(source_ip: String, timestamp_list: Array, accel: Vector3, linear_accel: Vector3, g_accel: Vector3):
|
|
|
|
|
if source_ip != ip_address:
|
|
|
|
|
return
|
|
|
|
|
var timestamp: float = 3600.*timestamp_list[0] + 60.*timestamp_list[1] + timestamp_list[2] + timestamp_list[3]
|
2026-07-08 20:58:21 -06:00
|
|
|
if accel_timestamps.size() > 0 and (timestamp - accel_timestamps[-1]) < -1:
|
|
|
|
|
accel_timestamps.clear()
|
|
|
|
|
linear_vecs.clear()
|
|
|
|
|
g_vecs.clear()
|
|
|
|
|
pitch_data.clear()
|
|
|
|
|
roll_data.clear()
|
|
|
|
|
lateral_g_data.clear()
|
2026-07-04 23:49:20 -06:00
|
|
|
if accel_timestamps.size() == max_data_length and not TimeHelpers.is_timestamp_newer_24h(accel_timestamps[-1], timestamp):
|
|
|
|
|
return
|
2026-07-06 13:57:09 -06:00
|
|
|
var insert_idx = Bisect.reverse_bisect(accel_timestamps, timestamp)
|
2026-07-04 23:49:20 -06:00
|
|
|
var x_z = Vector2(g_accel.x, g_accel.z).normalized()
|
|
|
|
|
var y_z = Vector2(g_accel.y, g_accel.z).normalized()
|
|
|
|
|
var pitch = DOWN.angle_to(x_z)
|
|
|
|
|
var roll = y_z.angle_to(DOWN)
|
|
|
|
|
accel_timestamps.insert(insert_idx, timestamp)
|
|
|
|
|
linear_vecs.insert(insert_idx, linear_accel)
|
|
|
|
|
g_vecs.insert(insert_idx, g_accel)
|
|
|
|
|
pitch_data.insert(insert_idx, pitch)
|
|
|
|
|
roll_data.insert(insert_idx, roll)
|
2026-07-06 13:57:09 -06:00
|
|
|
var lateral_g = Vector2(linear_accel.x, linear_accel.y)
|
|
|
|
|
lateral_g_data.insert(insert_idx, lateral_g.normalized()*lateral_g.length())
|
2026-07-04 23:49:20 -06:00
|
|
|
if accel_timestamps.size() > max_data_length:
|
2026-07-06 13:57:09 -06:00
|
|
|
accel_timestamps.pop_back()
|
|
|
|
|
linear_vecs.pop_back()
|
|
|
|
|
g_vecs.pop_back()
|
|
|
|
|
pitch_data.pop_back()
|
|
|
|
|
roll_data.pop_back()
|
|
|
|
|
lateral_g_data.pop_back()
|
2026-07-04 23:49:20 -06:00
|
|
|
_update_avg_pitch()
|
|
|
|
|
_update_avg_roll()
|
2026-07-06 13:57:09 -06:00
|
|
|
_update_g_coefficients()
|
2026-07-04 23:49:20 -06:00
|
|
|
|
|
|
|
|
func _on_mag_data_received(source_ip: String, timestamp_list: Array, mag_vec: Vector3):
|
|
|
|
|
if source_ip != ip_address:
|
|
|
|
|
return
|
|
|
|
|
var timestamp: float = 3600.*timestamp_list[0] + 60.*timestamp_list[1] + timestamp_list[2] + timestamp_list[3]
|
2026-07-08 20:58:21 -06:00
|
|
|
if mag_timestamps.size() > 0 and (timestamp - mag_timestamps[-1]) < -1:
|
|
|
|
|
mag_timestamps.clear()
|
|
|
|
|
mag_vecs.clear()
|
|
|
|
|
heading_data.clear()
|
2026-07-04 23:49:20 -06:00
|
|
|
if mag_timestamps.size() == max_data_length and not TimeHelpers.is_timestamp_newer_24h(mag_timestamps[-1], timestamp):
|
|
|
|
|
return
|
2026-07-06 13:57:09 -06:00
|
|
|
var insert_idx = Bisect.reverse_bisect(mag_timestamps, timestamp)
|
2026-07-04 23:49:20 -06:00
|
|
|
var mag_2d = Vector2(mag_vec.x, mag_vec.y)
|
|
|
|
|
mag_2d.normalized()
|
|
|
|
|
var new_heading_rad = atan2(-mag_2d.y, mag_2d.x)
|
2026-07-06 13:57:09 -06:00
|
|
|
if new_heading_rad < 0:
|
|
|
|
|
new_heading_rad += 2*PI
|
2026-07-04 23:49:20 -06:00
|
|
|
mag_timestamps.insert(insert_idx, timestamp)
|
|
|
|
|
mag_vecs.insert(insert_idx, mag_vec)
|
|
|
|
|
heading_data.insert(insert_idx, new_heading_rad)
|
|
|
|
|
if mag_timestamps.size() > max_data_length:
|
2026-07-06 13:57:09 -06:00
|
|
|
mag_timestamps.pop_back()
|
|
|
|
|
mag_vecs.pop_back()
|
|
|
|
|
heading_data.pop_back()
|
2026-07-04 23:49:20 -06:00
|
|
|
|
|
|
|
|
func _on_gyro_data_received(source_ip: String, timestamp: float):
|
|
|
|
|
if source_ip != ip_address:
|
|
|
|
|
return
|
|
|
|
|
|
2026-07-06 13:57:09 -06:00
|
|
|
func get_derrivative(dataset: Array) -> Array:
|
|
|
|
|
if dataset.size() < 2:
|
|
|
|
|
return [0, []]
|
|
|
|
|
var deltas = []
|
|
|
|
|
var delta_sum = 0
|
|
|
|
|
for i in range(dataset.size()-1):
|
|
|
|
|
var delta = dataset[i+1] - dataset[i]
|
|
|
|
|
deltas.append(dataset[i+1] - dataset[i])
|
|
|
|
|
return [delta_sum / deltas.size(), deltas]
|
|
|
|
|
|
|
|
|
|
func get_array_avg(dataset: Array):
|
|
|
|
|
var data_sum = 0
|
|
|
|
|
for i in dataset:
|
|
|
|
|
data_sum += i
|
|
|
|
|
return data_sum / dataset.size()
|
|
|
|
|
|
|
|
|
|
func get_coefficients(dataset: Array, order: int):
|
|
|
|
|
if order == 0:
|
|
|
|
|
return []
|
|
|
|
|
if dataset.size() <= order:
|
|
|
|
|
order = dataset.size() - 1
|
|
|
|
|
var coefficients = []
|
|
|
|
|
var tmp_dataset = dataset
|
|
|
|
|
var dx_result: Array
|
|
|
|
|
for i in range(order):
|
|
|
|
|
dx_result = get_derrivative(tmp_dataset)
|
|
|
|
|
coefficients.append(dx_result[0])
|
|
|
|
|
tmp_dataset = dx_result[1]
|
|
|
|
|
return coefficients
|
|
|
|
|
|
|
|
|
|
func _update_alt_coefficients():
|
|
|
|
|
if gps_timestamps.size() < 2:
|
|
|
|
|
return
|
|
|
|
|
alt_coefficients = get_coefficients(altitudes, 2)
|
|
|
|
|
|
2026-07-04 23:49:20 -06:00
|
|
|
func _get_current_altitude():
|
|
|
|
|
if gps_timestamps.size() < 3:
|
|
|
|
|
return null
|
|
|
|
|
var current_timestamp = TimeHelpers.get_current_sensor_time()
|
2026-07-06 13:57:09 -06:00
|
|
|
var time_diff = max(0, TimeHelpers.calc_time_diff_24h(gps_timestamps[0], current_timestamp))
|
|
|
|
|
var current_value = altitudes[0]
|
|
|
|
|
for idx in range(alt_coefficients.size()):
|
|
|
|
|
current_value += alt_coefficients[idx] * (time_diff ** idx+1)
|
|
|
|
|
return current_value
|
|
|
|
|
|
|
|
|
|
func _update_speed_coefficients():
|
|
|
|
|
if gps_timestamps.size() < 2:
|
|
|
|
|
return
|
|
|
|
|
speed_coefficients = get_coefficients(speed_data, 2)
|
2026-07-04 23:49:20 -06:00
|
|
|
|
|
|
|
|
func _get_current_speed():
|
|
|
|
|
if gps_timestamps.size() < 3:
|
2026-07-06 13:57:09 -06:00
|
|
|
return
|
2026-07-04 23:49:20 -06:00
|
|
|
var current_timestamp = TimeHelpers.get_current_sensor_time()
|
|
|
|
|
var time_diff = max(0, TimeHelpers.calc_time_diff_24h(gps_timestamps[-1], current_timestamp))
|
2026-07-06 13:57:09 -06:00
|
|
|
var current_value = speed_data[0]
|
|
|
|
|
for idx in range(speed_coefficients.size()):
|
|
|
|
|
current_value += speed_coefficients[idx] * (time_diff ** idx+1)
|
|
|
|
|
return current_value
|
|
|
|
|
|
|
|
|
|
func _update_g_coefficients():
|
|
|
|
|
if accel_timestamps.size() < 2:
|
|
|
|
|
return
|
|
|
|
|
var x_dataset = []
|
|
|
|
|
var y_dataset = []
|
|
|
|
|
for i in lateral_g_data:
|
|
|
|
|
x_dataset.append(i.x)
|
|
|
|
|
y_dataset.append(i.y)
|
|
|
|
|
x_coefficients = get_coefficients(x_dataset, 3)
|
|
|
|
|
y_coefficients = get_coefficients(y_dataset, 3)
|
|
|
|
|
|
|
|
|
|
func _get_current_gs():
|
|
|
|
|
if accel_timestamps.size() < 3:
|
|
|
|
|
return
|
|
|
|
|
var current_timestamp = TimeHelpers.get_current_sensor_time()
|
|
|
|
|
var time_diff = max(0, TimeHelpers.calc_time_diff_24h(accel_timestamps[0], current_timestamp))
|
|
|
|
|
var current_x = lateral_g_data[0].x
|
|
|
|
|
var current_y = lateral_g_data[0].y
|
|
|
|
|
for idx in range(speed_coefficients.size()):
|
|
|
|
|
current_x += x_coefficients[idx] * (time_diff ** idx+1)
|
|
|
|
|
current_y += y_coefficients[idx] * (time_diff ** idx+1)
|
|
|
|
|
return Vector2(current_x, current_y)
|
2026-07-04 23:49:20 -06:00
|
|
|
|
|
|
|
|
func _update_avg_pitch():
|
|
|
|
|
var pitch_sum = 0
|
|
|
|
|
for i in range(accel_timestamps.size()):
|
|
|
|
|
pitch_sum += pitch_data[i]
|
|
|
|
|
pitch_rad = pitch_sum / pitch_data.size()
|
|
|
|
|
|
|
|
|
|
func _update_avg_roll():
|
|
|
|
|
var roll_sum = 0
|
|
|
|
|
for i in range(accel_timestamps.size()):
|
|
|
|
|
roll_sum += roll_data[i]
|
|
|
|
|
roll_rad = roll_sum / roll_data.size()
|
|
|
|
|
|
|
|
|
|
func _update_avg_heading():
|
|
|
|
|
var heading_sum = 0
|
2026-07-06 13:57:09 -06:00
|
|
|
for i in range(min(mag_timestamps.size(), 2)):
|
2026-07-04 23:49:20 -06:00
|
|
|
heading_sum += heading_data[i]
|
|
|
|
|
heading_rad = heading_sum / heading_data.size()
|
|
|
|
|
|
|
|
|
|
|