简体   繁体   English

PJRC编码器对象作为另一个对象的属性

[英]PJRC Encoder Object as Property of Another Object

I'm borrowing PJRC's Encoder library to manage a stepper-powered syringe pump I am running off a Sparkfun RedBoard and a BigEasy Driver . 我借用PJRC的编码器库来管理步进动力注射泵,我正在运行Sparkfun RedBoardBigEasy Driver

I've been developing the program modularly, defining lower-level classes first and working up from there. 我一直在模块化地开发程序,首先定义较低级别的类,然后从那里开始进行工作。 It is my desire that higher-level classes take instances of lower classes as properties. 希望较高级别的类将较低类的实例作为属性。 In my current nightmare, I'm building a syringe Pump class with Stepper motor and Encoder objects as properties. 在当前的噩梦中,我正在构建一个注射器泵类,将步进电机和编码器对象作为属性。

I'm organizing the library into a header file and '.cpp' file as recommended by the Arduino Tutorials. 我正在按照Arduino教程的建议将库组织为头文件和'.cpp'文件。 The Pump class is declared as follows in 'Pump.h': Pump类在“ Pump.h”中声明如下:

#include "Arduino.h"
#include "Stepper.h"
#include "Encoder.h"

#define PUMP_TOP_SPEED 50   // ml/min               top pump speed
#define PUMP_ERROR 10       // encoder counts       acceptable error

class Pump {

    private:

        Stepper motor;          // object       stepper motor
        Encoder encoder;        // object       attached encoder
        int countPerRev;        // #            encoder counts per relovlution
        float nominalVolume;    // mL           nominal syringe volume
        float innerDiameter;    // cm           syringe inner diameter
        float shaftLead;        // cm           driveshaft threading lead distance
        float degVolume;        // mL           effective volume change per degree of rotation
        bool state;             // boolean      T = ready, F = slept

    public:

        // constructor
        Pump(const Stepper& stp, const Encoder& enc, int cpr, float vol, float diam, float lead);

        float volume();                         // returns nominalVolume
        float position();                       // returns current pump position in mL
        void hold();                            // high power state to resist back-pressure
        void relax();                           // low power state
        void pump(float vol, float rate);       // pumps the requested volume at requested rate
        void release();                         // moves the plunger all the way out so syringe can be serviced
        void set();                             // returns plunger to zero mL
};

The relevant code in 'Pump.cpp' file which I have been testing with is the constructor and the definition of the pump() method, which goes like so: 我一直在测试的“ Pump.cpp”文件中的相关代码是构造函数和pump()方法的定义,如下所示:

// constructor
Pump::Pump(const Stepper& stp, const Encoder& enc, int cpr, float vol, float diam, float lead) : motor(stp), encoder(enc), countPerRev(cpr), nominalVolume(vol), innerDiameter(diam), shaftLead(lead) {

    // calculate volume per degree
    // (diameter^2 / 4) * PI * (lead / 360) = mL / deg
    // diam * diam * lead * PI / 360 / 4 = (diam diam lead PI) / 1440
    degVolume = innerDiameter * innerDiameter * shaftLead * PI / 1440;

    // construct the encoder inside here
    /*encoder = new(Encoder(2,3));

    // set it to 0
    encoder.write(0);*/
}

// pumping function
void Pump::pump(float vol, float rate) {

    /*
        vol < 0         INFUSE
        vol > 0         WITHDRAW
    */

    if (rate > PUMP_TOP_SPEED) rate = PUMP_TOP_SPEED; // limit rate

    if (!state) hold(); // wake up the motor if it's asleep

    // make sure this doesn't push outside of the acceptable range
    if (position() + vol <= nominalVolume && position() + vol >= 0) {

        // (mL) / (mL/deg) = deg
        float degrees = vol / degVolume; // find number of degrees to turn the motor
        Serial.print("Looking to turn ");
        Serial.print(degrees, DEC);
        Serial.print(" degrees at ");

        // (count) + (deg) * (count/rev) / (deg/rev) = count
        long goal = encoder.read() + degrees * countPerRev / 360; // set target encoder reading

        // (mL/min) / (mL/deg) / (deg/rev) = RPM
        int rpm = abs(rate) / degVolume / 360; // find RPM to turn the motor
        Serial.print(rpm, DEC);
        Serial.println(" RPM in full-stepping mode");
        Serial.print("Going from encoder count ");
        Serial.print(encoder.read(), DEC);
        Serial.print(" to ");
        Serial.println(goal, DEC);

        motor.drive(degrees, 1, rpm); // drive the pump

        int err = goal - encoder.read(); // how far from the goal are we in counts?
        Serial.print("Reached encoder count ");
        Serial.println(encoder.read(), DEC);
        Serial.print("Missed by ");
        Serial.println(err, DEC);

    }
}

