Welcome! Log In Create A New Profile

Advanced

Firmware for encoder

Posted by mccoyn 
Firmware for encoder
March 04, 2009 07:52PM
I've been having a lot of trouple with the motor on my extruder either stalling or slipping. I decided to add an encoder so that I can maintain a more consistent speed. I can't find any examples on how to modify the firmware to use an encoder. Has anyone done this? Is there any example code for how to do this?

Edit: I'm using Arduino hardware. Looking through the source it appears that there is an interrupt setup but only for Sanguino. Can I just enable this stuff?

Edited 1 time(s). Last edit at 03/05/2009 05:18PM by mccoyn.
Re: Firmware for encoder
May 08, 2009 09:40AM
Did you manage to get your firmware sorted? I've just added a simple shaft encoder to my GM3 (an unused opto-endstop and flicker wheel) and I was just looking for the same thing - arduino firmware that supports a quadrature encoder.

There's a GCode_Interpreter_experimental branch, but it seems to be a relatively old branch from the main gcode encoder.

Any ideas?


---
Reprapping blog and other rants: [renoirsrants.blogspot.com]
My Reprap: [sites.google.com]
Re: Firmware for encoder
May 11, 2009 03:05PM
I've been thinking of writing my own for a while. I've been distracted for a while, but I think I'll be back to reprapping this week. Getting an encoder working is first on my list.
Re: Firmware for encoder
May 12, 2009 07:11AM
I've started hacking the firmware to add a simple encoder speed regulator. I'll blog if it ever works...


---
Reprapping blog and other rants: [renoirsrants.blogspot.com]
My Reprap: [sites.google.com]
Re: Firmware for encoder
May 12, 2009 08:21PM
I've had some success creating a pulsed controller. This runs the motor at full speed until the encoder switches (I'm just using 1 opto-switch) and then stops until a set amount of time has elapsed. The amount of time is controlled by the host software. This isn't my final solution, but it verifies that the hardware is all working as I expect it to.

Most of my work is in a function I called extruder::manage_speed, which I called from extruder::manage. That code is below. I set up the pin definition like most the other pins (I used digital pin 15). I also added a few variables to extruder.h.

I've attached my full extruder.h and extruder.pde files to this post.

I'm using an Arduino with an Atmega328, which has more memory and program space than many of the other Arduinos. What are you using DaveR?

Please let me know if you have any improvements. I'll try to keep this thread up-to-date with my daily progress.

In extruder.pde
void extruder::manage_speed()
{
    bool next_state = read_switch(encoder_pin);
     
    if (encoder_waiting)
    {
        e_delay = millis() - encoder_time;   
        error = e_delay - (256 - e_speed);
        if (error >= 0)
        {
            analogWrite(motor_speed_pin, 255);
            encoder_state = next_state;
            encoder_time = millis();
            encoder_waiting = false;
        }
    }

    else if (next_state != encoder_state)
    {
        e_delay = millis() - encoder_time;   
        error = e_delay - (256 - e_speed);
        if (error < 0)
            {
            analogWrite(motor_speed_pin, 0);
            encoder_waiting = true;
            }
     }
}

Added to extruder.h
    bool encoder_state;
    bool encoder_waiting;
    int encoder_time;
Attachments:
open | download - extruder.h (1.9 KB)
open | download - extruder.pde (13.3 KB)
Re: Firmware for encoder
May 13, 2009 04:55AM
Nice.

I've thought about it for the last week or so, and I came up with an almost identical functional design.

I'm using a single arduino (vanilla) setup with generation 2 electronics.

I've got the older BfB laser-cut kit which has a mounting for a standard opto-encoder on the GM3 mounting. I've added a single opto on the GM3 output shaft.

I've modified the firmware to re-use the encoder stepper timer. It monitors the encoder and counts up pulses. It should run the motor until it gets a pulse, then wait out the rest of the time. It *should* give me one motor rev per set time.

I'll post it once I've fixed it. :-)

Thanks for a look at yours.




I had to 'optimise' the arduino code to free up some space, because it's close to the limit.

Some rough notes I made for a blog entry:

I've been looking at the arduino firmware recently, and trying to add some simple shaft encoder speed control.

I printed the whole firmware out and read through it. Overall, it's pretty good - but I came up with a couple of improvements for my version:

There are several spare variables defined 'for encoder use' that are never used - should these be a #define for encoder use (or delete them?)

//this is for doing encoder based extruder control
int rpm;
long e_delay;
int error;
int last_extruder_error;
int error_delta;
bool e_direction;

I'd suggest a clearly #defined set of constants that match hardware. For instance,

#define EXTRUDER_VALVE
#define EXTRUDER_ENCODER
#define EXTRUDER_STEPPER
#define EXTRUDER_DC

- then we can include/hide chunks that do or do not matter. Space is limited on the arduino single-board, every byte is useful. I cut my dev version from 14364 to 13270 by #defing the valve routines (M126/M127) and combining the temp wait for warmup/error routines into wait_for_temperature().
#defing the gcodes 81, 82, 83 (canned drilling cycles) to Sanguino also saved some space, as I don't have a drill.

I ripped out the TEST_MACHINE code - it looks like it should possibly be an alternative firmware version rather than a compile switch, as it seems to be an entirely separate set of functions, unconnected to the main code.


---
Reprapping blog and other rants: [renoirsrants.blogspot.com]
My Reprap: [sites.google.com]
Re: Firmware for encoder
May 13, 2009 08:26PM
Yeah, some of the code could definently be cleaned up. Maybe if the two of us get a well-tested patch together we can convince someone to update SVN.

My previous approach of using manage() to look for changes was missing some steps on my 20° encoder. I think it consistently missed 1 step on each cycle and then sometimes missed a second one.

Instead, I looked into using an interrupt. I found a couple links. [www.arduino.cc] [www.arduino.cc] The interrupt had to be on pin 2, so I had to move X_STEP_PIN to pin 15. I noticed that when I added the interrupt, the program size jumped up by about 200 bytes.

The interrupt subtracts a fixed amount from a counter. This amount is determined by the target speed. In manage_speed() I determine the amount of time that has elapsed since the last call to manage_speed() or set_speed() and add that to the counter. The result is that the counter holds a value that is proportional to the error in the speed and I use that to adjust the speed.

This works well. Above the stall speed, the motor finds the appropriate speed and adjusts it when the load changes. Below the stall speed, the speed increases until the motor moves, then decreases below the stall speed again. The result is that the motor pulses with enough torque to move at any (slow) speed.

I had to reset the counter to 0 every time I adjusted the speed to prevent it from oscillating out of control. I think this adds some error that limits fine adjustments at extremely low speed.

In extruder.h
//this is for doing encoder based extruder control
    long e_delay;
    int error;
    int encoder_speed;
    int encoder_time;
    volatile int encoder_count;
    int encoder_inc;

   void manage_speed();
   friend void ::doEncoder();

In extruder::extruder
#ifdef SANGUINO

        setupTimerInterrupt();
	disableTimerInterrupt();
#else
        if (  (encoder_pin >= 0) && (encoder_pin != 255)  )
            attachInterrupt(encoder_pin-2, doEncoder, CHANGE);
#endif

In encoder.pde
void extruder::manage_speed()
{
    int current = millis();
    encoder_count += (current - encoder_time);
    encoder_time = current;
    
    error = encoder_count / 4;
    if (error != 0)
    {
        encoder_speed += error;
        if (encoder_speed < 0)
            encoder_speed = 0;
        else if (encoder_speed >= 256)
            encoder_speed = 255;
        analogWrite(motor_speed_pin, encoder_speed);
        encoder_count = 0;
    }
}

void doEncoder()
{
    ex[0]->encoder_count -= ex[0]->encoder_inc;
}

void extruder::set_speed(float sp)
{
  // DC motor?
    if (  (step_en_pin < 0) || (step_en_pin == 255)  )
    {
      e_speed = (byte)sp;
      if(e_speed > 0)
          wait_for_temperature();
      encoder_time = millis();
      encoder_count = 0;
      encoder_inc = (256 - e_speed);
      encoder_speed = e_speed;
      analogWrite(motor_speed_pin, e_speed);
      return;
    }
}
Re: Firmware for encoder
May 14, 2009 03:16AM
Here's mine - barely tested...
I use the existing interrupt to poll my pin and count up. The speed is inverted and the timing might need adjustment.

Zip of my current firmware:
[sites.google.com]


---
Reprapping blog and other rants: [renoirsrants.blogspot.com]
My Reprap: [sites.google.com]
Re: Firmware for encoder
May 14, 2009 07:48PM
I've made some minor adjustments to my version. The biggest is how I calculate encoder_inc. It now uses E_MM_PER_STEP and inverts the speed. I believe it gets the correct speed as long as E_MM_PER_STEP is correct. I set it to 10, which gives me a nice range of speeds on my 10° encoder which gives me 72 steps per revolution.

I haven't added the #define ENCODER_XXX, but I think it is a good idea to do eventually.

I've attached my current source.
Attachments:
open | download - GCode_Interpreter_with_encoder.tar.gz (14.1 KB)
Re: Firmware for encoder
May 26, 2009 03:38AM
You guy's rock - I love sample code.

I've recently taken bits of this code ( minus the interrupt parts ), and used a complete PS/2 ball mouse (and just one of its encoders) as the encoder-interface on my extruder. in manage_speed() I poll the "mouse" for the change-in-coordinates since the last call, and add that to the total "distance travelled since speed change". I then compare the actual distance travelled with what should have been travelled ( based on the elapsed time), and use the difference to speed or slow, much like you guys have done.

If you are interested in the code, post here, or PM me.
Re: Firmware for encoder
May 30, 2009 05:29PM
Latest hacked version

I've modified the firmware to include a basic speed control with an encoder using interrupts.

Note:
Currently this is an untested hacked version. YMMV.

The stepper interrupt loop now counts encoder pulses. The input parameter (RPM?) in the host software (1-255) is inverted - 1 - fast and 255-slow.

The RPM param determines a set number of ticks (e.g. 1=.001 sec , 200 = .2 sec)- I've not bothered to calculate the actual timings yet.

The motor is turned on. As soon as a pulse is recorded, the motor is switched off, and it waits out the remainder of the ticks.

once the ticks are up, the counter is reset and the motor starts up again.

UNTESTED HACKED CODE. I tested it for about 30sec and it seemed to work. not yet finished - but in-progress snapshot.

[sites.google.com]


---
Reprapping blog and other rants: [renoirsrants.blogspot.com]
My Reprap: [sites.google.com]
Re: Firmware for encoder
July 16, 2009 11:32PM
I discovered a bug. When the temperature falls too low right when the extruder is turned on, it turns the extruder on and starts speeding it up before the temperature is ready. This results dumping of extra material.

I built a new heater nozzle that is less powerful and so needs long heating times, resulting in big blobs of mess.

I've attached the fixed code.
Attachments:
open | download - GCode_Interpreter_with_encoder2.tar (60 KB)
Sorry, only registered users may post in this forum.

Click here to login