Who is here? 1 guest(s)
 Print Thread
TC4 with aArtisanQ_PID
renatoa
Two questions for anyone that has a deep understanding of TC source:

- why there is no data stream output, for any protocol, if standalone mode is chosen ?
Somewhat related, why no buttons/profile available if using an external roasting app?
In both cases the reasoning is same as above, maybe I want to roast with internal TC4 profile/PID and send data to Artisan... seems not possible with actual code.

- the second is about power control when using ICC... at some moment in time inside the ISR routine, at line 151, the Bresenham's algorithm decide to raise OT_ICC pin to HIGH. I don't see where in the code/moment in time, where the OT_ICC pin is reset to zero before the start of the next half sine, which is mandatory, imo, else the ZCD will never trigger one more time the ISR. And the heater will remain full power on forever. At least so happens to me...

btw, in my twisted mind, ISS should logically reside in same module as slow PWM control. Using a ZCD doesn't not make this method belonging to the phase angle principle, is still an on-off method, very fast and synced with frequency, but on-off.
Why would be this preferable... because there could be cases of ZCD malfunction, experienced them, where merging ICC with PWM in the same code would allow instant switching from ICC to slow PWM if ZCD fails/timeout. And save the roast... Grin
 
greencardigan
I don't have a full understanding of how the ICC code works but I will have a look at when I get a chance.

I believe that I didn't see any need at the time to include any output stream in standalone mode. It was intended for use when logging software was not being used. Maybe the TC4 profiling and buttons could be activated when in other modes? Actually it appears that the profile code is active in all modes. As you know there were low memory issues at one time and the button checking code was disabled in other modes to try and reduce memory usage. It is quite possible that it could be added back in as there was also some other memory savings.

Regarding the ICC and PWM being separate , this was a result of my merging of Jim's two branches. He had a PWM and phase angle control branches each with their own libraries and I simply merged them and include the appropriate library as required.
 
mg512
I had some free time this weekend and did a little experimenting with PID control, since this has been discussed again a few times recently. I noticed that PID behaves very differently in the sketch I have been using (based on an old aArtisan v3.10) compared to the latest aArtisanQ_PID.

In particular, my PID tuning parameters worked decently well on the old aArtisan sketch. But on aArtisanQ_PID, they gave serious oscillations, and heater output jumped only between 0 and 100%. Interestingly, this depended a lot on the tuning parameters used:

* Without a D-term, there was no appreciable difference.
* With a large D-term, aArtisan was fine, but aArtisanQ_PID oscillates.

After a lot of digging I think I found the issue: In aArtisanQ_PID the PID calculations are only done once per iteration of the main loop. Given the ADC delays, that's about once every 1.25 seconds. In the old aArtisan, the PID was also updated during the delay loop waiting for the ADC. I think this is especially bad for the D-term, since the error can change quite a lot in 1.25 seconds.

In any case, updating the PID during the delay loop seems to fix the issue for me, and PID control is now stable even with a large (32) D-term.

greencardigan, I have sent you a draft pull request on github - perhaps you can have a look. If anyone wants to give it a test in the mean time, the code is available here:

https://github.co...tisanQ_PID
 
greencardigan
I haven't had a chance to look at your pull request yet, but a few comments.

If I remember correctly, the ADC reads etc should take less than 1 second when using two channels. The loop and PID update should then run every 1000ms. If the loop will take longer tha 1 second then it should run every 2000ms.

The PID library should only compute after the period set by

void PID::SetSampleTime(int NewSampleTime)
which is 1000 ms and set in user.h. Not sure why trying to compute more often would do anything.
 
renatoa
The 18 bit ADC sample is minimum 270 ms, 300ms for safety, so 540-600ms for two channels minimum loop time.
If someone want faster loop time, maybe an interlacing of ADC readings could help, I mean reading a single ADC every cycle.
Not sure someone would need this, because the actual TC4 resolution (0.3 C degree) is lower than the temperature variation in one second - 0.16 C degree per second, for 10 C RoR.

If we are here, additional to the remark I sent last evening, about power at start, we should also think to a method to sync the ADC reading and loop time, with the Artisan READ commands, to avoid a lot of RoR issues that looks like temperature oscillations, but actually is a beating phenomenon, between the two loop frequencies, Artisan and TC4.