I've been testing my pump() method and threw in a whole bunch of Serial.print() to try to debug and figure out what is happening and from what I can see, the Encoder object that is a property of the Pump object doesn't have its position updated as the shaft turns, whereas the Encoder object declared in the Arduino sketch and passed to the Pump constructor does. 我一直在测试我的pump()方法,并放入一大堆Serial.print()来尝试调试并弄清楚发生了什么,并且从我所看到的来看,Encoder对象是Pump对象的一个属性轴旋转时不会更新其位置,而在Arduino草图中声明并传递给Pump构造函数的Encoder对象会更新。

As you can see above I've tried to initialize the encoder within the pump constructor but the 2 or 3 things I tried all threw a bunch of cryptic errors in the Arduino IDE when I tried to compile, left that commented out section so you can see what I was trying. 正如您在上面看到的那样,我已经尝试在Pump构造函数中初始化编码器,但是当我尝试编译时,我尝试的2到3件事都在Arduino IDE中引发了一系列神秘的错误,因此在注释部分留下了注释,以便您可以看看我在想什么。

What I find exceedingly annoying is that while my own Stepper object works fine, the Pump object can turn the motor, the Encoder object won't function inside the Pump object. 我感到非常烦人的是,虽然我自己的步进器对象运行良好,但Pump对象可以旋转电动机,而Encoder对象在Pump对象内部却无法正常工作。 When I run the sketch: 运行草图时:

#include <Stepper.h>
#include <Encoder.h>
#include <Pump.h>

// initialize stepper
Stepper motor(4, 5, 6, 7, 8, 9, 10, 11);

// initialize encoder
Encoder encoder(2, 3);

// initialize the pump
Pump pump(motor, encoder, 1440, 25, 2.328, 0.1);

void setup() {
  // start the Serial connection
  Serial.begin(9600);

  // set up the motor
  motor.enable();
  motor.reset();

  // pump
  pump.pump(0.25,25);

  Serial.print("Pump reading:       ");
  Serial.println(pump.position(), DEC);
  Serial.print("Encoder reading:    ");
  Serial.println(encoder.read(), DEC);

  // cool boards
  pump.relax();

}

void loop() {}

I get back the following in the Serial monitor: 我在串行监视器中得到以下信息:

Looking to turn 211.4397277832 degrees at 58 RPM in full-stepping mode
Going from encoder count 0 to 845
Reached encoder count 0
Missed by 845
Pump reading:       0.0000000000
Encoder reading:    845

So, the method encoder.read() always returns zero in the Pump object but when I called it at the end of my sketch in the setup() function it turns I turned exactly as far as I wanted to. 因此, encoder.read()方法始终在Pump对象中返回零,但是当我在setup()函数的草图末尾调用它时,它的旋转角度恰好达到了我想要的程度。

Thank you for reading. 感谢您的阅读。 I'd appreciate guidance on how to either properly pass an active Encoder object to Pump, or how to properly initialize an Encoder object within Pump without freaking out the compiler. 我将对如何正确地将活动的Encoder对象传递给Pump或如何在Pump中正确初始化Encoder对象而又不破坏编译器的指导表示赞赏。

The key was, in-fact, to initialize the encoder within the Pump object, as I've been reading on the Arduino boards posted by people some variant of my issue. 实际上,关键是初始化Pump对象中的编码器,正如我一直在阅读由我的某些问题的人发布的Arduino板上一样。

I constructed the encoder within the property declarations of 'Pump.h'. 我在“ Pump.h”的属性声明中构造了编码器。 Since the RedBoard I'm working with is an Arduino Uno, in essence, the only acceptable pins are 2 and 3 for interrupts. 由于我正在使用的RedBoard是Arduino Uno,从本质上讲,中断的唯一可接受的引脚是2和3。 I declared the encoder with the following line under the class's list of private properties: 我在类的私有属性列表下用以下行声明了编码器:

Encoder encoder = Encoder(2,3);     //  attached encoder

And it now works flawlessly. 现在它可以完美地工作了。 There is likely an option to pass the encoder pins to the Pump constructor and have it be flexible, but for the time being I need something that works more than I need something perfect. 可能有一个选项可以将编码器引脚传递给Pump构造函数,并使其具有灵活性,但是暂时我需要的东西比我需要的更完美。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM