Simpler temp and water controllers
This commit is contained in:
		
							parent
							
								
									a3167aff1e
								
							
						
					
					
						commit
						a957490cd8
					
				
					 2 changed files with 88 additions and 144 deletions
				
			
		|  | @ -6,94 +6,67 @@ import wash.control.WashingMessage.Order; | ||||||
| 
 | 
 | ||||||
| public final class ControllerTemp extends ActorThread<WashingMessage> { | public final class ControllerTemp extends ActorThread<WashingMessage> { | ||||||
|     private WashingIO io; |     private WashingIO io; | ||||||
|     private Heater heater; |  | ||||||
|     private WashingMessage m; |     private WashingMessage m; | ||||||
|  |     private WashingMessage temp; | ||||||
|  |     private boolean ackSent = true; | ||||||
|  |     private Order heaterState = Order.TEMP_IDLE; | ||||||
| 
 | 
 | ||||||
|     public ControllerTemp(WashingIO io) { |     public ControllerTemp(WashingIO io) { | ||||||
|         this.io = io; |         this.io = io; | ||||||
|         heater = new Heater(0); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected void sendAck() { |     protected void sendAck() { | ||||||
|         m.sendAck(this); |         m.sendAck(this); | ||||||
|  |         ackSent = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void run() { |     public void run() { | ||||||
|         heater.start(); |  | ||||||
| 
 |  | ||||||
|         while (true) { |         while (true) { | ||||||
|             try { |             try { | ||||||
|                 m = take(); |                 temp = receiveWithTimeout(10000 / Settings.SPEEDUP); | ||||||
|             } catch (Exception e) { | 
 | ||||||
|                 System.exit(1); |                 // If there is a new message, swap | ||||||
|  |                 if (temp != null) { | ||||||
|  |                     m = temp; | ||||||
|  |                     ackSent = false; // We have a new order | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             switch (m.order()) { |                 // If this message is not the same as last time | ||||||
|                 case Order.TEMP_SET_40 -> heater.setTarget(40); |                 if (m != null && m.order() != heaterState) { | ||||||
|                 case Order.TEMP_SET_60 -> heater.setTarget(60); |                     heaterState = m.order(); | ||||||
|                 case Order.TEMP_IDLE -> heater.setTarget(0); // TODO: Error |                 } | ||||||
|  | 
 | ||||||
|  |                 switch (heaterState) { | ||||||
|  |                     case Order.TEMP_SET_40 -> { | ||||||
|  |                         if (io.getTemperature() <= 39) { | ||||||
|  |                             io.heat(true); | ||||||
|  |                         } else { | ||||||
|  |                             io.heat(false); | ||||||
|  |                             if (!ackSent) | ||||||
|  |                                 sendAck(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     case Order.TEMP_SET_60 -> { | ||||||
|  |                         if (io.getTemperature() <= 59) { | ||||||
|  |                             io.heat(true); | ||||||
|  |                         } else { | ||||||
|  |                             io.heat(false); | ||||||
|  |                             if (!ackSent) | ||||||
|  |                                 sendAck(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     case Order.TEMP_IDLE -> { | ||||||
|  |                         io.heat(false); | ||||||
|  |                         if (!ackSent) | ||||||
|  |                             sendAck(); | ||||||
|  |                     } | ||||||
|                     default -> { |                     default -> { | ||||||
|                         continue; |                         continue; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|         } |             } catch (Exception e) { | ||||||
|     } |                 System.out.println("Exception: " + e); | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Heater class that extends Thread and controls the temperature |  | ||||||
|      * of the washing machine. |  | ||||||
|      * |  | ||||||
|      * Note that the heater has access to local variables in the |  | ||||||
|      * TemperatureController class. |  | ||||||
|      */ |  | ||||||
|     class Heater extends Thread { |  | ||||||
|         double target; |  | ||||||
|         boolean hovering; |  | ||||||
| 
 |  | ||||||
|         Heater(double target) { |  | ||||||
|             this.target = target; |  | ||||||
|             this.hovering = true; // No acks before actual setpoint is acquired |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         synchronized public void setTarget(double target) { |  | ||||||
|             this.target = target; |  | ||||||
|             this.hovering = false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @Override |  | ||||||
|         public void run() { |  | ||||||
|             double current; |  | ||||||
|             try { |  | ||||||
|                 while (!isInterrupted()) { |  | ||||||
|                     current = io.getTemperature(); |  | ||||||
| 
 |  | ||||||
|                     if (io.getWaterLevel() == 0) { |  | ||||||
|                         io.heat(false); |  | ||||||
|                         sleep(60000 / Settings.SPEEDUP); |  | ||||||
|                         continue; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (current < target) { |  | ||||||
|                         io.heat(true); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     else if (current >= target) { |  | ||||||
|                         io.heat(false); |  | ||||||
| 
 |  | ||||||
|                         if (!hovering) { |  | ||||||
|                             sendAck(); |  | ||||||
|                             hovering = true; |  | ||||||
|                             sleep(60000 / Settings.SPEEDUP); |  | ||||||
|                             continue; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     sleep(60000 / Settings.SPEEDUP); |  | ||||||
|                 } |  | ||||||
|             } catch (InterruptedException e) { |  | ||||||
|                 io.heat(false); |  | ||||||
|                 Thread.currentThread().interrupt(); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| package wash.control; | package wash.control; | ||||||
| 
 | 
 | ||||||
|  | import static wash.control.WashingMessage.Order.WATER_IDLE; | ||||||
|  | 
 | ||||||
| import actor.ActorThread; | import actor.ActorThread; | ||||||
| import wash.control.WashingMessage.Order; | import wash.control.WashingMessage.Order; | ||||||
| import wash.io.WashingIO; | import wash.io.WashingIO; | ||||||
|  | @ -8,98 +10,67 @@ public class ControllerWater extends ActorThread<WashingMessage> { | ||||||
| 
 | 
 | ||||||
|     WashingMessage.Order o; |     WashingMessage.Order o; | ||||||
|     WashingMessage m; |     WashingMessage m; | ||||||
|  |     WashingMessage temp; | ||||||
|     WashingIO io; |     WashingIO io; | ||||||
|     WaterPid waterpid; | 
 | ||||||
|  |     Order waterState = WATER_IDLE; | ||||||
|  |     boolean ackSent = true; | ||||||
| 
 | 
 | ||||||
|     public ControllerWater(WashingIO io) { |     public ControllerWater(WashingIO io) { | ||||||
|         this.io = io; |         this.io = io; | ||||||
|         this.waterpid = new WaterPid(0, 1); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void sendAck() { |     public void sendAck() { | ||||||
|  |         ackSent = true; | ||||||
|         m.sendAck(this); |         m.sendAck(this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void run() { |     public void run() { | ||||||
|         waterpid.start(); |  | ||||||
|         while (true) { |         while (true) { | ||||||
|             // m = poll(60000 / Settings.SPEEDUP).orElse(new WashingMessage(this, Order.NOOP)); |  | ||||||
|             try { |             try { | ||||||
|                 m = take(); |                 temp = receiveWithTimeout(10000 / Settings.SPEEDUP); | ||||||
|             } catch (Exception e) { | 
 | ||||||
|                 System.exit(1); |                 // If there is a new message, swap | ||||||
|  |                 if (temp != null) { | ||||||
|  |                     m = temp; | ||||||
|  |                     ackSent = false; // We have a new order | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             switch (m.order()) { |                 // If this message is not the same as last time | ||||||
|                 case Order.WATER_DRAIN -> waterpid.setTarget(0); |                 if (m != null && m.order() != waterState) { | ||||||
|                 case Order.WATER_FILL -> waterpid.setTarget(20); |                     waterState = m.order(); | ||||||
|                 case Order.WATER_IDLE -> waterpid.setIdle(); |                 } | ||||||
|  | 
 | ||||||
|  |                 switch (waterState) { | ||||||
|  |                     case Order.WATER_DRAIN -> { | ||||||
|  |                         io.drain(true); | ||||||
|  |                         io.fill(false); | ||||||
|  |                         if (io.getWaterLevel() == 0 && !ackSent) | ||||||
|  |                             sendAck(); | ||||||
|  |                     } | ||||||
|  |                     case Order.WATER_FILL -> { | ||||||
|  |                         io.drain(false); | ||||||
|  | 
 | ||||||
|  |                         if (io.getWaterLevel() < 19) | ||||||
|  |                             io.fill(true); | ||||||
|  |                         else { | ||||||
|  |                             io.fill(false); | ||||||
|  |                             if (!ackSent) { | ||||||
|  |                                 sendAck(); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     case Order.WATER_IDLE -> { | ||||||
|  |                         io.drain(false); | ||||||
|  |                         io.fill(false); | ||||||
|  |                     } | ||||||
|                     default -> { |                     default -> { | ||||||
|                         continue; |                         continue; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|         } |             } catch (Exception e) { | ||||||
|     } |                 System.out.println("Exception: " + e); | ||||||
| 
 |  | ||||||
|     /** A pid controller that is not actually a pid controller */ |  | ||||||
|     public final class WaterPid extends Thread { |  | ||||||
|         private double target; |  | ||||||
|         private final double tolerance; // Acceptable range around target |  | ||||||
|         private boolean hover = false; // Indicates if we're close enough to the target |  | ||||||
|         private boolean hasAcknowledged = true; // Tracks if ack has been sent |  | ||||||
| 
 |  | ||||||
|         public WaterPid(double targetLiter, double tolerance) { |  | ||||||
|             this.target = targetLiter; |  | ||||||
|             this.tolerance = tolerance; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /** Set the target level */ |  | ||||||
|         public synchronized void setTarget(double targetLiter) { |  | ||||||
|             this.target = targetLiter; |  | ||||||
|             this.hover = false; |  | ||||||
|             this.hasAcknowledged = false; // Reset ack when target changes |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /** Just coast at current level */ |  | ||||||
|         public synchronized void setIdle() { |  | ||||||
|             this.setTarget(io.getWaterLevel()); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /** Main control loop */ |  | ||||||
|         @Override |  | ||||||
|         public void run() { |  | ||||||
|             while (!isInterrupted()) { |  | ||||||
|                 double currentLevel = io.getWaterLevel(); // Get current water level |  | ||||||
|                 double error = target - currentLevel; |  | ||||||
|                 hover = Math.abs(error) <= tolerance; |  | ||||||
| 
 |  | ||||||
|                 // Open or close drain/fill based on current water level |  | ||||||
|                 if (!hover) { |  | ||||||
|                     if (error > 0) { |  | ||||||
|                         io.fill(true); // Open tap to increase water level |  | ||||||
|                         io.drain(false); // Ensure drain is closed |  | ||||||
|                     } else { |  | ||||||
|                         io.drain(true); // Open drain to decrease water level |  | ||||||
|                         io.fill(false); // Ensure tap is closed |  | ||||||
|                     } |  | ||||||
|                 } else { |  | ||||||
|                     // Stop adjustments if hovering near target |  | ||||||
|                     io.fill(false); |  | ||||||
|                     io.drain(false); |  | ||||||
| 
 |  | ||||||
|                     // Send acknowledgment if target is reached for the first time |  | ||||||
|                     if (!hasAcknowledged) { |  | ||||||
|                         sendAck(); |  | ||||||
|                         hasAcknowledged = true; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 try { |  | ||||||
|                     Thread.sleep(100); |  | ||||||
|                 } catch (InterruptedException e) { |  | ||||||
|                     Thread.currentThread().interrupt(); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Imbus
						Imbus