Not the last, why someone would need a D-term in a so slow roasting process?
What are the fast temperature changes that we want to calm down with a D-term ?
If such changes are reported by the measurement chain, then what is measured is too much (turbulent) air, not beans, I would try to address this instead.
 
mg512
I think PID::Compute() should be called as often as possible. It will decide itself when to update and when not to. From the PID library, in pid_v1.cpp:


/* Compute() **********************************************************************
 *     This, as they say, is where the magic happens.  this function should be called
 *   every time "void loop()" executes.  the function will decide for itself whether a new
 *   pid Output needs to be computed.  returns true when the output is computed,
 *   false when nothing has been done.
 **********************************************************************************/
bool PID::Compute()

If you call it less often, you essentially force the cycle time to be longer. With 4 channels, the ADC will take 1200ms.

But even with 2 seconds and 600ms, the PID cycle time will be 1200ms even if it is set to 1000ms, since PID::Compute() would only be called at 600ms and 1200ms.
edit: Nevermind, this is incorrect. I missed that the main loop waits until 1000ms. This is even worse though. See my next post.

Generally, you should call PID::Compute() much more frequently than the cycle time you want, unless you time it very precisely so that the Compute() calls happen exactly at or just after after the PID cycles. Otherwise, you get a different cycle time than intended, or even worse, irregular PID updates. This could mess up the output, since the PID code assumes regular updates and I- and D-parameters depend on cycle length I think.

On a side note, we could do away with the ADC delay loop altogether, if we do something similar in get_samples() as the PID::Compute() function does: Only execute if enough time has passed, otherwise return immediately. That makes the code a little simpler. I gave this a quick try, and can upload to github if you're interested.

Quote

Not the last, why someone would need a D-term in a so slow roasting process?

You could still have fast changes in set point, for instance. And besides, even if it's not needed, the code shouldn't misbehave if it's used. Fair point about measurement noise though, that's also something to keep in mind.
Edited by mg512 on 04/08/2019 4:25 AM
 
renatoa
Nope, check what the code is actually doing, not what the comments are claiming to do... doesn't work as you think.

The Compute is performed exactly at cycle time multiples, whatever it is, not related to ADC at all.


   unsigned long timeChange = (now - lastTime);
   if(timeChange>=SampleTime)
...
   }
   else return false;


If cycle time is 1000 ms, and we have two ADC channels active, thus 600 ms will be spent with acquisition, and 400 ms available for other tasks, the PID.Compute is called very one second.

If you change the code to call three times Compute in a second, then two calls will be no effect, just enter and exit function immediately, not performing any computations.

Once again, the weak point of the whole thing in this moment is the resolution, not the sample time.
With the actual resolution of 0.3 C degrees, you can sample the temperature as low as 3 seconds rate, for an average RoR of 10 C degrees per minute.
That's because a good digital image of a process requirement is the samples be taken at least at the 2x the rate the changes happens, is called Nyquist theorem.

Another factor to think about if anyone want to redesign the PID... power must change much slower than the actual PID output drive the heater.
A pro roaster will never change power level so chaotic as we see in the PID output graphs, a good roast can be driven with 4-5 power change for the whole cycle, and nothing else.
For this reason I changed the way how the output is driven in my PID code, switching to an incremental approach, instead output absolute values.
The Compute function decide only the direction to follow, and the change is only 1 unit per cycle, see code below.


     //*myOutput = output;
     if (*myOutput < outMin)
        *myOutput = outMin;
     else {
        if (*myOutput < output) *myOutput += 1;
        if (*myOutput > output) *myOutput -= 1;
     }


... instead of former direct value output, the first line in code above, which is commented now.
 
renatoa
More clarification how the time is spent into the main loop:

0 ms loop start
... 2-3 ms stuff without much impact

checkSerial(); // Has a command been received?
... the above can take a while... in the tenths of ms ballpark, but less than 100

get_samples(); // Read temperatures
... here we have the main time consumption, + 600 ms

// Read analogue POT values if defined
// Run PID if defined and active

... the above are actual power control... some tenths of ms

// Update LCD if defined
... again some some tenths of ms

// Send data to Roastlogger if defined

In this moment, based on my measurements, we are somewhere at the 800 ms ballparks, the rest to 1000 ms is spent in a look checking for serial input and buttons for command

