You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Java应用获取区域海拔:判定无人机挂载设备飞行状态

解决Android应用获取地面海拔以判定无人机飞行状态的问题

核心逻辑

你当前通过GPS获取的是手机的绝对海拔,要判定飞行状态,需要获取当前经纬度对应的地面地形海拔,计算两者的差值,当差值超过设定阈值时即可判定为飞行状态。

可行解决方案

方法1:调用在线地理高程API

这是最便捷的实现方案,通过当前获取到的经纬度,请求专业地理数据服务的高程接口,获取对应位置的地面海拔:

  • 确保应用在AndroidManifest.xml中申请INTERNET权限
  • 在获取到经纬度后,发起异步HTTP请求到高程API
  • 解析返回结果得到地面海拔,计算与手机海拔的差值

方法2:集成离线高程数据集

如果应用需要在无网络环境下运行,可以集成开源离线高程数据集(如SRTM),将数据打包进应用或通过本地存储加载,根据经纬度查询对应海拔。但该方案会增加应用体积,适合特定离线场景。

代码修改示例

以下是在你现有代码基础上,添加在线高程API调用逻辑的完整修改版本:

首先添加网络权限到AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

修改后的TimeService类:

public class TimeService extends Service{
    private final static String TAG = TimeService.class.getName();
    private LocationEntity location = new LocationEntity();
    private Handler handler;
    private FusedLocationProviderClient fusedLocationProviderClient;
    private LocationRequest newlocationRequest;
    private AppDatabase appDatabase;
    // 飞行判定阈值(可根据需求调整,单位:米)
    private static final double FLIGHT_THRESHOLD = 20.0;

    @Override
    public void onCreate() {
        super.onCreate();
        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
        appDatabase = AppDatabase.getDbIntance(this);
        
        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                super.onLocationResult(locationResult);
                Location location = locationResult.getLastLocation();
                if (location == null) return;
                Log.d("TAG", "onLocationResult: 经度="+location.getLongitude()+" 纬度="+location.getLatitude()+" 海拔="+location.getAltitude());
                // 获取地面海拔并判定飞行状态
                fetchGroundElevation(location.getLatitude(), location.getLongitude(), location.getAltitude());
            }
        };

        // 初始化Location配置
        locationSettings();
        startLocationUpdate();
       
        handler = new Handler();
        Runnable runnable = () -> {
            startLocationUpdate();
            Log.d("TAG", "run: 每30秒更新一次位置");
            handler.postDelayed(this, 30000L);
        };
        handler.post(runnable);
    }

    // 配置LocationRequest参数
    public void locationSettings() {
        newlocationRequest = new LocationRequest();
        newlocationRequest.setInterval(30000);
        newlocationRequest.setFastestInterval(5000);
        newlocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    public void updateGPS() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        fusedLocationProviderClient.getLastLocation().addOnSuccessListener(position -> {
            if (position == null) return;
            Log.d("TAG", "updateGPS: 经度="+position.getLongitude()+" 纬度="+position.getLatitude()+" 海拔="+position.getAltitude());
            
            location.setLongitude(position.getLongitude());
            location.setLatitude(position.getLatitude());
            location.setAltitude(position.getAltitude());
            location.setAccuracy(position.getAccuracy());
            location.setSpeed(position.getSpeed());
            
            appDatabase.locationDao().insert(location);
            // 同步判定飞行状态
            fetchGroundElevation(position.getLatitude(), position.getLongitude(), position.getAltitude());
        });
    }

    public void startLocationUpdate() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        fusedLocationProviderClient.requestLocationUpdates(newlocationRequest, locationCallback, null);
        updateGPS();
    }

    // 获取地面海拔并判定飞行状态
    private void fetchGroundElevation(double latitude, double longitude, double phoneAltitude) {
        // 替换为你选用的高程API地址,格式需匹配API要求
        String apiUrl = String.format("你的高程API请求地址?lat=%f&lon=%f", latitude, longitude);
        
        // 使用OkHttp发起异步请求(需添加OkHttp依赖)
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(apiUrl).build();
        
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Log.e(TAG, "获取地面海拔失败: "+e.getMessage());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (!response.isSuccessful()) {
                    Log.e(TAG, "API响应失败: "+response.code());
                    return;
                }
                String responseData = response.body().string();
                double groundElevation = parseGroundElevationFromResponse(responseData);
                
                // 计算相对高度,判定飞行状态
                double relativeHeight = phoneAltitude - groundElevation;
                boolean isFlying = relativeHeight >= FLIGHT_THRESHOLD;
                
                Log.d(TAG, "地面海拔: "+groundElevation+" 相对高度: "+relativeHeight+" 是否飞行: "+isFlying);
                // 可将飞行状态存入数据库或发送通知
            }
        });
    }

    // 解析API响应获取地面海拔(需根据实际API返回格式调整)
    private double parseGroundElevationFromResponse(String response) {
        // 示例:假设API返回JSON格式 {"elevation": 123.45}
        try {
            JSONObject jsonObject = new JSONObject(response);
            return jsonObject.getDouble("elevation");
        } catch (JSONException e) {
            Log.e(TAG, "解析海拔数据失败: "+e.getMessage());
            return 0.0;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

注意事项

  • 选择高程API时,需关注其精度、请求限制及费用(部分免费API有调用次数上限)
  • 网络请求必须放在异步线程中,避免阻塞主线程
  • 可对地面海拔数据进行本地缓存,减少重复请求
  • 若使用离线数据集,需注意数据更新周期和存储优化

内容的提问来源于stack exchange,提问作者Patrick Renaud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 20:57:29