bool MulticopterLandDetector::update()
{
	// first poll for new data from our subscriptions
	updateSubscriptions();

	// only trigger flight conditions if we are armed
	if (!_arming.armed) {
		return true;
	}

	const uint64_t now = hrt_absolute_time();

	// check if we are moving vertically
	bool verticalMovement = fabsf(_vehicleGlobalPosition.vel_d) > _params.maxClimbRate;

	// check if we are moving horizontally
	bool horizontalMovement = sqrtf(_vehicleGlobalPosition.vel_n * _vehicleGlobalPosition.vel_n
					+ _vehicleGlobalPosition.vel_e * _vehicleGlobalPosition.vel_e) > _params.maxVelocity;

	// next look if all rotation angles are not moving
	bool rotating = sqrtf(_sensors.gyro_rad_s[0] * _sensors.gyro_rad_s[0] +
			      _sensors.gyro_rad_s[1] * _sensors.gyro_rad_s[1] +
			      _sensors.gyro_rad_s[2] * _sensors.gyro_rad_s[2]) > _params.maxRotation;

	// check if thrust output is minimal (about half of default)
	bool minimalThrust = _actuators.control[3] <= _params.maxThrottle;

	if (verticalMovement || rotating || !minimalThrust || horizontalMovement) {
		// sensed movement, so reset the land detector
		_landTimer = now;
		return false;
	}

	return now - _landTimer > LAND_DETECTOR_TRIGGER_TIME;
}
Пример #2
0
bool FixedwingLandDetector::update()
{
	// First poll for new data from our subscriptions
	updateSubscriptions();

	const uint64_t now = hrt_absolute_time();
	bool landDetected = false;

	// TODO: reset filtered values on arming?
	_velocity_xy_filtered = 0.95f * _velocity_xy_filtered + 0.05f * sqrtf(_vehicleLocalPosition.vx *
				_vehicleLocalPosition.vx + _vehicleLocalPosition.vy * _vehicleLocalPosition.vy);
	_velocity_z_filtered = 0.95f * _velocity_z_filtered + 0.05f * fabsf(_vehicleLocalPosition.vz);
	_airspeed_filtered = 0.95f * _airspeed_filtered + 0.05f * _airspeed.true_airspeed_m_s;

	// crude land detector for fixedwing
	if (_velocity_xy_filtered < _params.maxVelocity
	    && _velocity_z_filtered < _params.maxClimbRate
	    && _airspeed_filtered < _params.maxAirSpeed) {

		// these conditions need to be stable for a period of time before we trust them
		if (now > _landDetectTrigger) {
			landDetected = true;
		}

	} else {
		// reset land detect trigger
		_landDetectTrigger = now + LAND_DETECTOR_TRIGGER_TIME;
	}

	return landDetected;
}
Пример #3
0
bool VtolLandDetector::update()
{
	updateSubscriptions();
	updateParameterCache(false);

	// this is returned from the mutlicopter land detector
	bool landed = get_landed_state();

	// for vtol we additionally consider airspeed
	if (hrt_elapsed_time(&_airspeed.timestamp) < 500 * 1000) {
		_airspeed_filtered = 0.95f * _airspeed_filtered + 0.05f * _airspeed.true_airspeed_m_s;

	} else {
		// if airspeed does not update, set it to zero and rely on multicopter land detector
		_airspeed_filtered = 0.0f;
	}

	// only consider airspeed if we have been in air before to avoid false
	// detections in the case of wind on the ground
	if (_was_in_air && _airspeed_filtered > _params.maxAirSpeed) {
		landed = false;
	}

	_was_in_air = !landed;

	return landed;
}
Пример #4
0
bool MulticopterLandDetector::update()
{
    // first poll for new data from our subscriptions
    updateSubscriptions();

    // only trigger flight conditions if we are armed
    if (!_arming.armed) {
        _arming_time = 0;
        return true;
    } else if (_arming_time == 0) {
        _arming_time = hrt_absolute_time();
    }

    // return status based on armed state if no position lock is available
    if (_vehicleGlobalPosition.timestamp == 0 ||
            hrt_elapsed_time(&_vehicleGlobalPosition.timestamp) > 500000) {

        // no position lock - not landed if armed
        return !_arming.armed;
    }

    const uint64_t now = hrt_absolute_time();

    float armThresholdFactor = 1.0f;

    // Widen acceptance thresholds for landed state right after arming
    // so that motor spool-up and other effects do not trigger false negatives
    if (hrt_elapsed_time(&_arming_time) < LAND_DETECTOR_ARM_PHASE_TIME) {
        armThresholdFactor = 2.5f;
    }

    // check if we are moving vertically - this might see a spike after arming due to
    // throttle-up vibration. If accelerating fast the throttle thresholds will still give
    // an accurate in-air indication
    bool verticalMovement = fabsf(_vehicleGlobalPosition.vel_d) > _params.maxClimbRate * armThresholdFactor;

    // check if we are moving horizontally
    bool horizontalMovement = sqrtf(_vehicleGlobalPosition.vel_n * _vehicleGlobalPosition.vel_n
                                    + _vehicleGlobalPosition.vel_e * _vehicleGlobalPosition.vel_e) > _params.maxVelocity
                              && _vehicleStatus.condition_global_position_valid;

    // next look if all rotation angles are not moving
    float maxRotationScaled = _params.maxRotation * armThresholdFactor;

    bool rotating = (fabsf(_vehicleAttitude.rollspeed)  > maxRotationScaled) ||
                    (fabsf(_vehicleAttitude.pitchspeed) > maxRotationScaled) ||
                    (fabsf(_vehicleAttitude.yawspeed) > maxRotationScaled);

    // check if thrust output is minimal (about half of default)
    bool minimalThrust = _actuators.control[3] <= _params.maxThrottle;

    if (verticalMovement || rotating || !minimalThrust || horizontalMovement) {
        // sensed movement, so reset the land detector
        _landTimer = now;
        return false;
    }

    return now - _landTimer > LAND_DETECTOR_TRIGGER_TIME;
}
bool MulticopterLandDetector::update()
{
	// first poll for new data from our subscriptions
	updateSubscriptions();

	updateParameterCache(false);

	return get_landed_state();
}
Пример #6
0
void BlockSegwayController::update() {
	// wait for a sensor update, check for exit condition every 100 ms
	if (poll(&_attPoll, 1, 100) < 0) return; // poll error

	uint64_t newTimeStamp = hrt_absolute_time();
	float dt = (newTimeStamp - _timeStamp) / 1.0e6f;
	_timeStamp = newTimeStamp;

	// check for sane values of dt
	// to prevent large control responses
	if (dt > 1.0f || dt < 0) return;

	// set dt for all child blocks
	setDt(dt);

	// check for new updates
	if (_param_update.updated()) updateParams();

	// get new information from subscriptions
	updateSubscriptions();

	// default all output to zero unless handled by mode
	for (unsigned i = 2; i < NUM_ACTUATOR_CONTROLS; i++)
		_actuators.control[i] = 0.0f;

	// only update guidance in auto mode
	if (_status.main_state == MAIN_STATE_AUTO) {
		// update guidance
	}

	// compute speed command
	float spdCmd = -th2v.update(_att.pitch) - q2v.update(_att.pitchspeed);

	// handle autopilot modes
	if (_status.main_state == MAIN_STATE_AUTO ||
	    _status.main_state == MAIN_STATE_ALTCTL ||
	    _status.main_state == MAIN_STATE_POSCTL) {
		_actuators.control[0] = spdCmd;
		_actuators.control[1] = spdCmd;

	} else if (_status.main_state == MAIN_STATE_MANUAL) {
		if (_status.navigation_state == NAVIGATION_STATE_DIRECT) {
			_actuators.control[CH_LEFT] = _manual.throttle;
			_actuators.control[CH_RIGHT] = _manual.pitch;

		} else if (_status.navigation_state == NAVIGATION_STATE_STABILIZE) {
			_actuators.control[0] = spdCmd;
			_actuators.control[1] = spdCmd;
		}
	}

	// update all publications
	updatePublications();

}
Пример #7
0
// Constructor
ContactSet::ContactSet(ResourceCached* resource,
                       UtlString& uri) :
   mResource(resource),
   mUri(uri)
{
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "ContactSet:: this = %p, resource = %p, mUri = '%s'",
                 this, mResource, mUri.data());

   // Set up the subscriptions.
   // Until we have any information from our SUBSCRIBE for "reg" events,
   // there will be one subscription to mUri.
   updateSubscriptions();

   // Start the subscription.
   UtlBoolean ret;
   UtlString mUriNameAddr = "<" + mUri + ">";
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "SubscriptionSet:: mUri = '%s', mUriNameAddr = '%s'",
                 mUri.data(), mUriNameAddr.data());
   ret = getResourceListServer()->getSubscribeClient().
      addSubscription(mUri.data(),
                      REG_EVENT_TYPE,
                      REG_EVENT_CONTENT_TYPE,
                      getResourceListServer()->getClientFromURI(),
                      mUriNameAddr.data(),
                      getResourceListServer()->getClientContactURI(),
                      getResourceListServer()->getResubscribeInterval(),
                      getResourceListSet(),
                      ResourceListSet::subscriptionEventCallbackAsync,
                      ResourceListSet::notifyEventCallbackAsync,
                      mSubscriptionEarlyDialogHandle);
   if (ret)
   {
      OsSysLog::add(FAC_RLS, PRI_DEBUG,
                    "ContactSet:: addSubscription succeeded mUri = '%s', mSubscriptionEarlyDialogHandle = '%s'",
                    mUri.data(),
                    mSubscriptionEarlyDialogHandle.data());
      // Add this ContactSet to mSubscribeMap.
      getResourceListSet()->addSubscribeMapping(&mSubscriptionEarlyDialogHandle,
                                                this);
   }
   else
   {
      OsSysLog::add(FAC_RLS, PRI_WARNING,
                    "ContactSet:: addSubscription failed mUri = '%s', mSubscriptionEarlyDialogHandle = '%s'",
                    mUri.data(),
                    mSubscriptionEarlyDialogHandle.data());
   }
}
bool MulticopterLandDetector::update()
{
	// first poll for new data from our subscriptions
	updateSubscriptions();

	// only trigger flight conditions if we are armed
	if (!_arming.armed) {
		return true;
	}

	// return status based on armed state if no position lock is available
	if (_vehicleGlobalPosition.timestamp == 0 ||
		hrt_elapsed_time(&_vehicleGlobalPosition.timestamp) > 500000) {

		// no position lock - not landed if armed
		return !_arming.armed;
	}

	const uint64_t now = hrt_absolute_time();

	// check if we are moving vertically
	bool verticalMovement = fabsf(_vehicleGlobalPosition.vel_d) > _params.maxClimbRate;

	// check if we are moving horizontally
	bool horizontalMovement = sqrtf(_vehicleGlobalPosition.vel_n * _vehicleGlobalPosition.vel_n
					+ _vehicleGlobalPosition.vel_e * _vehicleGlobalPosition.vel_e) > _params.maxVelocity
					&& _vehicleStatus.condition_global_position_valid;

	// next look if all rotation angles are not moving
	bool rotating = fabsf(_vehicleAttitude.rollspeed)  > _params.maxRotation ||
				    fabsf(_vehicleAttitude.pitchspeed) > _params.maxRotation ||
        			fabsf(_vehicleAttitude.yawspeed)   > _params.maxRotation;

	// check if thrust output is minimal (about half of default)
	bool minimalThrust = _actuators.control[3] <= _params.maxThrottle;

	if (verticalMovement || rotating || !minimalThrust || horizontalMovement) {
		// sensed movement, so reset the land detector
		_landTimer = now;
		return false;
	}

	return now - _landTimer > LAND_DETECTOR_TRIGGER_TIME;
}
Пример #9
0
LandDetectionResult MulticopterLandDetector::update()
{
	// first poll for new data from our subscriptions
	updateSubscriptions();

	updateParameterCache(false);

	if (get_freefall_state()) {
		_state = LANDDETECTION_RES_FREEFALL;

	} else if (get_landed_state()) {
		_state = LANDDETECTION_RES_LANDED;

	} else {
		_state = LANDDETECTION_RES_FLYING;
	}

	return _state;
}
Пример #10
0
bool FixedwingLandDetector::update()
{
	// First poll for new data from our subscriptions
	updateSubscriptions();

	const uint64_t now = hrt_absolute_time();
	bool landDetected = false;

	if (hrt_elapsed_time(&_vehicleLocalPosition.timestamp) < 500 * 1000) {
		float val = 0.97f * _velocity_xy_filtered + 0.03f * sqrtf(_vehicleLocalPosition.vx *
					_vehicleLocalPosition.vx + _vehicleLocalPosition.vy * _vehicleLocalPosition.vy);
		if (PX4_ISFINITE(val)) {
			_velocity_xy_filtered = val;
		}
		val = 0.99f * _velocity_z_filtered + 0.01f * fabsf(_vehicleLocalPosition.vz);

		if (PX4_ISFINITE(val)) {
			_velocity_z_filtered = val;
		}
	}

	if (hrt_elapsed_time(&_airspeed.timestamp) < 500 * 1000) {
		_airspeed_filtered = 0.95f * _airspeed_filtered + 0.05f * _airspeed.true_airspeed_m_s;
	}

	// crude land detector for fixedwing
	if (_velocity_xy_filtered < _params.maxVelocity
	    && _velocity_z_filtered < _params.maxClimbRate
	    && _airspeed_filtered < _params.maxAirSpeed) {

		// these conditions need to be stable for a period of time before we trust them
		if (now > _landDetectTrigger) {
			landDetected = true;
		}

	} else {
		// reset land detect trigger
		_landDetectTrigger = now + LAND_DETECTOR_TRIGGER_TIME;
	}

	return landDetected;
}
void BlockLocalPositionEstimator::update()
{

	// wait for a sensor update, check for exit condition every 100 ms
	int ret = px4_poll(_polls, 3, 100);

	if (ret < 0) {
		/* poll error, count it in perf */
		perf_count(_err_perf);
		return;
	}

	uint64_t newTimeStamp = hrt_absolute_time();
	float dt = (newTimeStamp - _timeStamp) / 1.0e6f;
	_timeStamp = newTimeStamp;

	// set dt for all child blocks
	setDt(dt);

	// auto-detect connected rangefinders while not armed
	bool armedState = _sub_armed.get().armed;

	if (!armedState && (_sub_lidar == NULL || _sub_sonar == NULL)) {
		detectDistanceSensors();
	}

	// reset pos, vel, and terrain on arming

	// XXX this will be re-enabled for indoor use cases using a
	// selection param, but is really not helping outdoors
	// right now.

	// if (!_lastArmedState && armedState) {

	// 	// we just armed, we are at origin on the ground
	// 	_x(X_x) = 0;
	// 	_x(X_y) = 0;
	// 	// reset Z or not? _x(X_z) = 0;

	// 	// we aren't moving, all velocities are zero
	// 	_x(X_vx) = 0;
	// 	_x(X_vy) = 0;
	// 	_x(X_vz) = 0;

	// 	// assume we are on the ground, so terrain alt is local alt
	// 	_x(X_tz) = _x(X_z);

	// 	// reset lowpass filter as well
	// 	_xLowPass.setState(_x);
	// 	_aglLowPass.setState(0);
	// }

	_lastArmedState = armedState;

	// see which updates are available
	bool flowUpdated = _sub_flow.updated();
	bool paramsUpdated = _sub_param_update.updated();
	bool baroUpdated = _sub_sensor.updated();
	bool gpsUpdated = _gps_on.get() && _sub_gps.updated();
	bool visionUpdated = _vision_on.get() && _sub_vision_pos.updated();
	bool mocapUpdated = _sub_mocap.updated();
	bool lidarUpdated = (_sub_lidar != NULL) && _sub_lidar->updated();
	bool sonarUpdated = (_sub_sonar != NULL) && _sub_sonar->updated();
	bool landUpdated = (
				   (_sub_land.get().landed ||
				    ((!_sub_armed.get().armed) && (!_sub_land.get().freefall)))
				   && (!(_lidarInitialized || _mocapInitialized || _visionInitialized || _sonarInitialized))
				   && ((_timeStamp - _time_last_land) > 1.0e6f / LAND_RATE));

	// get new data
	updateSubscriptions();

	// update parameters
	if (paramsUpdated) {
		updateParams();
		updateSSParams();
	}

	// is xy valid?
	bool vxy_stddev_ok = false;

	if (math::max(_P(X_vx, X_vx), _P(X_vy, X_vy)) < _vxy_pub_thresh.get()*_vxy_pub_thresh.get()) {
		vxy_stddev_ok = true;
	}

	if (_validXY) {
		// if valid and gps has timed out, set to not valid
		if (!vxy_stddev_ok && !_gpsInitialized) {
			_validXY = false;
		}

	} else {
		if (vxy_stddev_ok) {
			if (_flowInitialized || _gpsInitialized || _visionInitialized || _mocapInitialized) {
				_validXY = true;
			}
		}
	}

	// is z valid?
	bool z_stddev_ok = sqrtf(_P(X_z, X_z)) < _z_pub_thresh.get();

	if (_validZ) {
		// if valid and baro has timed out, set to not valid
		if (!z_stddev_ok && !_baroInitialized) {
			_validZ = false;
		}

	} else {
		if (z_stddev_ok) {
			_validZ = true;
		}
	}

	// is terrain valid?
	bool tz_stddev_ok = sqrtf(_P(X_tz, X_tz)) < _z_pub_thresh.get();

	if (_validTZ) {
		if (!tz_stddev_ok) {
			_validTZ = false;
		}

	} else {
		if (tz_stddev_ok) {
			_validTZ = true;
		}
	}

	// timeouts
	if (_validXY) {
		_time_last_xy = _timeStamp;
	}

	if (_validZ) {
		_time_last_z = _timeStamp;
	}

	if (_validTZ) {
		_time_last_tz = _timeStamp;
	}

	// check timeouts
	checkTimeouts();

	// if we have no lat, lon initialize projection at 0,0
	if (_validXY && !_map_ref.init_done) {
		map_projection_init(&_map_ref,
				    _init_origin_lat.get(),
				    _init_origin_lon.get());
	}

	// reinitialize x if necessary
	bool reinit_x = false;

	for (int i = 0; i < n_x; i++) {
		// should we do a reinit
		// of sensors here?
		// don't want it to take too long
		if (!PX4_ISFINITE(_x(i))) {
			reinit_x = true;
			mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] reinit x, x(%d) not finite", i);
			break;
		}
	}

	if (reinit_x) {
		for (int i = 0; i < n_x; i++) {
			_x(i) = 0;
		}

		mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] reinit x");
	}

	// force P symmetry and reinitialize P if necessary
	bool reinit_P = false;

	for (int i = 0; i < n_x; i++) {
		for (int j = 0; j <= i; j++) {
			if (!PX4_ISFINITE(_P(i, j))) {
				reinit_P = true;
			}

			if (i == j) {
				// make sure diagonal elements are positive
				if (_P(i, i) <= 0) {
					reinit_P = true;
				}

			} else {
				// copy elememnt from upper triangle to force
				// symmetry
				_P(j, i) = _P(i, j);
			}

			if (reinit_P) { break; }
		}

		if (reinit_P) { break; }
	}

	if (reinit_P) {
		mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] reinit P");
		initP();
	}

	// do prediction
	predict();

	// sensor corrections/ initializations
	if (gpsUpdated) {
		if (!_gpsInitialized) {
			gpsInit();

		} else {
			gpsCorrect();
		}
	}

	if (baroUpdated) {
		if (!_baroInitialized) {
			baroInit();

		} else {
			baroCorrect();
		}
	}

	if (lidarUpdated) {
		if (!_lidarInitialized) {
			lidarInit();

		} else {
			lidarCorrect();
		}
	}

	if (sonarUpdated) {
		if (!_sonarInitialized) {
			sonarInit();

		} else {
			sonarCorrect();
		}
	}

	if (flowUpdated) {
		if (!_flowInitialized) {
			flowInit();

		} else {
			perf_begin(_loop_perf);// TODO
			flowCorrect();
			//perf_count(_interval_perf);
			perf_end(_loop_perf);
		}
	}

	if (visionUpdated) {
		if (!_visionInitialized) {
			visionInit();

		} else {
			visionCorrect();
		}
	}

	if (mocapUpdated) {
		if (!_mocapInitialized) {
			mocapInit();

		} else {
			mocapCorrect();
		}
	}

	if (landUpdated) {
		if (!_landInitialized) {
			landInit();

		} else {
			landCorrect();
		}
	}

	if (_altOriginInitialized) {
		// update all publications if possible
		publishLocalPos();
		publishEstimatorStatus();
		_pub_innov.update();

		if (_validXY) {
			publishGlobalPos();
		}
	}

	// propagate delayed state, no matter what
	// if state is frozen, delayed state still
	// needs to be propagated with frozen state
	float dt_hist = 1.0e-6f * (_timeStamp - _time_last_hist);

	if (_time_last_hist == 0 ||
	    (dt_hist > HIST_STEP)) {
		_tDelay.update(Scalar<uint64_t>(_timeStamp));
		_xDelay.update(_x);
		_time_last_hist = _timeStamp;
	}
}
void BlockLocalPositionEstimator::update()
{
	// wait for a sensor update, check for exit condition every 100 ms
	int ret = px4_poll(_polls, 3, 100);

	if (ret < 0) {
		return;
	}

	uint64_t newTimeStamp = hrt_absolute_time();
	float dt = (newTimeStamp - _timeStamp) / 1.0e6f;
	_timeStamp = newTimeStamp;

	// set dt for all child blocks
	setDt(dt);

	// auto-detect connected rangefinders while not armed
	bool armedState = _sub_armed.get().armed;

	if (!armedState && (_sub_lidar == nullptr || _sub_sonar == nullptr)) {
		// detect distance sensors
		for (int i = 0; i < N_DIST_SUBS; i++) {
			uORB::Subscription<distance_sensor_s> *s = _dist_subs[i];

			if (s == _sub_lidar || s == _sub_sonar) { continue; }

			if (s->updated()) {
				s->update();

				if (s->get().timestamp == 0) { continue; }

				if (s->get().type == distance_sensor_s::MAV_DISTANCE_SENSOR_LASER &&
				    s->get().orientation == distance_sensor_s::ROTATION_DOWNWARD_FACING &&
				    _sub_lidar == nullptr) {
					_sub_lidar = s;
					mavlink_and_console_log_info(&mavlink_log_pub, "%sDownward-facing Lidar detected with ID %i", msg_label, i);

				} else if (s->get().type == distance_sensor_s::MAV_DISTANCE_SENSOR_ULTRASOUND &&
					   s->get().orientation == distance_sensor_s::ROTATION_DOWNWARD_FACING &&
					   _sub_sonar == nullptr) {
					_sub_sonar = s;
					mavlink_and_console_log_info(&mavlink_log_pub, "%sDownward-facing Sonar detected with ID %i", msg_label, i);
				}
			}
		}
	}

	// reset pos, vel, and terrain on arming

	// XXX this will be re-enabled for indoor use cases using a
	// selection param, but is really not helping outdoors
	// right now.

	// if (!_lastArmedState && armedState) {

	//      // we just armed, we are at origin on the ground
	//      _x(X_x) = 0;
	//      _x(X_y) = 0;
	//      // reset Z or not? _x(X_z) = 0;

	//      // we aren't moving, all velocities are zero
	//      _x(X_vx) = 0;
	//      _x(X_vy) = 0;
	//      _x(X_vz) = 0;

	//      // assume we are on the ground, so terrain alt is local alt
	//      _x(X_tz) = _x(X_z);

	//      // reset lowpass filter as well
	//      _xLowPass.setState(_x);
	//      _aglLowPass.setState(0);
	// }

	_lastArmedState = armedState;

	// see which updates are available
	bool paramsUpdated = _sub_param_update.updated();
	_baroUpdated = false;

	if ((_fusion.get() & FUSE_BARO) && _sub_sensor.updated()) {
		int32_t baro_timestamp_relative = _sub_sensor.get().baro_timestamp_relative;

		if (baro_timestamp_relative != _sub_sensor.get().RELATIVE_TIMESTAMP_INVALID) {
			uint64_t baro_timestamp = _sub_sensor.get().timestamp +	\
						  _sub_sensor.get().baro_timestamp_relative;

			if (baro_timestamp != _timeStampLastBaro) {
				_baroUpdated = true;
				_timeStampLastBaro = baro_timestamp;
			}
		}
	}

	_flowUpdated = (_fusion.get() & FUSE_FLOW) && _sub_flow.updated();
	_gpsUpdated = (_fusion.get() & FUSE_GPS) && _sub_gps.updated();
	_visionUpdated = (_fusion.get() & FUSE_VIS_POS) && _sub_vision_pos.updated();
	_mocapUpdated = _sub_mocap.updated();
	_lidarUpdated = (_sub_lidar != nullptr) && _sub_lidar->updated();
	_sonarUpdated = (_sub_sonar != nullptr) && _sub_sonar->updated();
	_landUpdated = landed() && ((_timeStamp - _time_last_land) > 1.0e6f / LAND_RATE);// throttle rate
	bool targetPositionUpdated = _sub_landing_target_pose.updated();

	// get new data
	updateSubscriptions();

	// update parameters
	if (paramsUpdated) {
		updateParams();
		updateSSParams();
	}

	// is xy valid?
	bool vxy_stddev_ok = false;

	if (math::max(_P(X_vx, X_vx), _P(X_vy, X_vy)) < _vxy_pub_thresh.get() * _vxy_pub_thresh.get()) {
		vxy_stddev_ok = true;
	}

	if (_estimatorInitialized & EST_XY) {
		// if valid and gps has timed out, set to not valid
		if (!vxy_stddev_ok && (_sensorTimeout & SENSOR_GPS)) {
			_estimatorInitialized &= ~EST_XY;
		}

	} else {
		if (vxy_stddev_ok) {
			if (!(_sensorTimeout & SENSOR_GPS)
			    || !(_sensorTimeout & SENSOR_FLOW)
			    || !(_sensorTimeout & SENSOR_VISION)
			    || !(_sensorTimeout & SENSOR_MOCAP)
			    || !(_sensorTimeout & SENSOR_LAND)
			    || !(_sensorTimeout & SENSOR_LAND_TARGET)
			   ) {
				_estimatorInitialized |= EST_XY;
			}
		}
	}

	// is z valid?
	bool z_stddev_ok = sqrtf(_P(X_z, X_z)) < _z_pub_thresh.get();

	if (_estimatorInitialized & EST_Z) {
		// if valid and baro has timed out, set to not valid
		if (!z_stddev_ok && (_sensorTimeout & SENSOR_BARO)) {
			_estimatorInitialized &= ~EST_Z;
		}

	} else {
		if (z_stddev_ok) {
			_estimatorInitialized |= EST_Z;
		}
	}

	// is terrain valid?
	bool tz_stddev_ok = sqrtf(_P(X_tz, X_tz)) < _z_pub_thresh.get();

	if (_estimatorInitialized & EST_TZ) {
		if (!tz_stddev_ok) {
			_estimatorInitialized &= ~EST_TZ;
		}

	} else {
		if (tz_stddev_ok) {
			_estimatorInitialized |= EST_TZ;
		}
	}

	// check timeouts
	checkTimeouts();

	// if we have no lat, lon initialize projection to LPE_LAT, LPE_LON parameters
	if (!_map_ref.init_done && (_estimatorInitialized & EST_XY) && _fake_origin.get()) {
		map_projection_init(&_map_ref,
				    _init_origin_lat.get(),
				    _init_origin_lon.get());

		// set timestamp when origin was set to current time
		_time_origin = _timeStamp;

		mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] global origin init (parameter) : lat %6.2f lon %6.2f alt %5.1f m",
					     double(_init_origin_lat.get()), double(_init_origin_lon.get()), double(_altOrigin));
	}

	// reinitialize x if necessary
	bool reinit_x = false;

	for (int i = 0; i < n_x; i++) {
		// should we do a reinit
		// of sensors here?
		// don't want it to take too long
		if (!PX4_ISFINITE(_x(i))) {
			reinit_x = true;
			mavlink_and_console_log_info(&mavlink_log_pub, "%sreinit x, x(%d) not finite", msg_label, i);
			break;
		}
	}

	if (reinit_x) {
		for (int i = 0; i < n_x; i++) {
			_x(i) = 0;
		}

		mavlink_and_console_log_info(&mavlink_log_pub, "%sreinit x", msg_label);
	}

	// force P symmetry and reinitialize P if necessary
	bool reinit_P = false;

	for (int i = 0; i < n_x; i++) {
		for (int j = 0; j <= i; j++) {
			if (!PX4_ISFINITE(_P(i, j))) {
				mavlink_and_console_log_info(&mavlink_log_pub,
							     "%sreinit P (%d, %d) not finite", msg_label, i, j);
				reinit_P = true;
			}

			if (i == j) {
				// make sure diagonal elements are positive
				if (_P(i, i) <= 0) {
					mavlink_and_console_log_info(&mavlink_log_pub,
								     "%sreinit P (%d, %d) negative", msg_label, i, j);
					reinit_P = true;
				}

			} else {
				// copy elememnt from upper triangle to force
				// symmetry
				_P(j, i) = _P(i, j);
			}

			if (reinit_P) { break; }
		}

		if (reinit_P) { break; }
	}

	if (reinit_P) {
		initP();
	}

	// do prediction
	predict();

	// sensor corrections/ initializations
	if (_gpsUpdated) {
		if (_sensorTimeout & SENSOR_GPS) {
			gpsInit();

		} else {
			gpsCorrect();
		}
	}

	if (_baroUpdated) {
		if (_sensorTimeout & SENSOR_BARO) {
			baroInit();

		} else {
			baroCorrect();
		}
	}

	if (_lidarUpdated) {
		if (_sensorTimeout & SENSOR_LIDAR) {
			lidarInit();

		} else {
			lidarCorrect();
		}
	}

	if (_sonarUpdated) {
		if (_sensorTimeout & SENSOR_SONAR) {
			sonarInit();

		} else {
			sonarCorrect();
		}
	}

	if (_flowUpdated) {
		if (_sensorTimeout & SENSOR_FLOW) {
			flowInit();

		} else {
			flowCorrect();
		}
	}

	if (_visionUpdated) {
		if (_sensorTimeout & SENSOR_VISION) {
			visionInit();

		} else {
			visionCorrect();
		}
	}

	if (_mocapUpdated) {
		if (_sensorTimeout & SENSOR_MOCAP) {
			mocapInit();

		} else {
			mocapCorrect();
		}
	}

	if (_landUpdated) {
		if (_sensorTimeout & SENSOR_LAND) {
			landInit();

		} else {
			landCorrect();
		}
	}

	if (targetPositionUpdated) {
		if (_sensorTimeout & SENSOR_LAND_TARGET) {
			landingTargetInit();

		} else {
			landingTargetCorrect();
		}
	}

	if (_altOriginInitialized) {
		// update all publications if possible
		publishLocalPos();
		publishEstimatorStatus();
		_pub_innov.get().timestamp = _timeStamp;
		_pub_innov.update();

		if ((_estimatorInitialized & EST_XY) && (_map_ref.init_done || _fake_origin.get())) {
			publishGlobalPos();
		}
	}

	// propagate delayed state, no matter what
	// if state is frozen, delayed state still
	// needs to be propagated with frozen state
	float dt_hist = 1.0e-6f * (_timeStamp - _time_last_hist);

	if (_time_last_hist == 0 ||
	    (dt_hist > HIST_STEP)) {
		_tDelay.update(Scalar<uint64_t>(_timeStamp));
		_xDelay.update(_x);
		_time_last_hist = _timeStamp;
	}
}
Пример #13
0
void BlockMultiModeBacksideAutopilot::update()
{
	// wait for a sensor update, check for exit condition every 100 ms
	if (poll(&_attPoll, 1, 100) < 0) return; // poll error

	uint64_t newTimeStamp = hrt_absolute_time();
	float dt = (newTimeStamp - _timeStamp) / 1.0e6f;
	_timeStamp = newTimeStamp;

	// check for sane values of dt
	// to prevent large control responses
	if (dt > 1.0f || dt < 0) return;

	// set dt for all child blocks
	setDt(dt);

	// store old position command before update if new command sent
	if (_posCmd.updated()) {
		_lastPosCmd = _posCmd.getData();
	}

	// check for new updates
	if (_param_update.updated()) updateParams();

	// get new information from subscriptions
	updateSubscriptions();

	// default all output to zero unless handled by mode
	for (unsigned i = 4; i < NUM_ACTUATOR_CONTROLS; i++)
		_actuators.control[i] = 0.0f;

	// only update guidance in auto mode
	if (_status.state_machine == SYSTEM_STATE_AUTO) {
		// update guidance
		_guide.update(_pos, _att, _posCmd, _lastPosCmd);
	}

	// XXX handle STABILIZED (loiter on spot) as well
	// once the system switches from manual or auto to stabilized
	// the setpoint should update to loitering around this position

	// handle autopilot modes
	if (_status.state_machine == SYSTEM_STATE_AUTO ||
	    _status.state_machine == SYSTEM_STATE_STABILIZED) {

		// update guidance
		_guide.update(_pos, _att, _posCmd, _lastPosCmd);

		// calculate velocity, XXX should be airspeed, but using ground speed for now
		float v = sqrtf(_pos.vx * _pos.vx + _pos.vy * _pos.vy + _pos.vz * _pos.vz);

		// altitude hold
		float dThrottle = _h2Thr.update(_posCmd.altitude - _pos.alt);

		// heading hold
		float psiError = _wrap_pi(_guide.getPsiCmd() - _att.yaw);
		float phiCmd = _phiLimit.update(_psi2Phi.update(psiError));
		float pCmd = _phi2P.update(phiCmd - _att.roll);

		// velocity hold
		// negative sign because nose over to increase speed
		float thetaCmd = _theLimit.update(-_v2Theta.update(
				_vLimit.update(_vCmd.get()) - v));
		float qCmd = _theta2Q.update(thetaCmd - _att.pitch);

		// yaw rate cmd
		float rCmd = 0;

		// stabilization
		_stabilization.update(pCmd, qCmd, rCmd,
				      _att.rollspeed, _att.pitchspeed, _att.yawspeed);

		// output
		_actuators.control[CH_AIL] = _stabilization.getAileron() + _trimAil.get();
		_actuators.control[CH_ELV] = _stabilization.getElevator() + _trimElv.get();
		_actuators.control[CH_RDR] = _stabilization.getRudder() + _trimRdr.get();
		_actuators.control[CH_THR] = dThrottle + _trimThr.get();

		// XXX limit throttle to manual setting (safety) for now.
		// If it turns out to be confusing, it can be removed later once
		// a first binary release can be targeted.
		// This is not a hack, but a design choice.

		/* do not limit in HIL */
		if (!_status.flag_hil_enabled) {
			/* limit to value of manual throttle */
			_actuators.control[CH_THR] = (_actuators.control[CH_THR] < _manual.throttle) ?
						     _actuators.control[CH_THR] : _manual.throttle;
		}

	} else if (_status.state_machine == SYSTEM_STATE_MANUAL) {

		if (_status.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_DIRECT) {
			_actuators.control[CH_AIL] = _manual.roll;
			_actuators.control[CH_ELV] = _manual.pitch;
			_actuators.control[CH_RDR] = _manual.yaw;
			_actuators.control[CH_THR] = _manual.throttle;

		} else if (_status.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_SAS) {

			// calculate velocity, XXX should be airspeed, but using ground speed for now
			float v = sqrtf(_pos.vx * _pos.vx + _pos.vy * _pos.vy + _pos.vz * _pos.vz);

			// pitch channel -> rate of climb
			// TODO, might want to put a gain on this, otherwise commanding
			// from +1 -> -1 m/s for rate of climb
			//float dThrottle = _roc2Thr.update(
			//_rocMax.get()*_manual.pitch - _pos.vz);

			// roll channel -> bank angle
			float phiCmd = _phiLimit.update(_manual.roll * _phiLimit.getMax());
			float pCmd = _phi2P.update(phiCmd - _att.roll);

			// throttle channel -> velocity
			// negative sign because nose over to increase speed
			float vCmd = _manual.throttle * (_vLimit.getMax() - _vLimit.getMin()) + _vLimit.getMin();
			float thetaCmd = _theLimit.update(-_v2Theta.update(_vLimit.update(vCmd) - v));
			float qCmd = _theta2Q.update(thetaCmd - _att.pitch);

			// yaw rate cmd
			float rCmd = 0;

			// stabilization
			_stabilization.update(pCmd, qCmd, rCmd,
					      _att.rollspeed, _att.pitchspeed, _att.yawspeed);

			// output
			_actuators.control[CH_AIL] = _stabilization.getAileron() + _trimAil.get();
			_actuators.control[CH_ELV] = _stabilization.getElevator() + _trimElv.get();
			_actuators.control[CH_RDR] = _stabilization.getRudder() + _trimRdr.get();

			// currenlty using manual throttle
			// XXX if you enable this watch out, vz might be very noisy
			//_actuators.control[CH_THR] = dThrottle + _trimThr.get();
			_actuators.control[CH_THR] = _manual.throttle;

			// XXX limit throttle to manual setting (safety) for now.
			// If it turns out to be confusing, it can be removed later once
			// a first binary release can be targeted.
			// This is not a hack, but a design choice.

			/* do not limit in HIL */
			if (!_status.flag_hil_enabled) {
				/* limit to value of manual throttle */
				_actuators.control[CH_THR] = (_actuators.control[CH_THR] < _manual.throttle) ?
							     _actuators.control[CH_THR] : _manual.throttle;
			}
		}

		// body rates controller, disabled for now
		else if (0 /*_status.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_SAS*/) {

			_stabilization.update(_manual.roll, _manual.pitch, _manual.yaw,
					      _att.rollspeed, _att.pitchspeed, _att.yawspeed);

			_actuators.control[CH_AIL] = _stabilization.getAileron();
			_actuators.control[CH_ELV] = _stabilization.getElevator();
			_actuators.control[CH_RDR] = _stabilization.getRudder();
			_actuators.control[CH_THR] = _manual.throttle;
		}
	}

	// update all publications
	updatePublications();
}
void BlockLocalPositionEstimator::update()
{

	// wait for a sensor update, check for exit condition every 100 ms
	int ret = px4_poll(_polls, 3, 100);

	if (ret < 0) {
		/* poll error, count it in perf */
		perf_count(_err_perf);
		return;
	}

	uint64_t newTimeStamp = hrt_absolute_time();
	float dt = (newTimeStamp - _timeStamp) / 1.0e6f;
	_timeStamp = newTimeStamp;

	// set dt for all child blocks
	setDt(dt);

	// auto-detect connected rangefinders while not armed
	bool armedState = _sub_armed.get().armed;

	if (!armedState && (_sub_lidar == NULL || _sub_sonar == NULL)) {
		detectDistanceSensors();
	}

	// reset pos, vel, and terrain on arming
	if (!_lastArmedState && armedState) {

		// we just armed, we are at home position on the ground
		_x(X_x) = 0;
		_x(X_y) = 0;

		// the pressure altitude of home may have drifted, so we don't
		// reset z to zero

		// reset flow integral
		_flowX = 0;
		_flowY = 0;

		// we aren't moving, all velocities are zero
		_x(X_vx) = 0;
		_x(X_vy) = 0;
		_x(X_vz) = 0;

		// assume we are on the ground, so terrain alt is local alt
		_x(X_tz) = _x(X_z);

		// reset lowpass filter as well
		_xLowPass.setState(_x);
	}

	_lastArmedState = armedState;

	// see which updates are available
	bool flowUpdated = _sub_flow.updated();
	bool paramsUpdated = _sub_param_update.updated();
	bool baroUpdated = _sub_sensor.updated();
	bool gpsUpdated = _gps_on.get() && _sub_gps.updated();
	bool homeUpdated = _sub_home.updated();
	bool visionUpdated = _vision_on.get() && _sub_vision_pos.updated();
	bool mocapUpdated = _sub_mocap.updated();
	bool lidarUpdated = (_sub_lidar != NULL) && _sub_lidar->updated();
	bool sonarUpdated = (_sub_sonar != NULL) && _sub_sonar->updated();

	// get new data
	updateSubscriptions();

	// update parameters
	if (paramsUpdated) {
		updateParams();
		updateSSParams();
	}

	// update home position projection
	if (homeUpdated) {
		updateHome();
	}

	// is xy valid?
	bool xy_stddev_ok = sqrtf(math::max(_P(X_x, X_x), _P(X_y, X_y))) < _xy_pub_thresh.get();

	if (_validXY) {
		// if valid and gps has timed out, set to not valid
		if (!xy_stddev_ok && !_gpsInitialized) {
			_validXY = false;
		}

	} else {
		if (xy_stddev_ok) {
			_validXY = true;
		}
	}

	// is z valid?
	bool z_stddev_ok = sqrtf(_P(X_z, X_z)) < _z_pub_thresh.get();

	if (_validZ) {
		// if valid and baro has timed out, set to not valid
		if (!z_stddev_ok && !_baroInitialized) {
			_validZ = false;
		}

	} else {
		if (z_stddev_ok) {
			_validZ = true;
		}
	}

	// is terrain valid?
	bool tz_stddev_ok = sqrtf(_P(X_tz, X_tz)) < _z_pub_thresh.get();

	if (_validTZ) {
		if (!tz_stddev_ok) {
			_validTZ = false;
		}

	} else {
		if (tz_stddev_ok) {
			_validTZ = true;
		}
	}

	// timeouts
	if (_validXY) {
		_time_last_xy = _timeStamp;
	}

	if (_validZ) {
		_time_last_z = _timeStamp;
	}

	if (_validTZ) {
		_time_last_tz = _timeStamp;
	}

	// check timeouts
	checkTimeouts();

	// if we have no lat, lon initialize projection at 0,0
	if (_validXY && !_map_ref.init_done) {
		map_projection_init(&_map_ref,
				    _init_home_lat.get(),
				    _init_home_lon.get());
	}

	// reinitialize x if necessary
	bool reinit_x = false;

	for (int i = 0; i < n_x; i++) {
		// should we do a reinit
		// of sensors here?
		// don't want it to take too long
		if (!PX4_ISFINITE(_x(i))) {
			reinit_x = true;
			break;
		}
	}

	if (reinit_x) {
		for (int i = 0; i < n_x; i++) {
			_x(i) = 0;
		}

		mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] reinit x");
	}

	// reinitialize P if necessary
	bool reinit_P = false;

	for (int i = 0; i < n_x; i++) {
		for (int j = 0; j < n_x; j++) {
			if (!PX4_ISFINITE(_P(i, j))) {
				reinit_P = true;
				break;
			}
		}

		if (reinit_P) { break; }
	}

	if (reinit_P) {
		mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] reinit P");
		initP();
	}

	// do prediction
	predict();

	// sensor corrections/ initializations
	if (gpsUpdated) {
		if (!_gpsInitialized) {
			gpsInit();

		} else {
			gpsCorrect();
		}
	}

	if (baroUpdated) {
		if (!_baroInitialized) {
			baroInit();

		} else {
			baroCorrect();
		}
	}

	if (lidarUpdated) {
		if (!_lidarInitialized) {
			lidarInit();

		} else {
			lidarCorrect();
		}
	}

	if (sonarUpdated) {
		if (!_sonarInitialized) {
			sonarInit();

		} else {
			sonarCorrect();
		}
	}

	if (flowUpdated) {
		if (!_flowInitialized) {
			flowInit();

		} else {
			perf_begin(_loop_perf);// TODO
			flowCorrect();
			//perf_count(_interval_perf);
			perf_end(_loop_perf);
		}
	}

	if (visionUpdated) {
		if (!_visionInitialized) {
			visionInit();

		} else {
			visionCorrect();
		}
	}

	if (mocapUpdated) {
		if (!_mocapInitialized) {
			mocapInit();

		} else {
			mocapCorrect();
		}
	}

	if (_altHomeInitialized) {
		// update all publications if possible
		publishLocalPos();
		publishEstimatorStatus();

		if (_validXY) {
			publishGlobalPos();
		}
	}

	// propagate delayed state, no matter what
	// if state is frozen, delayed state still
	// needs to be propagated with frozen state
	float dt_hist = 1.0e-6f * (_timeStamp - _time_last_hist);

	if (_time_last_hist == 0 ||
	    (dt_hist > HIST_STEP)) {
		_tDelay.update(Scalar<uint64_t>(_timeStamp));
		_xDelay.update(_x);
		_time_last_hist = _timeStamp;
	}
}
Пример #15
0
void BlockMultiModeBacksideAutopilot::update()
{
	// wait for a sensor update, check for exit condition every 100 ms
	if (poll(&_attPoll, 1, 100) < 0) return; // poll error

	uint64_t newTimeStamp = hrt_absolute_time();
	float dt = (newTimeStamp - _timeStamp) / 1.0e6f;
	_timeStamp = newTimeStamp;

	// check for sane values of dt
	// to prevent large control responses
	if (dt > 1.0f || dt < 0) return;

	// set dt for all child blocks
	setDt(dt);

	// store old position command before update if new command sent
	if (_posCmd.updated()) {
		_lastPosCmd = _posCmd.getData();
	}

	// check for new updates
	if (_param_update.updated()) updateParams();

	// get new information from subscriptions
	updateSubscriptions();

	// default all output to zero unless handled by mode
	for (unsigned i = 4; i < NUM_ACTUATOR_CONTROLS; i++)
		_actuators.control[i] = 0.0f;

	// handle autopilot modes
	if (_status.state_machine == SYSTEM_STATE_STABILIZED) {
		_stabilization.update(
			_ratesCmd.roll, _ratesCmd.pitch, _ratesCmd.yaw,
			_att.rollspeed, _att.pitchspeed, _att.yawspeed);
		_actuators.control[CH_AIL] = _stabilization.getAileron();
		_actuators.control[CH_ELV] = _stabilization.getElevator();
		_actuators.control[CH_RDR] = _stabilization.getRudder();
		_actuators.control[CH_THR] = _manual.throttle;

	} else if (_status.state_machine == SYSTEM_STATE_AUTO) {
		// update guidance
		_guide.update(_pos, _att, _posCmd, _lastPosCmd);

		// calculate velocity, XXX should be airspeed, but using ground speed for now
		float v = sqrtf(_pos.vx * _pos.vx + _pos.vy * _pos.vy + _pos.vz * _pos.vz);

		// commands
		float rCmd = 0;

		_backsideAutopilot.update(
			_posCmd.altitude, _vCmd.get(), rCmd, _guide.getPsiCmd(),
			_pos.alt, v,
			_att.roll, _att.pitch, _att.yaw,
			_att.rollspeed, _att.pitchspeed, _att.yawspeed
		);
		_actuators.control[CH_AIL] = _backsideAutopilot.getAileron();
		_actuators.control[CH_ELV] = _backsideAutopilot.getElevator();
		_actuators.control[CH_RDR] = _backsideAutopilot.getRudder();
		_actuators.control[CH_THR] = _backsideAutopilot.getThrottle();

	} else if (_status.state_machine == SYSTEM_STATE_MANUAL) {
		_actuators.control[CH_AIL] = _manual.roll;
		_actuators.control[CH_ELV] = _manual.pitch;
		_actuators.control[CH_RDR] = _manual.yaw;
		_actuators.control[CH_THR] = _manual.throttle;
	}

	// update all publications
	updatePublications();
}
Пример #16
0
void AppearanceGroup::subscriptionEventCallback(
   const UtlString* earlyDialogHandle,
   const UtlString* dialogHandle,
   SipSubscribeClient::SubscriptionState newState,
   const UtlString* subscriptionState)
{
   Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                 "AppearanceGroup::subscriptionEventCallback mUri = '%s', newState = %d, earlyDialogHandle = '%s', dialogHandle = '%s', subscriptionState = '%s'",
                 mSharedUser.data(),
                 newState, mSubscriptionEarlyDialogHandle.data(),
                 dialogHandle->data(), subscriptionState->data());

   switch (newState)
   {
   case SipSubscribeClient::SUBSCRIPTION_INITIATED:
      break;
   case SipSubscribeClient::SUBSCRIPTION_SETUP:
   {
      // Check that we don't have too many subscriptions.
      if (mSubscriptions.entries() <
          getAppearanceAgent()->getMaxRegSubscInGroup())
      {
         // Add this AppearanceGroup to mNotifyMap for the subscription.
         getAppearanceAgent()->getAppearanceGroupSet().addNotifyMapping(dialogHandle, this);
         // Remember it in mSubscriptions, if there isn't already an entry.
         if (!mSubscriptions.find(dialogHandle))
         {
            mSubscriptions.insertKeyAndValue(new UtlString(*dialogHandle), new UtlHashMap);
            Os::Logger::instance().log(FAC_SAA, PRI_INFO,
                          "AppearanceGroup::subscriptionEventCallback "
                          "subscription setup for AppearanceGroup = '%s', dialogHandle = '%s'",
                          mSharedUser.data(), dialogHandle->data());
         }
         else
         {
            Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                          "AppearanceGroup::subscriptionEventCallback "
                          "mSubscriptions element already exists for this dialog handle mUri = '%s', dialogHandle = '%s'",
                          mSharedUser.data(),
                          dialogHandle->data());
         }
      }
      else
      {
         Os::Logger::instance().log(FAC_SAA, PRI_ERR,
                       "AppearanceGroup::subscriptionEventCallback "
                       "cannot add reg subscription with dialog handle '%s', already %zu in AppearanceGroup '%s'",
                       dialogHandle->data(), mSubscriptions.entries(),
                       mSharedUser.data());
      }
   }
   break;
   case SipSubscribeClient::SUBSCRIPTION_TERMINATED:
   {
      // Remove this dialogHandle from mNotifyMap for the subscription.
      // A new one will be added later if necessary.
      mAppearanceGroupSet->deleteNotifyMapping(dialogHandle);

      // Delete this subscription from mSubscriptions.
      mSubscriptions.destroy(dialogHandle);

      // Delete this AppearanceGroup from mSubscribeMap (for the "reg" subscription).
      mAppearanceGroupSet->deleteSubscribeMapping(&mSubscriptionEarlyDialogHandle);

      // End the terminated "reg" subscription.
      UtlBoolean ret;
      ret = getAppearanceAgent()->getSubscribeClient().
         endSubscriptionGroup(mSubscriptionEarlyDialogHandle);
      Os::Logger::instance().log(FAC_SAA,
                    ret ? PRI_INFO : PRI_WARNING,
                    "AppearanceGroup::subscriptionEventCallback "
                    "endSubscriptionGroup %s mSharedUser = '******', mSubscriptionEarlyDialogHandle = '%s'",
                    ret ? "succeeded" : "failed",
                    mSharedUser.data(),
                    mSubscriptionEarlyDialogHandle.data());
      OsTask::delay(getAppearanceAgent()->getChangeDelay());

      // Check to see if there is supposed to be a group with this name.
      if (mAppearanceGroupSet->findAppearanceGroup(mSharedUser))
      {
         Os::Logger::instance().log(FAC_SAA, PRI_WARNING,
                       "AppearanceGroup::subscriptionEventCallback "
                       "subscription terminated for AppearanceGroup '%s', but should exist. Retrying subscription",
                       mSharedUser.data());
         startSubscription();
      }
      else
      {
         Os::Logger::instance().log(FAC_SAA, PRI_INFO,
                       "AppearanceGroup::subscriptionEventCallback "
                       "subscription terminated for AppearanceGroup = '%s', dialogHandle = '%s'",
                       mSharedUser.data(), dialogHandle->data());

      }

      // Update the subscriptions.
      updateSubscriptions();
   }
   break;
   }
}
Пример #17
0
// Process a notify event callback.
// This involves parsing the content of the callback and revising our record
// of the state for that subscription.  Then, we must regenerate the list
// of contacts and update the set of subscriptions to match the current
// contacts.
void ContactSet::notifyEventCallback(const UtlString* dialogHandle,
                                     const UtlString* content)
{
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "ContactSet::notifyEventCallback mUri = '%s', dialogHandle = '%s', content = '%s'",
                 mUri.data(), dialogHandle->data(), content->data());

   // Parse the XML and update the contact status.

   // Find the UtlHashMap for this subscription.
   UtlHashMap* state_from_this_subscr =
      dynamic_cast <UtlHashMap*> (mSubscriptions.findValue(dialogHandle));
   if (!state_from_this_subscr)
   {
      // No state for this dialogHandle, so we need to add one.
      OsSysLog::add(FAC_RLS, PRI_WARNING,
                    "ContactSet::notifyEventCallback mSubscriptions element does not exist for this dialog handle mUri = '%s', dialogHandle = '%s'",
                    mUri.data(),
                    dialogHandle->data());

      // Check that we don't have too many subscriptions.
      if (mSubscriptions.entries() <
          getResourceListServer()->getMaxRegSubscInResource())
      {
         state_from_this_subscr = new UtlHashMap;
         mSubscriptions.insertKeyAndValue(new UtlString(*dialogHandle),
                                          state_from_this_subscr);
      }
      else
      {
         OsSysLog::add(FAC_RLS, PRI_ERR,
                       "ContactSet::notifyEventCallback cannot add reg subscription with dialog handle '%s', already %zu in ContactSet '%s'",
                       dialogHandle->data(), mSubscriptions.entries(),
                       mUri.data());
      }
   }

   // Perform the remainder of the processing if we obtained a hash map
   // from the above processing.
   if (state_from_this_subscr)
   {
      // Initialize Tiny XML document object.
      TiXmlDocument document;
      TiXmlNode* reginfo_node;
      if (
         // Load the XML into it.
         document.Parse(content->data()) &&
         // Find the top element, which should be a <reginfo>.
         (reginfo_node = document.FirstChild("reginfo")) != NULL &&
         reginfo_node->Type() == TiXmlNode::ELEMENT)
      {
         // Check the state attribute.
         const char* p = reginfo_node->ToElement()->Attribute("state");
         if (p && strcmp(p, "full") == 0)
         {
            // If the state is "full", delete the current state.
            state_from_this_subscr->destroyAll();
            OsSysLog::add(FAC_RLS, PRI_DEBUG,
                          "ContactSet::notifyEventCallback clearing state");
         }

         // Find all the <registration> elements for this URI.
         for (TiXmlNode* registration_node = 0;
              (registration_node =
               reginfo_node->IterateChildren("registration",
                                             registration_node));
            )
         {
            // Do not test the aor attribute of <registration> elements
            // because the reg event server may be operating with the real
            // AOR for this URI, whereas we may have been told of an alias.

            // Find all the <contact> elements.
            for (TiXmlNode* contact_node = 0;
                 (contact_node =
                  registration_node->IterateChildren("contact",
                                                     contact_node));
               )
            {
               TiXmlElement* contact_element = contact_node->ToElement();

               // Get the state attribute.
               const char* state = contact_element->Attribute("state");
               // Get the id attribute
               const char* id = contact_element->Attribute("id");

               // Get the Contact URI for the phone. If a GRUU address is present we should
               // use that as the Contact URI. Otherwise, use the contact URI present in the
               // "uri" element, and append any path headers that are present to the ROUTE
               // header parameter in the URI. This will ensure proper routing in HA systems.
               // Please refer to XECS-1694 for more details.

               UtlString* uri_allocated = new UtlString;
               UtlBoolean check_uri = TRUE;
               TiXmlNode* pub_gruu_node = contact_element->FirstChild("gr:pub-gruu");
               if (pub_gruu_node)
               {
                  TiXmlElement* pub_gruu_element = pub_gruu_node->ToElement();
                  UtlString pub_gruu_uri(pub_gruu_element->Attribute("uri"));
                  if (!pub_gruu_uri.isNull())
                  {
                     // Check the URI Scheme. Only accept the GRUU address if it is of either
                     // a sip or sips scheme
                     Url tmp(pub_gruu_uri, TRUE);
                     Url::Scheme uriScheme = tmp.getScheme();
                     if(Url::SipUrlScheme == uriScheme ||
                        Url::SipsUrlScheme == uriScheme)
                     {
                        tmp.removeAngleBrackets();
                        tmp.getUri(*uri_allocated);
                        check_uri = FALSE;
                     }
                  }
               }

               // If we did not find a GRUU address, then use the address in the "uri" element as the
               // contact URI, and check for path headers.
               if (check_uri)
               {
                  TiXmlNode* u = contact_element->FirstChild("uri");
                  if (u)
                  {
                     textContentShallow(*uri_allocated, u);

                     // Iterate through all the path header elements. Path headers are stored in the
                     // "unknown-param" elements that have a "name" attribute value of "path".
                     for (TiXmlNode* unknown_param_node = 0;
                          (unknown_param_node = contact_node->IterateChildren("unknown-param",
                                                                               unknown_param_node));
                          )
                     {
                        TiXmlElement* unknown_param_element = unknown_param_node->ToElement();
                        UtlString path(unknown_param_element->Attribute("name"));
                        if(0 == path.compareTo("path"))
                        {
                           UtlString pathVector;
                           textContentShallow(pathVector, unknown_param_node);
                           if(!pathVector.isNull())
                           {
                              Url contact_uri(*uri_allocated, TRUE);

                              // there is already a Route header parameter in the contact; append it to the
                              // Route derived from the Path vector.
                              UtlString existingRouteValue;
                              if ( contact_uri.getHeaderParameter(SIP_ROUTE_FIELD, existingRouteValue))
                              {
                                 pathVector.append(SIP_MULTIFIELD_SEPARATOR);
                                 pathVector.append(existingRouteValue);
                              }
                              contact_uri.setHeaderParameter(SIP_ROUTE_FIELD, pathVector);
                              contact_uri.removeAngleBrackets();
                              contact_uri.getUri(*uri_allocated);
                           }
                        }
                     }
                  }
               }

               // Only process <contact> elements that have the needed values.
               if (state && state[0] != '\0' &&
                   id && id[0] != '\0' &&
                   !uri_allocated->isNull())
               {
                  UtlString* id_allocated = new UtlString(id);

                  if (strcmp(state, "active") == 0)
                  {
                     // Add the contact if it is not already present.
                     if (!state_from_this_subscr->find(id_allocated))
                     {
                        // Prepend the registration Call-Id and ';' to *uri_allocated..
                        uri_allocated->insert(0, ';');
                        const char* call_id = contact_element->Attribute("callid");
                        if (call_id)
                        {
                           uri_allocated->insert(0, call_id);
                        }

                        // Check that we don't have too many contacts.
                        if (state_from_this_subscr->entries() <
                            getResourceListServer()->getMaxContInRegSubsc())
                        {
                           // Insert the registration record.
                           if (state_from_this_subscr->insertKeyAndValue(id_allocated,
                                                                         uri_allocated))
                           {
                              OsSysLog::add(FAC_RLS, PRI_DEBUG,
                                            "ContactSet::notifyEventCallback adding id = '%s' Call-Id;URI = '%s'",
                                            id, uri_allocated->data());
                              id_allocated = NULL;
                              uri_allocated = NULL;
                           }
                           else
                           {
                              OsSysLog::add(FAC_RLS, PRI_ERR,
                                            "ContactSet::notifyEventCallback adding id = '%s' Call-Id;URI = '%s' failed",
                                            id_allocated->data(), uri_allocated->data());
                              OsSysLog::add(FAC_RLS, PRI_DEBUG,
                                            "ContactSet::notifyEventCallback *state_from_this_subscr is:");
                              UtlHashMapIterator itor(*state_from_this_subscr);
                              UtlContainable* k;
                              while ((k = itor()))
                              {
                                 UtlContainable* v = itor.value();
                                 OsSysLog::add(FAC_RLS, PRI_DEBUG,
                                               "ContactSet::notifyEventCallback (*state_from_this_subscr)['%s'] = '%s'",
                                               (dynamic_cast <UtlString*> (k))->data(),
                                               (dynamic_cast <UtlString*> (v))->data());
                              }
                           }
                        }
                        else
                        {
                           OsSysLog::add(FAC_RLS, PRI_ERR,
                                         "ContactSet::notifyEventCallback cannot add Call-Id;RUI '%s', already %zu in ContactSet '%s' subscription '%s'",
                                         uri_allocated->data(),
                                         state_from_this_subscr->entries(),
                                         mUri.data(), dialogHandle->data());
                        }
                     }
                  }
                  else if (strcmp(state, "terminated") == 0)
                  {
                     // Delete it from the contact state.
                     state_from_this_subscr->destroy(id_allocated);
                     OsSysLog::add(FAC_RLS, PRI_DEBUG,
                                   "ContactSet::notifyEventCallback deleting id = '%s'",
                                   id);
                  }
                  // Free id_allocated, if it is not pointed to by a data
                  // structure, which is indicated by setting it to NULL.
                  if (id_allocated)
                  {
                     delete id_allocated;
                  }
               }
               else
               {
                  OsSysLog::add(FAC_RLS, PRI_ERR,
                                "ContactSet::notifyEventCallback <contact> element with id = '%s' is missing id, state, and/or URI",
                                id ? id : "(missing)");
               }
               // Free uri_allocated, if it is not pointed to by a data
               // structure, which is indicated by setting it to NULL.
               if (uri_allocated)
               {
                  delete uri_allocated;
               }
            }
         }
      }
      else
      {
         // Error parsing the contents.
         OsSysLog::add(FAC_RLS, PRI_ERR,
                       "ContactSet::notifyEventCallback malformed reg event content for mUri = '%s'",
                       mUri.data());
      }

      // Update the subscriptions we maintain to agree with the new state.
      updateSubscriptions();
   }
}
Пример #18
0
void ContactSet::subscriptionEventCallback(
   const UtlString* earlyDialogHandle,
   const UtlString* dialogHandle,
   SipSubscribeClient::SubscriptionState newState,
   const UtlString* subscriptionState)
{
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "ContactSet::subscriptionEventCallback mUri = '%s', newState = %d, earlyDialogHandle = '%s', dialogHandle = '%s', subscriptionState = '%s'",
                 mUri.data(),
                 newState, mSubscriptionEarlyDialogHandle.data(),
                 dialogHandle->data(), subscriptionState->data());

   switch (newState)
   {
   case SipSubscribeClient::SUBSCRIPTION_INITIATED:
      break;
   case SipSubscribeClient::SUBSCRIPTION_SETUP:
   {
         // Remember it in mSubscriptions, if there isn't already an entry.
         if (!mSubscriptions.find(dialogHandle))
         {
            // Check that we don't have too many subscriptions.
            if (mSubscriptions.entries() <
                getResourceListServer()->getMaxRegSubscInResource())
            {
               // Add this ContactSet to mNotifyMap for the subscription.
               // (::addNotifyMapping() copies *dialogHandle.)
               getResourceListSet()->addNotifyMapping(*dialogHandle, this);

               // Remember to make a copy of *dialogHandle.
               mSubscriptions.insertKeyAndValue(new UtlString(*dialogHandle),
                                                new UtlHashMap);
            }
            else
            {
               OsSysLog::add(FAC_RLS, PRI_ERR,
                             "ContactSet::subscriptionEventCallback cannot add reg subscription with dialog handle '%s', already %zu in ContactSet '%s'",
                             dialogHandle->data(), mSubscriptions.entries(),
                             mUri.data());
            }
         }
         else
         {
            OsSysLog::add(FAC_RLS, PRI_DEBUG,
                          "ContactSet::subscriptionEventCallback mSubscriptions element already exists for this dialog handle mUri = '%s', dialogHandle = '%s'",
                          mUri.data(),
                          dialogHandle->data());
         }
   }
   break;
   case SipSubscribeClient::SUBSCRIPTION_TERMINATED:
   {
      // Remove this ContactSet from mNotifyMap for the subscription.
      getResourceListSet()->deleteNotifyMapping(dialogHandle);

      // Delete this subscription from mSubscriptions.
      mSubscriptions.destroy(dialogHandle);
      // Update the subscriptions.
      updateSubscriptions();
   }
   break;
   }
}