// wait until looptiom is expired. Check serial and buttons while waiting
while( millis() < next_loop_time ) {
checkSerial(); // Has a command been received?
...
checkButtonPins();
#endif
#endif
}

// Set next loop time and increment counter
next_loop_time = next_loop_time + looptime; // add time until next loop
counter = counter + ( looptime / 1000 ); if( counter > 3599 ) counter = 3599;
}
 
mg512
Ah, right, I missed that the main loop always waits until 1000ms have elapsed. But this is actually even worse. In fact calling PID::Compute() at intervals roughly the same as the configured cycle length is the worst case scenario! Consider what happens if there is even a 1ms variance between loop executions:
* If the main loop takes 1001ms, you have 1001ms between two calls to PID::Compute(). That means PID::Compute() does its calculations.
* If on the other hand you have 999ms between two calls, PID::Compute() does nothing in this iteration. So then you have a roughly 2000ms interval between PID updates. This then messes up the I- and D-terms for that update.

This is what I meant by "irregular updates" in my previous post.

I just tried this to be sure. Add a couple of serial outputs to PID_v1.cpp in PID::Compute(): One every time the function is called, and one only if the update is actually performed. With timing information, e.g. like this:



   Serial.print("PID::Compute() called at ");
   Serial.print(timeChange); 
   Serial.println(" ms after previous PID update.");
   if(timeChange>=SampleTime)
   {
      Serial.print("PID update cycle time ");
      Serial.println(timeChange); 


And check the serial output after you turn on the PID:



PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000
PID::Compute() called at 1001 ms after previous PID update.
PID update cycle time 1001
PID::Compute() called at 999 ms after previous PID update.
PID::Compute() called at 2000 ms after previous PID update.
PID update cycle time 2000
PID::Compute() called at 999 ms after previous PID update.
PID::Compute() called at 1999 ms after previous PID update.
PID update cycle time 1999
PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000
PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000
PID::Compute() called at 1001 ms after previous PID update.
PID update cycle time 1001
PID::Compute() called at 999 ms after previous PID update.
PID::Compute() called at 1999 ms after previous PID update.
PID update cycle time 1999
PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000
PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000

Edited by mg512 on 04/08/2019 4:34 AM
 
renatoa
I can't figure how the 999-1001 situation could happen, when we have about 200 ms to burn doing nothing in a cycle... enough margin to never have the 2000 ms scenario.
Also, the 999 ms scenario is impossible because PID is always called at loop start, you can't have timeChange smaller than SampleTime, unless the clock of your board is ticking in twilight zone... Shock

But... the most important... almost nothing is messed !
Even for the 2000 ms scenario, the I-term will add double error in double time, so what's the drama ?
D-term could be affected indeed, because Brett suppose a constant run interval, because he want to save a division operation in the D-term computation.
Check here his reasoning http://brettbeaur...mple-time/
Can be easily fixed reinstating the right, complete, formula for D-term, but I don't see in real world the need for this. First because on my machine the PID is called quartz stable at 1000 ms, never recorded a glitch, and second... oh, yeah, my D-term is zero always Grin

As I already wrote... the lack of sync with Artisan READ is infinitely bigger issue, Artisan never knows what is the age of the results received as a reply to a READ. Could be 1 ms old, could be 999 ms... unknown, and variable in time, because different loop timings.
Already discussed this issue with Makomo, and he can't do nothing, the ball is in TC field, if the loops have to be synced, then only in TC4 can be done.
Actually, is quite simple... make the get samples call async, triggered from two places, either from the loop if no Artisan usage, either by the READ command, and in this second case in the main loop either use conversion values, either wait for conversion to finish.
 
mg512
Of course you can have timeChange smaller than SampleTime. That's precisely what is supposed to happen if you call PID::Compute() frequently. PID::Compute() then checks if timeChange is at least SampleTime, and only if that's the case it will actually perform the PID calculations. That is the if-statement in the pasted code above by the way, where I added the debug serial output - that's already in the PID::Compute function. See below for the full code, if it doesn't make sense.

To be clear, the serial output I pasted above is directly from aArtisanQ_PID recompiled with the added serial output in the PID library. If you don't believe the 2000ms-interval can happen, please do verify this yourself.

The I-term will add half as much if you skip an update. But the D-term will count twice as much. Hence this adds lots of instability with a large D-term; it will still mess things up with only an I-term though.





/* Compute() **********************************************************************
 *     This, as they say, is where the magic happens.  this function should be called
 *   every time "void loop()" executes.  the function will decide for itself whether a new
 *   pid Output needs to be computed.  returns true when the output is computed,
 *   false when nothing has been done.
 **********************************************************************************/
bool PID::Compute()
{
   if(!inAuto) return false;
   unsigned long now = millis();
   unsigned long timeChange = (now - lastTime);
   // DEBUG: Write to Serial every time the function is called:
   Serial.print("PID::Compute() called at ");
   Serial.print(timeChange); 
   Serial.println(" ms after previous PID update.");
   if(timeChange>=SampleTime)
   {
      // DEBUG: Write to Serial every time an update is actually performed:
      Serial.print("PID update cycle time ");
      Serial.println(timeChange); 
      /*Compute all the working error variables*/
      double input = *myInput;
      double error = *mySetpoint - input;
      double dInput = (input - lastInput);
      outputSum+= (ki * error);

      /*Add Proportional on Measurement, if P_ON_M is specified*/
      if(!pOnE) outputSum-= kp * dInput;

      if(outputSum > outMax) outputSum= outMax;
      else if(outputSum < outMin) outputSum= outMin;

      /*Add Proportional on Error, if P_ON_E is specified*/
      double output;
      if(pOnE) output = kp * error;
      else output = 0;

      /*Compute Rest of PID Output*/
      output += outputSum - kd * dInput;

       if(output > outMax) output = outMax;
      else if(output < outMin) output = outMin;
       *myOutput = output;

      /*Remember some variables for next time*/
      lastInput = input;
      lastTime = now;
       return true;
   }
   else return false;
}
 
renatoa

Quote

PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000
PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000
PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000
PID::Compute() called at 1000 ms after previous PID update.
PID update cycle time 1000


Sorry, can't debug this... Grin
 
mg512

Quote

renatoa wrote:
Sorry, can't debug this...


Huh, that is odd. I just verified again on my end. I assume you left it running for more than those 4 seconds? Are you on the latest aArtisanQ_PID from git, and latest Arduino version? You wrote earlier that the PID gets called at the loop start - that is not the case in the latest git version, there the PID code is in the middle of the loop: line 1526 onwards on https://github.co....ino#L1526

Anyway, we are also getting a bit sidetracked here. There is no harm in calling PID::Compute() more often. And even if calling it only once per main loop wasn't an issue with the default settings, it would still be a problem with cycle times <1000ms or 4 active channels.
 
renatoa
Yes, same code, was wrong about the loop start, I meant after getsamples, which for me is the logical loop start, where everything begins.

Cycle time should be changed according to DAC usage, this is obvious.
With 4 channels it should be increased to 1500 at least.
Or use my 60 ms improved architecture from TC4ESP fork, can be used for Arduino too. Is what I advise any existing TC4 user.
Sorry if I forgot to mention, the acquisition time is 120 ms in the rock stable loop above ...
 
ROSTARN
Hi guys
My setup is resitive heater on OT1, ac fan on OT2 and DC motor on IO3, using PAC2 mode.

Ive been experimenting with the pwm frequency on IO3 by changing the prescaler on line pwmio3.Setup( IO3_PCORPWM, IO3_PRESCALE_8 )
It works nicely to change it but I get some strange results.

It seems like when I lower the frequency under 500 Hz, the speed of the DC motor maxes out at 30% duty cycle. AC fan is behaving as expected.

When I put on 30kHz The motors speed correlates to the duty cycle but then the AC fan needs a 50% duty cycle to even start moving.

And this happen when AC and DC fan (OT2 and IO3) are running at the same time.

Haven't looked at the heaters behavior yet.

It seems like a prescale at 3.9kHz is the happy medium but I get this high pitch coil whine from the motor that I wish to removesmile

Is this behavior known or can be explained?
 
renatoa
Hi,

I want to show you a finding in TC4 PID actual implementation that is actually a flaw for most roasting machines, even if in theory it is packed nice as initially intended, under the windup term.

Is about the second line of code below:



        if (outputSum > outMax) outputSum = outMax;
        // else if (outputSum < outMin) outputSum = outMin;


from Compute method.
Please notice the second line in the code quoted above is commented, as is in my code. You will find it active in yours, without the // characters in front.

What's wrong with this... well, the initial PID code of Brett had been designed to cover the pure theory of PID, without any particularization for a specific process type.
In theory, the processes can evolve in both directions, up and down, and variables can have either negative or positive values.
In a thermal process this means it can heat, or cool, I mean forcefully cooled, when output of PID is negative !!!
In most roasters this is not true, our heaters only heat, and output is always positive. outMin is zero almost everywhere, probably nobody is using other value for outMin (i.e. MIN_OT1).
Sure, there could be very advanced machines, where the PID controls also the airflow, so a positive output has a meaning for burners only, and a negative output for the fan, but is not the case of the most home built, or even commercial machines.

What is the impact of this in driving a roast: it amplifies oscillations, if any, or, creates conditions to appear, even for perfectly tuned systems.
That's because the outputSum, after accumulating some error values, will never decrease under outMin, to become negative, thus reducing the output, even if error became negative !
If you ask how it is working then a profile following, with this logic flaw, well, it's pure luck due to the nature of our process: the always rising setpoint ! Even if the error become negative, but without effect on the output, due to the outMin clamping of I term, the setpoint will continue to increase, catching up the process value, the negative error will nullify, then start to increase, and the issue will repeat.

This flaw can be better observed for the cases when the temperature is not increasing, but decreasing! As in the beans charge in a machine with preheat, how well is handled the TP undershoot :D
This is where I noticed first time the adverse effect of this code line, trying to explain the issues I have to recover from TP undershot, because there is no I term built there to push the power up, helping flatten the TP transition to match the profile.
After some PID debugging, when I saw that error increase but output stay stable and not compensate, was easy to locate the culprit.

So, if you have oscillations in your current setup you are unable to get rid off using any tuning, give a try to this small change and tell me how it works.
Edited by renatoa on 11/04/2020 1:38 PM
 
greencardigan
I have added a new mode to the aArtisanQ_PID sketch which allows PWM control of a DC fan connected on the IO3 port and integral cycle control / burst fire for the heater on OT1. In user.h just enable the CONFIG_PAC2_IO3FAN mode.

It is similar to the original PWM mode but it does ICC/Burst fire for the heater instead of slow PWM. The new mode requires a zero cross detector though.

I have attached the sketch for testing to this post. Let me know if you try it, and if you have any issues.
greencardigan attached the following file:
aartisanq_pid_6_8.zip [2.45MB / 722 Downloads]
 
renatoa
Why not combine both in single automatic mode, that use slow pwm if no zcd, and icc otherwise, switchable at runtime, without recompile.
Is how I did in TC4ESP, because noisy mains environments, that cause false ZCD triggering.
 
sebiiksbcs
Nice that there's still development on this. I have been looking at the code and saw that there were changes in the way the buttons are checked, too? (buttons.keyPressed / buttons.keyChanged) Is this more efficient now?

Next question, I see that there are the two arrays profile_name[40] and profile_description[80], however it looks like only the first 20 bytes of the name and 40 bytes of the description are ever accessed (to be displayed on the LCD) or am I missing something here? Anyway in my custom branch I have reduced the name array to 20 and done away entirely with the description as I don't use it, instead I am displaying the first 5 times and temps of the profile.

TL;DR I believe many bytes of RAM can be saved by reducing array sizes.

Actually while I am here, I was wondering how many of you still use the firmware for standalone as I've implemented profile editing commands via serial monitor. If there is interest I could "revert" my code to be compatible with the original branch and share it ...
 
renatoa
A lot of memory can be saved in the TC code area, there is no need to let the J and T type termocouples code alive and eat space, when only K is used.

Me too added a PROF(ile) command, for fully profile management via serial, but is there just for the record, because switched to other profiling paradigm, based on DE and FC moments only as targets.

Not sure what you mean "as standalone", my goal in TC4ESP was been to use it as standalone as possible, getting rid of any computer tethering, and I think I succeeded... but with other memory resources, not available for Uno boards.
So yes, I am roasting with the board only, all time. However, every roast data points are stored in the board memory, and I can dump later via serial directly in Artisan .csv format, for desktop graph, analyse, archiving, etc.
 
greencardigan

Quote

sebiiksbcs wrote:
Nice that there's still development on this. I have been looking at the code and saw that there were changes in the way the buttons are checked, too? (buttons.keyPressed / buttons.keyChanged) Is this more efficient now?


First change in a few years woohoo.
I was working on another project (hot air reflow controller) and wanted this mode for it.

The buttons.keyPressed / buttons.keyChanged have been in there for a long time. They are used if you have the LCDapter code active. If using the other I2C LCD option it use the code in checkButtonPins().

Quote


Next question, I see that there are the two arrays profile_name[40] and profile_description[80], however it looks like only the first 20 bytes of the name and 40 bytes of the description are ever accessed (to be displayed on the LCD) or am I missing something here? Anyway in my custom branch I have reduced the name array to 20 and done away entirely with the description as I don't use it, instead I am displaying the first 5 times and temps of the profile.

TL;DR I believe many bytes of RAM can be saved by reducing array sizes.


I haven?t looked at it too closely but I think your right, it looks like only half of memory allocated gets used. Also the profile_name and profile_description don?t get used at all unless it is running in standalone mode which is currently the only time buttons are checked and the LCD can display alternative views.

Quote


Actually while I am here, I was wondering how many of you still use the firmware for standalone as I've implemented profile editing commands via serial monitor. If there is interest I could "revert" my code to be compatible with the original branch and share it ...

I?m not aware of many using the standalone mode. I added it for myself many moons ago but found the uploading of profiles too cumbersome. I?m assuming that most users are connecting to Artisan roasting software.

I?d be still interested in seeing it. If I get around to it I could try to tidy up the code to save memory (will look at the thermocouple code as suggested by renatoa ThumbsUp)
 
greencardigan

Quote

renatoa wrote:

A lot of memory can be saved in the TC code area, there is no need to let the J and T type termocouples code alive and eat space, when only K is used.

Me too added a PROF(ile) command, for fully profile management via serial, but is there just for the record, because switched to other profiling paradigm, based on DE and FC moments only as targets.

Not sure what you mean "as standalone", my goal in TC4ESP was been to use it as standalone as possible, getting rid of any computer tethering, and I think I succeeded... but with other memory resources, not available for Uno boards.
So yes, I am roasting with the board only, all time. However, every roast data points are stored in the board memory, and I can dump later via serial directly in Artisan .csv format, for desktop graph, analyse, archiving, etc.

Yes, this is what standalone mode is referring to in the code. No connection to any other device while roasting. Using profiles stored on the TC4 eeprom.
 
sebiiksbcs

Quote

I?d be still interested in seeing it. If I get around to it I could try to tidy up the code to save memory (will look at the thermocouple code as suggested by renatoa :ThumbsUp:)


Edit: wow, directly pasting the code seemed to break the layout. I've attached the cmndreader.cpp and cmndreader.h files.



This is only the respective "doCommand" function in cmndreader.cpp, of course you'd have to add all the class, prototype, initialization etc. stuff. Also I have made quite some modifications on your code just so I could better read and understand it, and to save some bytes of memory here and there so the firmware could run standalone and talk to artisan at the same time without crashing.

Hope this makes sense, not sure what other mods I made that might prevent the code from running, but since you wrote the firmware I guess you'll figure it out! Let me know if anything's missing.
sebiiksbcs attached the following file:
cmndreader.zip [6.77kB / 644 Downloads]
 
renatoa

Quote

greencardigan wrote:
...I could try to tidy up the code to save memory (will look at the thermocouple code as suggested by renatoa ThumbsUp)


Check the modified thermocouple code in the TC4ESP custom libraries folder:

https://github.co...ermocouple

The new usingK(T/J) defines are the flags that invalidates big chunks of code, for each unused TC code.
 
czeffy66
I thought I would share my adventures with ARDUINO UNO WiFi REV2. My understanding was that these boards are kind of compatible with each other, at least this one with uno, they just added the integrated WIFI, I thought it might be good feature in the future. Unfortunatelly when I tried to compile the aArtisanQ_PID, I have got all kind of variables not in the scope messages and did not compile. I even installed everything twice, I thought I did something wrong. When I had an idea to compile it on uno and it worked, so I ordered an UNO REV3. Now I hope that REV3 is compitable with the original.
 
Jump to Forum: