void start_autotune() {
  power = 127;
  auto_tune.SetControlType(1);
  auto_tune.SetNoiseBand(config.noise_band);
  auto_tune.SetOutputStep(127);
  auto_tune.SetLookbackSec((int)(config.lookback_min * 60));
  
  Serial.println("Starting Autotune");
  tuning = true;
}
示例#2
0
  void setup() {
    pinMode(MOSFET_PIN, OUTPUT);
    pinMode(HEAT_ON_LED_PIN, OUTPUT);

    pid.SetOutputLimits(-PID_OUTPUT_RANGE, PID_OUTPUT_RANGE);

    pid_autotune.SetOutputStep(PID_OUTPUT_RANGE);
    pid_autotune.SetControlType(1);  // PID control type.

    EEPROM.begin(EEPROM_TOTAL_BYTES);
    byte* p = (byte*)(void*)&settings;
    for (unsigned int i = 0; i < sizeof(settings); i++) {
      *p++ = EEPROM.read(EEPROM_SETTINGS_LOCATION + i);
    }

    update_pid_tunings();
    handle_enabled();
  }
示例#3
0
  void update() {
    if (settings.enabled) {
      if (autotune_running) {
        if (pid_autotune.Runtime()) {
          autotune_running = false;

          settings.pid.kp = pid_autotune.GetKp();
          settings.pid.ki = pid_autotune.GetKi();
          settings.pid.kd = pid_autotune.GetKd();

          update_pid_tunings();
          write_settings();
        }
      }

      if (! autotune_running) {
        pid.Compute();
      }

      pid_output_sum += pid_output;
      pid_output_count++;

      unsigned long now = millis();
      if (now >= window_end_millis) {
        pid_output_average = pid_output_sum / pid_output_count;

        if (pid_output_average >= settings.heat_on.threshold) {
          set_heat(true);
        } else if (pid_output_average + settings.heat_on.delta <=
                   settings.heat_on.threshold) {
          set_heat(false);
        }

        reset_window();
      }
    }
  }
void control_loop() {
  pinMode( control_pin, OUTPUT );
  
  if(tuning && auto_tune.Runtime()) {
    finish_autotune();
  } else if(!tuning) {
    pid.SetMode(!config.paused);
    pid.SetTunings(profiles[config.driving].kp, profiles[config.driving].ki, profiles[config.driving].kd);
    pid.SetSampleTime(1000 * profiles[config.driving].sample_time);  // Update the control value once per second
    current_target_temp = profiles[config.driving].target_temp;
    pid.Compute();
  }
  
  if(last_power != power) {
    last_power = power;
    analogWrite(control_pin, power);
    Serial.print("Log\tpower\t");
    Serial.println((100.0 * ((float)power / 255.0)));
  }
}
void finish_autotune() {
  Serial.println("Finished autotune");
  Serial.print("Kp: ");
  Serial.println(auto_tune.GetKp());
  Serial.print("Ki: ");
  Serial.println(auto_tune.GetKi());
  Serial.print("Kd: ");
  Serial.println(auto_tune.GetKd());
  
  profiles[config.driving].kp = auto_tune.GetKp();
  profiles[config.driving].ki = auto_tune.GetKi();
  profiles[config.driving].kd = auto_tune.GetKd();
  
  save();
  tuning = false;
}
示例#6
0
namespace Thermostat {
  settings_struct settings;
  bool heat_on = false;

  unsigned long window_end_millis;
  double pid_output;
  double pid_output_sum;
  int pid_output_count;
  double pid_output_average = 0.0;

  bool autotune_running = false;

  PID pid(
      &TemperatureSensor::temperature, &pid_output, &settings.temperature,
      settings.pid.kp, settings.pid.ki, settings.pid.kd, DIRECT);

  PID_ATune pid_autotune(&TemperatureSensor::temperature, &pid_output);

  void setup() {
    pinMode(MOSFET_PIN, OUTPUT);
    pinMode(HEAT_ON_LED_PIN, OUTPUT);

    pid.SetOutputLimits(-PID_OUTPUT_RANGE, PID_OUTPUT_RANGE);

    pid_autotune.SetOutputStep(PID_OUTPUT_RANGE);
    pid_autotune.SetControlType(1);  // PID control type.

    EEPROM.begin(EEPROM_TOTAL_BYTES);
    byte* p = (byte*)(void*)&settings;
    for (unsigned int i = 0; i < sizeof(settings); i++) {
      *p++ = EEPROM.read(EEPROM_SETTINGS_LOCATION + i);
    }

    update_pid_tunings();
    handle_enabled();
  }

  void update() {
    if (settings.enabled) {
      if (autotune_running) {
        if (pid_autotune.Runtime()) {
          autotune_running = false;

          settings.pid.kp = pid_autotune.GetKp();
          settings.pid.ki = pid_autotune.GetKi();
          settings.pid.kd = pid_autotune.GetKd();

          update_pid_tunings();
          write_settings();
        }
      }

      if (! autotune_running) {
        pid.Compute();
      }

      pid_output_sum += pid_output;
      pid_output_count++;

      unsigned long now = millis();
      if (now >= window_end_millis) {
        pid_output_average = pid_output_sum / pid_output_count;

        if (pid_output_average >= settings.heat_on.threshold) {
          set_heat(true);
        } else if (pid_output_average + settings.heat_on.delta <=
                   settings.heat_on.threshold) {
          set_heat(false);
        }

        reset_window();
      }
    }
  }

  void handle_enabled() {
    if (settings.enabled) {
      reset_window();
      pid.SetMode(AUTOMATIC);
    } else {
      cancel_autotune();
      pid.SetMode(MANUAL);
      set_heat(false);
    }
  }

