element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Embedded Forum How to convert PID output into meaningful result to feed into controller
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 7 replies
  • Subscribers 461 subscribers
  • Views 937 views
  • Users 0 members are here
  • pid controller
Related

How to convert PID output into meaningful result to feed into controller

chrischristian14
chrischristian14 over 5 years ago

Hi, I am creating a pressure controller with PIC micro that is controlling the heating coil and a pocketbeagle that is running a PID loop. The PIC micro takes commands from pocketbeagle over UART.

PIC responds to 0 to 9, with 9 being heating coil switched off and 1 being full on.The PID loop outputs numbers up to 10000000, depending upon what is the difference between the measured pressure and the desired pressure, and I am really struggling to convert this PID output (0 to 10 million ) to a range of 0 to 9 and not killing the PID functionality - i.e. keeping it PID and not making it like a normal code. I managed to have a few range of loop, and each range is a PID loop on its own, but that is not an ideal solution. Below is the code I tried, int_diff is the (int) PID output. Can anyone pelase help ? I have a feeling I might be over complicating things but don't know how.

Just to explain, in below code, each range sends 0 to 9 numbers to PIC micro, so the problem arises when the difference between set pressure and measured pressure is low and it just need to go up by a little, but the output (int_diff) switches range and suddenly it goes to 0 (heating coil full on) and then on next measurement (after about a second) it goes to 9 (heating coil off), while it should be moving from 8 to 9. This kind of movement (0 to 9) causes overshoot, and the reverse is also true, causing very slow rise in temperature or undershoot.

I hope I am making sense. Thanks

if(0<int_diff && int_diff<99)
{
value = diff/10; //(gives 1 to 9)
closer =1;
}
#if 1
else if(99<int_diff && int_diff<999)
{


value = diff/100;
closer =1;
}




else if (999<int_diff && int_diff<9999)
{
value = diff/1000;
closer =1;
}
else if (9999<int_diff && int_diff<99999)
{
value = diff/10000;
closer =1;
}




else if (99999<int_diff && int_diff<999999)
{
value = diff/100000;
closer =1; 
}
else if (999999<int_diff && int_diff<9999999)
{
value = diff/1000000;
closer =1;
//value = 0;
}




if(closer==1)
{


if(value>=0)
{
value= 9-(int)value;
}
else if(value<0)
{
value=9;
}


}
else
{
value = 0;
}

  • Sign in to reply
  • Cancel

Top Replies

  • chrischristian14
    chrischristian14 over 5 years ago in reply to michaelkellett +3
    Thanks Michael, I am not new to this embedded stuff, I have about 10 years of experience in electronics and maintain an RTOS product as part of my full time work, what I am not good at is explaining things…
  • michaelkellett
    michaelkellett over 5 years ago +2
    Not making much sense ! This doesn't look like all your code ! You would do much better to have it all in one place either on the PIC or the Beagle. Steps of only 0 to 9 is quite possibly not fine enough…
  • michaelkellett
    michaelkellett over 5 years ago in reply to chrischristian14 +2
    I get the feeling you are new to all this embedded stuff. My first bit of advice is that you should never leave an unexplained observation to fester. You say that the triac turns on and then turns off…
  • michaelkellett
    michaelkellett over 5 years ago

    Not making much sense !

    This doesn't look like all your code !

     

    You would do much better to have it all in one place either on the PIC or the Beagle.

    Steps of only 0 to 9 is quite possibly not fine enough control for a PID to work correctly.

     

    Suppose you only need a power setting of 3.5 to get the correct pressure, the actual, setting will need to oscillate between 3 and 4, this can work but its not  PID.

     

    Also, the ONLY valid way to scale the output of the Beagle controller is by linearly scaling it, in your case multiplying by 9/1e7.

     

    No one ever uses a straight PID controller in real life, you always need extras like integral wind up limiting.

     

    If you describe the system in more detail and post the Beagle code it will be possible to help you (why do you need a Beagle and a PIC), how does the heater work ?

     

    I've got code for two controllers in mind, one I did for a heater which is linear and another for a fridge which is not.  But I'd need to know a lot more about you system before suggesting code.

     

    MK

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • Cancel
  • dougw
    dougw over 5 years ago

    Michael has some good points.

    However If you just want to convert the big number, you might try taking a logarithm. It could radically change performance of the PID loop and there still may not be enough resolution in the result. The D factor (error derivative feedback) in that loop can easily cause instability. Sorting out the implications might be tougher than programming a PID loop from scratch.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • genebren
    genebren over 5 years ago

    Chris,

     

    This is a little complex, but not in a good way.  Unless you need the PIC for other things, why not drive the heating coil switch directly from the pocketbeagle?  If the PIC has some other useful function, and you need to drive the heating coil switch from it, why not skip the UART ans communicate the PID output via something like a PWM signal (having a much greater range than 10 discrete levels).  The PIC could read the PWM signal as an analog input (passed through a low pass filter to convert the PWM to a DC signal).  This could allow the PID loop to be a bit more continuous and eliminate the need for the limited range of control.

     

    Best of luck!

    Gene

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • chrischristian14
    chrischristian14 over 5 years ago

    Thanks you all, the reason I have PIC an pocketbeagle is because, PIC handles ZeroCross detection and creates software PWM according to the value supplied by pocketbeagle, which handles PID. I need to have USB,WiFI n LCD display and embedded webserver functionality that's why I chose poketbeagle and since it can't handle zero cross detection or any real time processing (unless I dive into PRU codes, which is a bit of a learning curve that I would want like to avoid at this stage), I moved the ZCD code to PIC. Unfortunately I can't post all the code here because it belongs to the company.

    I fought with the PIC code for it to accept a string and then change that string to integer, I am doing the same at the moment but just for a single character instead of a string. If I can get a string and then itoa(str) then, I can have a bigger resolution instead of just 0 to 9  and that may solve the problem. For some reason the PIC halts or at least it stops activating the tirac used to switch coil. It always stops the coil and never gets stuck in ON position. Here is my PIC code.

     

    #include <xc.h>
     #include <stdlib.h>
    #include <math.h>
    #include <stdint.h>
    #include "main.h"
    #include "UART.h"
    
    
    // BEGIN CONFIG
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
    #pragma config PWRTE = OFF       // Power-up Timer Enable bit (PWRT enabled)
    #pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
    #pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
    #pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
    #pragma config FEXTOSC = OFF    // External Oscillator mode selection bits (Oscillator not enabled)
    #pragma config RSTOSC = HFINT1  // Power-up default value for COSC bits (HFINTOSC (1MHz))
    //END CONFIG
    int i=0;
    int my_delay = 10000;
    int t, value=0;
    char zc;
    char result[2];
    char foo, buffer[3] ; // 10(0x0D))
    char counter=0; 
    
    
    void interrupt ISR(void)
    {
        if(INTF) // check if RA2/INT interrupt is triggered.
            INTF=0;
             GIE=0;
            zc = 1;
            if(INTEDG)
                INTEDG =0;
            else
                INTEDG =1;
            GIE =1;
    }
    
    
    setup(void)
    {
        TRISA4 = 0; //Set as output 
        TRISAbits.TRISA2 =1;
        ANSELAbits.ANSA2 =0;
        INLVLAbits.INLVLA2 = 1;
        INTPPS = 0x02;
        INTE =1;
        INTF = 0;
        INTEDG = 1;
        
        zc = 0; 
    
    
        PEIE =1;
        GIE=1;          //Enable Global Interrupt
        
       delay_ms(500);
    }
    
    
    delay_ms(unsigned int ms)
    {
        while(ms > 0)
        {
            __delay_ms(1);
            ms--;
        }
    }
    void delay_10us(unsigned int us_count)
     {
        while(us_count!=0)
          {
            for(int i=0;i<11;i++)
            {
             __delay_us(1)  ;
    us_count--;
            }
       }
       }
    
    
    
    
    
    
    ser_process()
    {
       char str[8];
       {
       UART_Read_Text(str,8);
       delay_ms(200);
       UART_send_string(str);
        }
    
    
    #if 0 
        if(RC1IF)
        {
    
    
       foo = UART_get_char();
       buffer[counter]=foo;
       counter++;
       if(foo==0x0D)
       {
       buffer[counter]=0x00; // remove 0x0D
       my_delay = atoi(buffer);
       if(my_delay>9) // make sure not to overshoot
           my_delay=9;
       UART_send_string(buffer);
       itoa(result,my_delay,10);
       
       for(int i=0;i<3;i++)
       {
           buffer[i] =0x00;
          
       }
        counter = 0;
       
       }
                 }
    
    
    #endif
                
    }
    void main(void) 
    {
      
        OSCCON1bits.NDIV = 0; // necessary 
        OSCFRQbits.HFFRQ = 0b011; // 8MHz
        
        Initialize_UART();
        setup();
        my_delay = 1;
    
    
            while(1)
                
            {
    
    
    #if 1
                while(zc==0);
                
                {     
                delay_ms(0);  //THIS IS WHERE THE VALUE FROM PID SHOULD GO
                RA4 = 1;
                }
                __delay_us(500);
                RA4 = 0;
                zc = 0; 
    #endif
    
    
              ser_process();
        
        
    
            }
    
    
        
        return;
    }

    I played around with it and found that even if I try to receive individual characters, it can't handle more than than three characters and then it gets stuck, the code still responds to UART but the heating coil stays off. In the above code I have hard coded for it to stay on (delay_ms(0)), and still it goes off, and  this is where I would want to use __delay_us instead, to get higher resolution, so I can send inputs e.g 34587, instead of just 3. So the question is why above code would suddenly turn the heating coil off ? while continue to respond to UART. Thanks

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • michaelkellett
    michaelkellett over 5 years ago in reply to chrischristian14

    I get the feeling you are new to all this embedded stuff.

     

    My first bit of advice is that you should never leave an unexplained observation to fester.

     

    You say that the triac turns on and then turns off unexpectedly. You need to know why.  You haven't posted a circuit so I can't help you work that out.

    You need to get a scope on it ( EXTREME CAUTION - IF YOU ARE CONNECTED TO MAINS POWER).

    Start with the simplest of PIC code that just switches the triac on for a 20 cycles and then off, get that working.

     

    Your UART code doesn't work but you are calling  functions like UART_Read_Rext() which we can't see - are they any good.

     

    Which of the many PIC processors are you using and which debugger. All modern PICs support hardware debugging - you need to use it to see what is going on.

     

    If your system is mains powered then for development I very strongly suggest that you use low voltage  AC (like 24V) from  a transformer.

     

    If you are not using opto coupled drivers (possibly with built in zero crossing detection) - why not - unless you are going to build many thousands of this thing it is a totally false economy to direct drive a mains switching triac.

     

    Do you actually need cycle by cycle control or could you use integral cycle "pwm" - if your thermal time constant is long enough (greater than about 20 seconds) then you can - then you could use a nice, safe, ready made solid state switch.

     

    Finally, a point of ethics, if you are working on a commercial project you should say so and give a little detail (like the area of business) - many people on E14 will still help you if this is your paid work, but might not wish to do so or may have ethical reservations about some areas of work.

     

    Hope some of this helps.

     

    MK

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • Cancel
  • chrischristian14
    chrischristian14 over 5 years ago in reply to michaelkellett

    Thanks Michael, I am not new to this embedded stuff, I have about 10 years of experience in electronics and maintain an RTOS product as part of my full time work, what I am not good at is explaining things on forums.

    Yes I  am using optocouplers to drive triac and yes I have tested it with basic code etc.

    The UART works fine, that's why I didn't add the code for UART.

    The PIC is 16F15323. I am using PID because that is client requirement -- so yes this is a commercial project.

    Finally I figured out what is causing the problem, I still haven't figured out how to solve it. -- The problem is by the time UART finishes receiving three or more char, a zero cross interrupt had already occurred, so the TRIAC misses the opportunity to get triggered, I think it's just about resetting the trigger flag at the right place. -- a little break and a fine cup of tea, that's all I needed to see things more clearly.

    Thanks everyone for the help.  

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • Cancel
  • genebren
    genebren over 5 years ago in reply to chrischristian14

    Chris,

     

    In looking at your interrupt function:

    void interrupt ISR(void)  
    {  
        if(INTF) // check if RA2/INT interrupt is triggered.  
            INTF=0;  
             GIE=0;  
            zc = 1;  
            if(INTEDG)  
                INTEDG =0;  
            else  
                INTEDG =1;  
            GIE =1;  
    } 

    I am not sure if the initial 'if(INTF) is intended to qualify all of the remaining code, or if the indention is unintentional.  Without braces '{}' the only statement that is dependent on the 'if(INTF) statement is 'INTF=0', all the remaining statements are executed on any interrupt, which might be causing your code to set zc to one unexpectedly.

     

    Not sure if this is part of your problem, or just me getting confused by the indention.

     

    Good luck!

    Gene

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube