-
Posts
45,326 -
Joined
-
Last visited
-
Days Won
120
Content Type
Profiles
Forums
Gallery
Events
Blogs
Posts posted by Gina
-
-
Tried a different ESP32 and it's alright.
-
Back to the wind client...
Have a problem.
-
I've been using the UL method of making unsigned long constants in all my clients so these will all need correcting, though they seem to be working fine.
-
Working fine I think, though won't know for sure until I get the wind sensors connected and the wind blowing on it. Looks like the UL constant(s) has been causing the problems all along and that the Arduino Reference is wrong!
-
I thought adding U or L or UL allocated the extra space but to avoid any possible trouble I've declared as follows
// 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;
-
The hardware timer works.
I don't quite understand "While the Arduino manual is right you cannot declare an int and stuff it with an unsigned long." I've thought about this, it seems to work fine but I guess I could assign an unsigned long variable and preset it with the value I want and use it as a constant. After all, a non-varying variable is a constant in effect. Would that be better?
Yes, the compiler should have picked up that error. Guess nothing is perfect and the error checking is pretty good. Though sometimes the error message can be rather vague or unhelpful.
-
14 minutes ago, skybadger said:
Don't write debug code in interrupts that write to serial.!
I'm not.
16 minutes ago, skybadger said:You are using the hardware timer, there are only a few available . On the 8266 you can chain many more using the soft interrupt timer , I don't know if this is true for esp32.
I'm only running one hardware timer - the ESP32 has 4. All other timings are by counting or using millis and now.
-
12 minutes ago, skybadger said:
Also, dont sit and wait in the loop for things to fire. A loop happens every 5ms or so, so loop should look for a timer interrupt fired flag to indicate the desired event has happened rather than block. On do ding the flag you can then process the action. Otherwise, while interrupts will keep on firing, your Wi-Fi may crap out due to missing carrier detects.
OK took that from elsewhere - changed it to
void loop() { // if (!client.connected()) {reconnect();} client.loop(); if (interrupts == 0 ){ // ISR has triggered - proceed and perform the jobs if (timerCount >= 21) {speed21sum(); timerCount=0;}; // time the various periods long now = millis(); if(now - last3s > P3s) {getDirection(); last3s = now;} if(now - last3m > P3m) {ConsensusAveraging(); last3m = now;} interrupts = 0; // Reset the flag } }
-
11 minutes ago, skybadger said:
Looking at the code I would note that constant int xxxx = 1234ul will have unintended outcomes.
Got that from the Arduino Reference for Constants.
QuoteU & L formatters:
By default, an integer constant is treated as an int with the attendant limitations in values. To specify an integer constant with another data type, follow it with:
-
a 'u' or 'U' to force the constant into an unsigned data format. Example: 33u
-
a 'l' or 'L' to force the constant into a long data format. Example: 100000L
-
a 'ul' or 'UL' to force the constant into an unsigned long constant. Example: 32767ul
-
-
42 minutes ago, JamesF said:
The mention of a backtrace before the reboot suggests to me that something has been caught running out of bounds or something like that. Perhaps run off the end of an array into memory you're not allowed to use? Attempting to dereference a null pointer might be another favourite, but I don't recall you doing any pointery type stuff in your code.
James
The problem was trying to increment a float. Now fixed.
-
Next will be to remove Serial Monitor debugging and upload the sketch to the wind sensors ESP32 and try the table based test rig. That will be tomorrow.
-
-
Found that error easily - forgot to reset the timerCount.
New code.
if (timerCount >= 21) {speed21sum(); timerCount=0;};
-
-
All lines back except
windSpeed += PulseCount; // Accumulate mean speed
Not sure why but windSpeed is a float whilst PulseCount is an integer. I'll try changing that.
-
I'll uncomment each line in turn until the problem comes back.
-
-
-
Something is causing it to reboot!!!
-
Just ran it as a test and there's something wrong. It repeatedly reconnects to the WiFi and does nothing else.
-
I have renamed the routines better to reflect the operations and separated speed and direction processes. The Timer and Hardware ISRs are now next to each other with the constant and variable declarations first. I have changed the speed averaging period to 21x3s intervals to make the divisor an integer when dividing the sum and correcting the speed (speed integration time 3s rather than the 4.5s which would have given mph directly).
This is the sketch.
// Wind speed and direction 2020-09-04 /********* 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 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 const int P3m = 180000ul; // unsigned long long last3s = 0; 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}; int dirn = 0; // 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}; // 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; // Output variables int Direction = 0; // 0-359 degrees int meanSpeed = 0; // 0-100mph int gustSpeed = 0; // 0-100mph // Set GPIO for Hall Sensor const int HallSensorPin = 4; int PulseCount = 0, windGust = 0; float 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++; windSpeed += PulseCount; // Accumulate mean speed if (PulseCount > windGust) {windGust = PulseCount;}; // Get max speed for gust 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() { // Serial.println("Hall Triggered"); ++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(); } 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 } 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 int readDirection(){ // 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 - 1) %16; // correct encoder for North return dirn; } // 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 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 sendNumberMessage2(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/number2", numString); } */ void getDirection(){ byte instDir = readDirection(); ++bin[instDir]; // increment appropriate bin sendDirectionMessageInst(instDir); // send instantaneous direction } void speed21sum(){ int divisor = 140; Serial.print("ringIndex: "); Serial.print(ringIndex); // 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 meanSpeed = 0; gustSpeed = 0; windSpeed = 0; windGust = 0; for (int i = 0; i < 10; i++) { meanSpeed += meanArray[i]; // sum the windSpeeds if (gustArray[i] > gustSpeed){gustSpeed = gustArray[i];}} // find maximum gust speed divisor = timerCount * 10 / 1.5; // with timerCount=21 this gives a whole number meanSpeed /=divisor; // the first sum was over 21 values and then the second over 10 values gustSpeed *= 1.5; // Speed count over 3s rather than 4.5s sendSpeedMessages(); ringIndex = (ringIndex+1)%10; // move ringIndex on to next location in the ring arrays } 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(); while( interrupts == 0 ){} // will spin here until the ISR sets the flag // ISR has triggered - proceed and perform the jobs if (timerCount >= 21) {speed21sum();}; // time the various periods long now = millis(); if(now - last3s > P3s) {getDirection(); last3s = now;} if(now - last3m > P3m) {ConsensusAveraging(); last3m = now;} interrupts = 0; // Reset the flag }
-
Think I may have it sussed. Used the timer interrupt just to count the anemometer pulses plus a count of times it was enacted to use later for the divisor.
void IRAM_ATTR onTime() { portENTER_CRITICAL_ISR(&timerMux); interrupts++; windSpeed += PulseCount; // Accumulate mean speed if (PulseCount > windGust) {windGust = PulseCount;}; // Get max speed for gust PulseCount = 0; // clear count timerCount++; // count number of timer interrupts for 1m speed sum portEXIT_CRITICAL_ISR(&timerMux); }
This sets the interrupts flag, counts the anemometer pulses, calculating sum and max for mean and gust speeds. Then the PulseCount is cleared for the next count and the number of times this ISR is run is counted in timerCount.
-
Decided to put the speed part of the 3s jobs directly in the ISR.
void IRAM_ATTR onTime() { portENTER_CRITICAL_ISR(&timerMux); interrupts++; windSpeed += PulseCount; // Accumulate mean speed if (PulseCount > windGust) {windGust = PulseCount;}; // Get max speed for gust PulseCount = 0; portEXIT_CRITICAL_ISR(&timerMux); }
-
I have certainly considered taking the sensor etc. out of the casing but the lens to sensor distance has to be accurate to microns!! In the past I have used fixed focus lenses in my ASCs but using the mounting thread for focussing was far too coarse. The lens I'm using now has a focus ring and focuses using a very fine thread. This is a lot better but still needs just a few degrees rotation to take the focus from good to dreadful.
I have a few ideas for finer focussing. I can get rid of backlash with a spring but have to be careful to avoid plastic creep. One idea is a lever and cam. Another is a threaded rod and nut moving the lever.
Weather Station Ideas
in DIY Astronomer
Posted
Running test rig on the table with desk fan. Seems reasonable. Mean speed slightly below the Gust speed but speeds are just to the nearest mph, so Gust of 10mph and Mean of 9mph is reasonable.