  void update_pid_tunings() {
    pid.SetTunings(settings.pid.kp, settings.pid.ki, settings.pid.kd);
  }

  void set_heat(bool is_on) {
    digitalWrite(MOSFET_PIN, is_on);
    digitalWrite(HEAT_ON_LED_PIN, ! is_on);

    heat_on = is_on;
  }

  void reset_window() {
    window_end_millis = millis() + settings.pid.window_seconds * 1000;
    pid_output_sum = 0.0;
    pid_output_count = 0;
  }

  void start_autotune() {
    pid_autotune.SetLookbackSec(settings.pid_autotune.lookback_minutes * 60);
    pid_autotune.SetNoiseBand(settings.pid_autotune.noise_band);

    autotune_running = true;
  }

  void cancel_autotune() {
    if (autotune_running) {
      pid_autotune.Cancel();
      autotune_running = false;
    }
  }

  void apply_settings(settings_struct new_settings) {
    settings_struct old_settings = settings;
    settings = new_settings;

    if (settings.enabled != new_settings.enabled) {
      handle_enabled();
    }

    if (settings.temperature != new_settings.temperature) {
      cancel_autotune();
    }

    if (settings.pid.kp != new_settings.pid.kp or
        settings.pid.ki != new_settings.pid.ki or
        settings.pid.kd != new_settings.pid.kd) {
      update_pid_tunings();
    }

    write_settings();
  }

  void write_settings() {
    const byte* p = (const byte*)(const void*)&settings;
    for (unsigned int i = 0; i < sizeof(settings); i++) {
      EEPROM.write(EEPROM_SETTINGS_LOCATION + i, *p++);
    }

    EEPROM.commit();
  }
}
示例#7
0
 void cancel_autotune() {
   if (autotune_running) {
     pid_autotune.Cancel();
     autotune_running = false;
   }
 }
示例#8
0
  void start_autotune() {
    pid_autotune.SetLookbackSec(settings.pid_autotune.lookback_minutes * 60);
    pid_autotune.SetNoiseBand(settings.pid_autotune.noise_band);

    autotune_running = true;
  }
示例#9
0
文件: main.c 项目: nvanfleet/Coffeed
int main(int argc, char **argv)
{
	// Setup
	setup_config(argc,argv);
	setup_state();
	setup_sigs();

	// Objects	
	logger.setup();
	server.setup();
	sensor.setup();
	heater.setup();

    // Thread
	if(pthread_create( &serverThread, NULL, serverPoll, NULL) != 0)
		logger.fail("Server thread creation failure");

	float chosenSetPoint;
	int sensorResult = 0;
	clock_t nextLoop;
	
	conf.update = 1000/conf.update;
	
	timeTick();
	nextLoop = state.time + conf.update;
    
 	logger.info("Starting up Coffeed");
 	
	while(state.run)
	{
		// Time update
		timeTick();

		if(state.time >= nextLoop)
		{
			// Get sensor data
			sensorResult = sensor.update();
		
			// If active choose set point
			if(state.active)
			{
				if(state.brewmode == TRUE)
					chosenSetPoint = conf.brewPoint;
				else
					chosenSetPoint = conf.steamPoint;
								
				// Sensor fault
				if(!sensorResult)
				{
					logger.fail("Sensor read failure");
					state.active = FALSE;
					heater.off();
				}
				// Tuning mode
				else if(state.tuning != FALSE)
				{
					// Begin
					if(state.tuning == 2)
					{
						state.tuning = TRUE;
						
						heater.setPower(50);
						aTune.cancel();
						//aTune.setNoiseBand(1);
						//aTune.setOutputStep(50);
						//aTune.setLookbackSec(20);
						//aTune.setControlType(1);
						
						logger.info("Autotuning BEGIN %f %f %f",conf.pgain,conf.igain,conf.dgain);
					}
					// While (1) we want to tune + (2) update is not done
					else if(state.tuning == TRUE && aTune.update() == FALSE)
					{
						logger.info("tuning");
					}
					// Tuning complete because state.tuning = TRUE but aTune == TRUE
					else
					{
						logger.info("tuning successful am I right?");
						// Done
						conf.pgain = aTune.getKp();
						conf.igain = aTune.getKi();
						conf.dgain = aTune.getKd();
						
						logger.info("Autotuning FINISH %f %f %f",conf.pgain,conf.igain,conf.dgain);
						
						state.tuning = FALSE;
					}					
				}
				// Regular control
				else
				{					
					// PID result
					state.pidResult = pid.result(chosenSetPoint, state.tempPoint);
					
					// Set Heater Duty
					heater.setPower( state.pidResult );
					
					// Log
					logger.debug("PID Result %d temperature %f setP %f brewP %f steamP %f", state.pidResult, state.tempPoint, chosenSetPoint, conf.brewPoint, conf.steamPoint);
				}
			}
			// Inactive system
			else
			{
				// Tuning can't happen in a inactive system
				if(state.tuning != FALSE)
				{
					state.tuning = FALSE;
					aTune.cancel();
				}
				
				if(state.brewmode)
					state.brewmode = TRUE;
				
				chosenSetPoint = 0;
				heater.off();
			}

			// Get Heater Duty
			// This should be centralized to the heater
			state.power = heater.getPower();
			
			// Schedule the next loop after the whole operation	
			nextLoop = state.time + conf.update;
		}
		else
		{
			// Sleep until we need you
			usleep(1000 * (nextLoop - state.time));
		}
	}
	
    logger.info("Shutting down Coffeed");
}