如何修改此直流电机编码器代码以与 4 个直流电机一起使用?

问题描述 投票:0回答:1

我一直在宽松地关注 ROS 上的 Articulated Robotics 系列,并决定使用他的 ros_arduino_bridge 代码通过串行方式从 ROS2 驱动我的电机到我的 Arduino Mega 2560。无论如何,我的机器人使用 4 轮麦克纳姆驱动,所以代码确实需要修改。

除了编码器代码之外,一切看起来都很简单,可以更改,因为它利用了我不熟悉的 Arduino 概念。从那以后我学到了一些,但不是100%。以下是我认为与编码器代码相关的所有主要部分。

在设置中:

void setup() {
...
    //set as inputs
    DDRD &= ~(1<<LEFT_ENC_PIN_A);
    DDRD &= ~(1<<LEFT_ENC_PIN_B);
    DDRC &= ~(1<<RIGHT_ENC_PIN_A);
    DDRC &= ~(1<<RIGHT_ENC_PIN_B);
    
    //enable pull up resistors
    PORTD |= (1<<LEFT_ENC_PIN_A);
    PORTD |= (1<<LEFT_ENC_PIN_B);
    PORTC |= (1<<RIGHT_ENC_PIN_A);
    PORTC |= (1<<RIGHT_ENC_PIN_B);
    
    // tell pin change mask to listen to left encoder pins
    PCMSK2 |= (1 << LEFT_ENC_PIN_A)|(1 << LEFT_ENC_PIN_B);
    // tell pin change mask to listen to right encoder pins
    PCMSK1 |= (1 << RIGHT_ENC_PIN_A)|(1 << RIGHT_ENC_PIN_B);
    
    // enable PCINT1 and PCINT2 interrupt in the general interrupt mask
    PCICR |= (1 << PCIE1) | (1 << PCIE2);
...
}

在econder_driver.h中:

...
  //below can be changed, but should be PORTD pins; 
  //otherwise additional changes in the code are required
  #define LEFT_ENC_PIN_A PD2  //pin 2
  #define LEFT_ENC_PIN_B PD3  //pin 3
  
  //below can be changed, but should be PORTC pins
  #define RIGHT_ENC_PIN_A PC4  //pin A4
  #define RIGHT_ENC_PIN_B PC5   //pin A5
...

在encoder_driver.ino中:

  volatile long left_enc_pos = 0L;
  volatile long right_enc_pos = 0L;
  static const int8_t ENC_STATES [] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0};  //encoder lookup table
    
  /* Interrupt routine for LEFT encoder, taking care of actual counting */
  ISR (PCINT2_vect){
    static uint8_t enc_last=0;
        
    enc_last <<=2; //shift previous state two places
    enc_last |= (PIND & (3 << 2)) >> 2; //read the current state into lowest 2 bits
  
    left_enc_pos += ENC_STATES[(enc_last & 0x0f)];
  }
  
  /* Interrupt routine for RIGHT encoder, taking care of actual counting */
  ISR (PCINT1_vect){
        static uint8_t enc_last=0;
            
    enc_last <<=2; //shift previous state two places
    enc_last |= (PINC & (3 << 4)) >> 4; //read the current state into lowest 2 bits
  
    right_enc_pos += ENC_STATES[(enc_last & 0x0f)];
  }
  
  /* Wrap the encoder reading function */
  long readEncoder(int i) {
    if (i == LEFT) return left_enc_pos;
    else return right_enc_pos;
  }
...

我采用了猴脑策略,仅添加另外两个 DDRB 和 DDRA,以及另外两个电机的 PORTB 和 PORTA 分配,并添加另外两个 ICR 功能。我不太确定如何进行位掩码和移位以及功能的填充。尽管据我所知,Mega 可能甚至没有足够的中断引脚来容纳 4 个电机。遗憾的是,我无法用实际的电机进行实际测试,这是一个有趣的问题,所以我希望有人可以帮助我。

c++ arduino ros arduino-c++
1个回答
0
投票

ros_arduino_bridge 主要是为 Arduino Uno Atmega328p 编码的,您可以从所选的引脚及其对应的 PCINT 中看到这一点

ATmega328P 微控制器具有三个引脚变化中断向量: PCINT0_vect:适用于引脚 PCINT0-7(物理引脚 23-30) PCINT1_vect:适用于引脚 PCINT8-14(物理引脚 1-7) PCINT2_vect:适用于引脚 PCINT16-23(物理引脚 8-14) ATmega328P上共有24个引脚可以触发引脚变化中断,但它们被分为这三个向量。您应该喜欢 Arduino uno 引脚排列以了解更多信息。

您始终可以配置多对引脚来触发编码器更改。它不一定是 PD2 和 PD3,例如仅由 PCINT2_vect 处理。您可以在那里处理其他引脚。

如果您使用 Arduino Uno,您可以执行以下操作。您可以使用分组在 PCINT0_vect 中的 PCINT0-3 并将其交叉到引脚 PB0-4(uno 头上的引脚 8-11)并连接两个新闻编码器。 (ofc 假设它们没有被使用 - 如果它们被使用,你就会明白这个概念并可以找到其他的)。

设置它们

// Set PB0-PB3 as input pins
DDRB &= ~((1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3));

// Enable pin change interrupts for PB0-PB3
PCMSK0 |= (1 << PCINT0) | (1 << PCINT1) | (1 << PCINT2) | (1 << PCINT3);

// Enable pin change interrupt for PCINT0_vect
PCICR |= (1 << PCIE0);

// Enable global interrupts
sei();

ISR 可以是这样的

volatile long left_enc_pos = 0L;
volatile long right_enc_pos = 0L;
// encoder lookup table
static const int8_t ENC_STATES[] = {0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0}; 

ISR(PCINT0_vect) {
    static uint8_t prev_state = 0;
    uint8_t current_state = PINB & 0x0F; // Read PB0-PB3 pins
    // Update enc_last based on the changes in the state of PB0-PB3
    uint8_t change = current_state ^ prev_state;

    // Check for changes on PB0 and PB1 (Left encoder)
    if (change & ((1 << PB0) | (1 << PB1))) {
        uint8_t state = (current_state >> PB0) & 0x03; // Extract the state of PB0 and PB1
        left_enc_pos += ENC_STATES[state];
    }

    // Check for changes on PB2 and PB3 (Right encoder)
    if (change & ((1 << PB2) | (1 << PB3))) {
        uint8_t state = (current_state >> PB2) & 0x03; // Extract the state of PB2 and PB3
        right_enc_pos += ENC_STATES[state];
    }

    // Store the current state for the next iteration
    prev_state = current_state;
}

如果您想使用 Arduino Mega,您必须配置用于所有 4 个编码器的引脚和 PINCT#_Vect。现有的和新的也是如此。您可以查看大型引脚图并轻松找出数字。 PCINT 在 Arduino Mega 中分组,类似于 UNO,只是映射到不同的端口和 PIN 码

© www.soinside.com 2019 - 2024. All rights reserved.