Jump to content

Banner.jpg.b83b14cd4142fe10848741bb2a14c66b.jpg

Gina

Beyond the Event Horizon
  • Posts

    45,326
  • Joined

  • Last visited

  • Days Won

    120

Posts posted by Gina

  1. I have now stripped the ASC right down - needed if only using the O ring to seal the dome.  The wet is evident everywhere, even the copper waterblock has gone green!  But the cause is known and can be fixed.  Focus is a different matter, even manual focus.

  2. Wind measuring rig taken down and brought indoors.  Taken apart and new sketch uploaded to ESP32, put back together and a quick test to check it's working before taking it back out and attaching to obsy corner post.  Powered up and working again.

    1887663972_Screenshotfrom2020-09-0719-42-46.thumb.png.79649cf34d7f65579f7795ee0b2ab86c.png

  3. This is the new sketch.

    // Wind speed and direction 2020-09-07
    
    /*********
      With thanks to Rui Santos
      Complete project details at https://randomnerdtutorials.com 
      and others
    ********
    Modified and added to by Gina 2020-08-21 onward
    ********
    */
    // Set value for North offset correction
    int northOffset = 15; // use a value between 0 and 15
    
    // Set up for timer interrupts
    volatile int interrupts;
    int totalInterrupts;
    
    hw_timer_t * timer = NULL;
    portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
    int timerCount = 0;
    
    // periods or intervals in milliseconds
    const int P3s = 3000;       // integer
    unsigned long P3m = 180000; // variable used as constant
    unsigned long last3s = 0;
    unsigned long last3m = 0;
    
    // ADC pins
    const int An1 = 34;
    const int An2 = 35;
    const int An3 = 32;
    const int An4 = 33;
    // ADC readings
    int dir1 = 0;
    int dir2 = 0;
    int dir3 = 0;
    int dir4 = 0;
    
    // Gray to binary table
    int codeArray[16] = {0,1,3,2,7,6,4,5,15,14,12,13,8,9,11,10};  // index Gray (local)
    
    // Direction count bins
    int bin[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};  // indexes dirn, i, I (local)
    
    // 10m speed averaging etc.
    int meanArray[10] = {0,0,0,0,0,0,0,0,0,0};
    int gustArray[10] = {0,0,0,0,0,0,0,0,0,0};
    int ringIndex = 0;
    
    // debugging the PulseCount
    int pulseArray[10] = {0,0,0,0,0,0,0,0,0,0};
    int writeIndex = 0, readIndex = 0;
    
    // Speed variables
    long sumSpeed = 0; // 0-
    int meanSpeed = 0; // 0-100mph
    int gustSpeed = 0; // 0-100mph
    
    // Set GPIO for Hall Sensor
    const int HallSensorPin = 4;
    int PulseCount = 0, windGust = 0;
    int windSpeed = 0;
    
    #include <WiFi.h>
    #include <PubSubClient.h>
    
    // Replace the next variables with your SSID/Password combination
    const char* ssid = "Ubiquity";
    const char* password = "********";
    
    const char* mqtt_server = "192.168.1.140";
    
    WiFiClient windClient;
    PubSubClient client(windClient);
    
    void IRAM_ATTR onTime() {
      portENTER_CRITICAL_ISR(&timerMux);
      interrupts=1;
      windSpeed += PulseCount;  //  Accumulate mean speed
      if (PulseCount > windGust) {windGust = PulseCount;};  // Get max speed for gust
      pulseArray[writeIndex] = PulseCount;
      writeIndex = (writeIndex+1)%10;
      PulseCount = 0; // clear count 
      timerCount++;  // count number of timer interrupts for 1m speed sum                                      
      portEXIT_CRITICAL_ISR(&timerMux);
    }
    
    // Checks if Hall sensor was triggered - Interrupt Handler
    void IRAM_ATTR HallTriggered() {
      ++PulseCount; // Increment count
    }
    
    int Beaufort(int mph){
      if (mph < 1) return 0;
      else if (mph <= 3) return 1;
      else if (mph <= 7) return 2;
      else if (mph <= 12) return 3;
      else if (mph <= 18) return 4;
      else if (mph <= 24) return 5;
      else if (mph <= 31) return 6;
      else if (mph <= 38) return 7;
      else if (mph <= 46) return 8;
      else if (mph <= 54) return 9;
      else if (mph <= 63) return 10;
      else if (mph <= 72) return 11;
      else return 12;
    }
    
    void setup() {
      Serial.begin(115200);
      setup_wifi();
      client.setServer(mqtt_server, 1883);
      client.setCallback(callback);
      
      // Hall Sensor mode INPUT_PULLUP
      pinMode(HallSensorPin, INPUT_PULLUP);
      // Set HallSensor pin as interrupt, assign interrupt function and set FALLING mode
      attachInterrupt(digitalPinToInterrupt(HallSensorPin), HallTriggered, FALLING);
      if (!client.connected()) {reconnect();}
    //
      // Configure Prescaler to 80, as our timer runs @ 80Mhz
      // Giving an output of 80,000,000 / 80 = 1,000,000 ticks / second
      timer = timerBegin(0, 80, true);                
      timerAttachInterrupt(timer, &onTime, true);    
      // Fire Interrupt every 3m ticks, so 3s
      timerAlarmWrite(timer, 3000000, true);      
      timerAlarmEnable(timer);
    }
    
    void setup_wifi() {
      delay(10);
      // We start by connecting to a WiFi network
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);
    
      WiFi.begin(ssid, password);
    
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
    
      Serial.println("");
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    }
    
    void callback(char* topic, byte* message, unsigned int length) {
      Serial.print("Message arrived on topic: ");
      Serial.print(topic);
      Serial.print(". Message: ");
      String messageTemp;
      
      for (int i = 0; i < length; i++) {
        Serial.print((char)message[i]);
        messageTemp += (char)message[i];
      }
      Serial.println();
    
      if (String(topic) == "wind/northoffset") {
        Serial.print("Message String : ");
        Serial.println(messageTemp);
        Serial.print("Number : ");
        int Number = messageTemp.toInt();
        Serial.println(Number);
        northOffset = Number;
      }
    }
    
    void reconnect() {
      // Loop until we're reconnected
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (client.connect("windClient")) {
          Serial.println("connected");
          // Subscribe
          client.subscribe("wind/northoffset");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }
    
    //Get instantaneous wind direction - variable dirn
    void getDirection(){    
      int dirn = 0;
      // Read wind vane optical sensor values
      dir1 = analogRead(An1);
      dir2 = analogRead(An2);
      dir3 = analogRead(An3);
      dir4 = analogRead(An4);
      // Convert Gray bits to integer
      int Gray = 0;
      if (dir1 > 2000) {Gray = 8;};
      if (dir2 > 2000) {Gray += 4;};
      if (dir3 > 2000) {Gray += 2;};
      if (dir4 > 2000) {Gray += 1;};
      //  Convert Gray to binary
      dirn = 15 - codeArray[Gray]; // correct rotation direction
      dirn = (dirn + northOffset) %16; // correct encoder for North
      ++bin[dirn]; // increment appropriate bin for Consensus Averaging
      sendDirectionMessageInst(dirn); // send instantaneous direction 
    }
    //
    void sendSpeedMessages(){
      if (!client.connected()) {reconnect();}
      // messages to send :-
      // wind/speed/mph -- meanSpeed
      // wind speed/force -- Beaufort(meanSpeed)
      // wind/gust/mph -- gustSpeed
      // wind/gust/force -- Beaufort(gustSpeed)
      // 
      // Convert the Mean Speed to a char array
      char msString[8];
      dtostrf(meanSpeed, 1, 1, msString);
      Serial.print("  Mean Speed: ");
      Serial.print(msString);
      client.publish("wind/speed/mph", msString);
      
      // Convert the Mean-Speed-Force to a char array
      char bsString[8];
      dtostrf(Beaufort(meanSpeed), 1, 0, bsString);
    //  Serial.print("Force: ");
    //  Serial.println(bsString);
      client.publish("wind/speed/force", bsString);
      
      // Convert the Gust-Speed to a char array
      char gsString[8];
      dtostrf(gustSpeed, 1, 0, gsString);
      Serial.print("  Gust: ");
      Serial.println(gsString);
      client.publish("wind/gust/mph", gsString);
    
      // Convert the Gust-Speed-Force to a char array
      char bgString[8];
      dtostrf(Beaufort(gustSpeed), 1, 0, bgString);
    //  Serial.print("Gust Force: ");
    //  Serial.println(bgString);
      client.publish("wind/gust/force", bgString);
    }
    void sendDirectionMessage(int Dir){
      // Convert the Direction to a char array
      char dirString[8];
      dtostrf(Dir, 1, 0, dirString);
    //  Serial.print("  Direction: ");
    //  Serial.println(dirString);
      client.publish("wind/direction", dirString);
    }
    void sendDirectionMessageInst(int Dir){
      // Convert the Direction to a char array
      char dirString[8];
      dtostrf(Dir, 1, 0, dirString);
    //  Serial.print("Transient Direction: ");
    //  Serial.println(dirString);
      client.publish("wind/direction/inst", dirString);
    }
    //  Debugging only
    void sendringIndex(){
      // Convert the number to a char array
      char numString[8];
      dtostrf(ringIndex, 1, 0, numString);
      Serial.print("ringIndex: ");
      Serial.println(numString);
      client.publish("wind/ringIndex", numString);
    }
    void sendNumberMessage(int N){
      // Convert the number to a char array
      char numString[8];
      dtostrf(N, 1, 0, numString);
      Serial.print("Number: ");
      Serial.println(numString);
      client.publish("wind/number", numString);
    }
    void sendNorthOffset(){
      // Convert the number to a char array
      char numString[8];
      dtostrf(northOffset, 1, 0, numString);
      Serial.print("northOffset: ");
      Serial.println(numString);
      client.publish("wind/northoffset/confirm", numString);
    } 
    void speed20sum(){
      sendringIndex();
      sendNorthOffset();
    //  sendNumberMessage2(Number);
    //  sendNumberMessage2(windSpeed);
      // wind speed mean and gust ring arrays and report
      meanArray[ringIndex] = windSpeed; // put windSpeed into new array index
      gustArray[ringIndex] = windGust;  // put windGust into new array index
      sumSpeed = 0; gustSpeed = 0; windSpeed = 0; windGust = 0;
      for (int i = 0; i < 10; i++) { 
        sumSpeed += meanArray[i];  // sum the windSpeeds 
        if (gustArray[i] > gustSpeed){gustSpeed = gustArray[i];}} // find maximum gust speed
      sumSpeed *=3;  // in conjunction with 20 converts speed by 1.5
      meanSpeed = sumSpeed /20 /timerCount;  // 
      gustSpeed = gustSpeed *3 /2;  // Speed count over 3s rather than 4.5s
      sendSpeedMessages();
      ringIndex = (ringIndex+1)%10; // move ringIndex on to next location in the ring arrays
    }
      // debugging PulseCount
    void sendPulseArray(){
      sendNumberMessage(pulseArray[readIndex]); 
      readIndex = (readIndex+1)%10; // move readIndex on to next location in the pulse ring array
    }
    
    void ConsensusAveraging(){
      // wind direction calculations and report
      int sum[16];
      int S=0,I=0,W=0;
      bin[16] = bin[0];
      bin[17] = bin[1];
      bin[18] = bin[2];
      bin[19] = bin[3];
      for (int i = 0; i < 16; i++) {sum[i] = bin[i] + bin[i+1] + bin[i+2] + bin[i+3] + bin[i+4];
        // find the index with the highest sum and save sum and index
        if (sum[i] > S){S = sum[i]; I = i;};}
      W = (bin[I+1] + 2 * bin[I+2] + 3 * bin[I+3] + 4 * bin[I+4]) * 45 / S;
      sendDirectionMessage((I * 45 + W)%720 /2);
      //Empty the bins ready for a new direction calculation
      for (int i = 0; i < 16; i++) {bin[i] = 0;};
    }
    
    void loop() {
    //  if (!client.connected()) {reconnect();}
      client.loop();
      if (interrupts != 0 ){
        // ISR has triggered - proceed and perform the jobs
        if (timerCount >= 20) {speed20sum(); timerCount=0;};
        // time the various periods
        long now = millis();
        if(now - last3s > P3s) {getDirection(); sendPulseArray(); last3s = now;}
        if(now - last3m > P3m) {ConsensusAveraging(); last3m = now;}
        interrupts = 0; // Reset the flag
      }
    }

     

  4. This would enable me to set the North direction remotely if I decide to turn the wind sensor mast to move the wind vane out of the view from the mount.  Anyone see any disadvantage to doing this?  I might repeat the offset value back to the Dashboard as confirmation.

  5. I get excellent results using narrowband filters with Asahi (Pentax) Takumar, Super Takumar and SMC Takumar M42 mount lenses.  These are superb lenses and work well even at full aperture.  I have several of various focal lengths.  The point with terrestrial camera lenses is that they are not fully APO into the deep red but with very narrow band filters this isn't a problem - just that you need different focus settings for Ha & SII as compared with OIII.

    HTH.

    • Thanks 1
  6. Running a test for remote number setting via MQTT.  Changed the topic from wind/northoffset to tes/northoffset and set up a test client on a new ESP32.  Changed the number in Dashboard and watched the Serial Monitor on the testClient.  Test successful.

    void callback(char* topic, byte* message, unsigned int length) {
      Serial.print("Message arrived on topic: ");
      Serial.print(topic);
      Serial.print(". Message: ");
      String messageTemp;
      
      for (int i = 0; i < length; i++) {
        Serial.print((char)message[i]);
        messageTemp += (char)message[i];
      }
      Serial.println();
    
      if (String(topic) == "test/northoffset") {
        Serial.print("Message String : ");
        Serial.println(messageTemp);
        Serial.print("Number : ");
        Serial.println(messageTemp.toInt());
      }
    }

    61982302_Screenshotfrom2020-09-0711-50-20.thumb.png.12c6e13e6001956536ee4a3da9e5551b.png

  7. I think it should be easy enough to remote control the North Offset via MQTT.

    In Node-RED
    1889722615_Screenshotfrom2020-09-0622-51-31.png.2d7ef1cd952b2fca9e0dc7f12366b42d.png

    This shows a numeric control in the Dashboard
    713396741_Screenshotfrom2020-09-0622-53-36.png.bac3e173e9cd82be370d872baabacc1a.png

    Then I just have to read the message in the sketch and convert it to an integer.  I'll look at that tomorrow.

  8. Code changed to

    //Get instantaneous wind direction - variable dirn
    void getDirection(){    
      int dirn = 0;
      // Read wind vane optical sensor values
      dir1 = analogRead(An1);
      dir2 = analogRead(An2);
      dir3 = analogRead(An3);
      dir4 = analogRead(An4);
      // Convert Gray bits to integer
      int Gray = 0;
      if (dir1 > 2000) {Gray = 8;};
      if (dir2 > 2000) {Gray += 4;};
      if (dir3 > 2000) {Gray += 2;};
      if (dir4 > 2000) {Gray += 1;};
      //  Convert Gray to binary
      dirn = 15 - codeArray[Gray]; // correct rotation direction
      dirn = (dirn + northOffset) %16; // correct encoder for North
      ++bin[dirn]; // increment appropriate bin for Consensus Averaging
      sendDirectionMessageInst(dirn); // send instantaneous direction 
    }

    with this at the beginning of the sketch

    // Set value for North offset correction
    int northOffset = 15; // use a value between 0 and 15
    • Like 1
  9. 10 minutes ago, globular said:

    The two lines you are removing change the values in the array, not their positions.
    So I think you want to change
    0,1,3,2,7,6,4,5,15,14,12,13,8,9,11,10 
    to
    14,13,11,12,7,8,10,9,15,0,2,1,6,5,3,4 

    As you say, a clear head tomorrow will make it clearer.

    Oh yes, you're right - the array is arranged in Gray code order not binary.  Agreed!!  Not touching it - too much trouble!!

  10. 12 minutes ago, JamesF said:

    My feeling is that it's more maintainable to keep the gray code table consistent with what one would expect and then do a little maths to get the direction correct than to reorder the gray codes and then find in a couple of years time when you come back to make some changes that you can't remember what on Earth you were doing.

    Also, should you need to change the north direction, say, at some point in the future, it's far more straightforward to change the line that handles the offset than it is to reorder the gray code table.

    James

    Yes, that was my thinking in the first place.  The reason for the two separate lines - one for orientation and the other for offset.

    As for changing the North direction, I was wondering whether to add code to enable this to be changed remotely via MQTT.

  11. 0,1,3,2,7,6,4,5,15,14,12,13,8,9,11,10 becomes
    10,11,9,8,13,12,14,15,5,4,6,7,2,3,1,0 then shifted one way or the other which I'll work out tomorrow with a clear head!

    Either
    11,9,8,13,12,14,15,5,4,6,7,2,3,1,0,10 or
    0,10,11,9,8,13,12,14,15,5,4,6,7,2,3,1

  12. If I were to rearrange the Gray to Binary conversion look-up table array I could replace these two lines

      dirn = 15 - codeArray[Gray]; // correct rotation direction
      dirn = (dirn + 15) %16; // correct encoder for North

    with just

      dirn = codeArray[Gray];

    Backwards to reverse the direction and shifted one round to correct for north.  No %16 required.

    • Like 1
  13. I'm leaving the debugging code in place as it doesn't detract from performance and if there is still a problem when the rig is deployed it may help to find the cause.  ATM I have the rig assembled onto the mast and in final test before deployment outside.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.