Arduino
void LpwmCb(const std_msgs::Int32& pwm){
if(pwm.data == 0) { ledcWrite(ledChannel1, 0); ledcWrite(ledChannel2, 0); }
if(pwm.data > 0) { ledcWrite(ledChannel1, abs(pwm.data)); ledcWrite(ledChannel2, 0); }
if(pwm.data < 0) { ledcWrite(ledChannel1, 0); ledcWrite(ledChannel2, abs(pwm.data));}
}
This code defines two callback functions, LpwmCb()
and RpwmCb()
, which take a std_msgs::Int32 object as input. The functions control the speed of 2 motors by writing PWM signals using the ledcWrite function.
The if statements check the value of the input pwm.data and determine which PWM signal to write to each motor.
If pwm.data is zero, then both PWM signals for the corresponding motor are set to zero, which stops the motor.
If pwm.data is positive, then the first PWM signal is set to the absolute value of pwm.data, which sets the motor to move forward.
If pwm.data is negative, then the second PWM signal is set to the absolute value of pwm.data, which sets the motor to move backward.
void setup() {
nh.initNode();
nh.advertise(left_enc_pub);
nh.advertise(right_enc_pub);
nh.advertise(left_enc_error);
nh.advertise(right_enc_error);
nh.subscribe(Lpwm_sub);
nh.subscribe(Rpwm_sub);
ledcSetup(ledChannel1, freq, resolution);
ledcSetup(ledChannel2, freq, resolution);
ledcSetup(ledChannel3, freq, resolution);
ledcSetup(ledChannel4, freq, resolution);
pinMode(encoderLPin1, INPUT_PULLUP);
pinMode(encoderLPin2, INPUT_PULLUP);
pinMode(encoderRPin1, INPUT_PULLUP);
pinMode(encoderRPin2, INPUT_PULLUP);
pinMode(standby, OUTPUT);
digitalWrite(standby, HIGH);
ledcAttachPin(LForward, ledChannel1);
ledcAttachPin(LBackward, ledChannel2);
ledcAttachPin(RForward, ledChannel3);
ledcAttachPin(RBackward, ledChannel4);
lastStateL = digitalRead(encoderLPin1);
lastStateR = digitalRead(encoderRPin1);
attachInterrupt(digitalPinToInterrupt(encoderLPin1), updateEncoder_L, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderLPin2), updateEncoder_L, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderRPin1), updateEncoder_R, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderRPin2), updateEncoder_R, CHANGE);
}
This code snippet is used to set up the various settings needed for the robot to operate, including the ROS node, PWM signals for the motors, encoder signals for the wheels, and interrupt service routines for updating the encoder counts.
The
nh.initNode()
function initializes a node in the ROS (Robot Operating System).The
nh.advertise
functions advertise four topics in the ROS :left_enc_pub
,right_enc_pub
,left_enc_error
, andright_enc_error
. These topics are used to publish information about the state of the encoders on the left and right wheels of the robot.The
nh.subscribe` functions subscribe to two topics in the ROS : ``Lpwm_sub
andRpwm_sub
. These topics are used to receive PWM signals that control the speed and direction of the left and right motors.The
ledcSetup
functions set up four LEDC (LED Control) channels with the specified frequency and resolution. These channels are used to generate PWM signals for the left and right motors.The
pinMode
functions set the pins used for the encoder signals to input mode with pull-up resistors. These pins are used to read the signals from the encoders on the left and right wheels of the robot and also this function sets the standby pin to output mode. This pin is used to enable/disable the motor driver.The
ledcAttachPin
functions attach each of the four LEDC channels to a specific pin on the Arduino. These pins are used to output the PWM signals to the left and right motors.The
lastStateL
andlastStateR
variables are initialized with the initial state of the encoder signals for the left and right wheels, respectively.The
attachInterrupt
functions attach two interrupt service routines (updateEncoder_L
andupdateEncoder_R
) to the encoder pins for the left and right wheels. These routines are called whenever the state of the encoder signals changes (i.e., when the wheel rotates). They are used to update the encoder counts and calculate the speed of the wheels.
void publish_encoder_data()
{
encoder_msg_left.data = encoderValue_L;
left_enc_pub.publish(&encoder_msg_left);
encoder_msg_right.data = encoderValue_R;
right_enc_pub.publish(&encoder_msg_right);
encoder_msg_left_error.data = rpmL_error;
left_enc_error.publish(&encoder_msg_left_error);
encoder_msg_right_error.data = rpmR_error;
right_enc_error.publish(&encoder_msg_right_error);
}
The function publish_encoder_data()
is used to publish the encoder values and any associated errors to their respective ROS topics.
void updateEncoder_L(){
int LMSB = digitalRead(encoderLPin1);
int LLSB = digitalRead(encoderLPin2); //LSB = least significant bit
int Lencoded = (LMSB << 1) |LLSB; //converting the 2 pin value to single number
int Lsum = (lastEncoded_L << 2) | Lencoded; //adding it to the previous encoded value
if(Lsum == 0b1101 || Lsum == 0b0100 || Lsum == 0b0010 || Lsum == 0b1011) encoderValue_L ++;
if(Lsum == 0b1110 || Lsum == 0b0111 || Lsum == 0b0001 || Lsum == 0b1000) encoderValue_L --;
lastEncoded_L = Lencoded; //store this value for next time
}
The Lencoded value is then combined with the previous encoded value of the left motor using the
bitwise OR operator (|)
and stored in the Lsum variable.The function then checks the value of Lsum against a set of four possible values (0b1101, 0b0100, 0b0010, 0b1011) and increments the
encoderValue_L
variable if it matches any of them. Similarly, if Lsum matches one of the four possible values (0b1110, 0b0111, 0b0001, 0b1000), the function decrements theencoderValue_L
variable.Finally, the current encoded value (Lencoded) is stored in the
lastEncoded_L
variable for use in the next iteration of the function.