Project Update 5: Python script running .wav file

The team was able to succesfully use the PyAudio python library in order to play a .wav file out loud. The reason this is important is because the group wants the rover to have some sort of feedback, whether that be auditory, visual, or preferably both. This python script enables the group to provide auditory feedback to persons in the vicinity of the rover. Here is a link to the PyAudio API documentation: https://people.csail.mit.edu/hubert/pyaudio/

Below shows the audio file called “test2.wav” as well as the python code used to play it out loud.

test2.wav

PyAudio Python code

#!usr/bin/env python  
#coding=utf-8  

import pyaudio  
import wave  

#define stream chunk   
chunk = 1024  

#open a wav format music  
f = wave.open("test2.wav","rb")  
#instantiate PyAudio  
p = pyaudio.PyAudio()  
#open stream  
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),  
                channels = f.getnchannels(),  
                rate = f.getframerate(),  
                output = True)  
#read data  
data = f.readframes(chunk)  

#play stream  
while data:  
    stream.write(data)  
    data = f.readframes(chunk)  

#stop stream  
stream.stop_stream()  
stream.close()  

#close PyAudio  
p.terminate() 


Project Update 4: Raspberry Pi 4 to Arduino Mega Serial Communication

Figure 1: Raspberry Pi and Arduino Mega Serial Communication via USB

The group was able to send messages between the Raspberry Pi 4 and Arduino Mega via serial communication. A python script running on the Pi accepts a number from the command line and sends it to the Mega using a popular Python library for sending serial information called PySerial. The Mega then increments the number by 1 and sends it back to the Raspberry Pi which will display the new number to the terminal.

The serial.Serial(…) command on line 3 opens serial communication on port /dev/ttyACM0 because the Mega was connected to port /dev/ttyACM0 on the Pi. Notice how the baud rate on the Pi must match the baud rate on the Mega (115,200 Hz).

The terminal shows the result of running the Python code after uploading the Arduino .ino file to the Mega.

Python Code

import serial
import time
arduino = serial.Serial(port='/dev/ttyACM0', baudrate=115200, timeout=.1)
def write_read(x):
    arduino.write(bytes(x, 'utf-8'))
    time.sleep(0.05)
    data = arduino.readline()
    return data
while True:
    num = input("Enter a number: ") # Taking input from user
    value = write_read(num)
    print(value) # printing the value

Arduino Code

int x;

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(1);
}

void loop() {
  while (!Serial.available());
  x = Serial.readString().toInt();
  Serial.print(x + 1);
}

Running PySerial in Raspberry Pi Terminal

Project Update 3: Simple PID Controller

Figure 1: Motor with Encoder

The group was able to implement a simple digital PID controller on the Arduino to precisely control the position of a motor with encoder. A function of time representing the desired motor encoder counts (blue) is inputted into the PID controller. The actual rotation of the motor in encoder counts (red) closely aligns with the desired position indicating that the the tuning parameters for the proportional, integral, and derivative terms are appropriate. In the two examples shown below, Kp = 2.0, Ki = 0.02, and Kd = 0.2.

Figure 2: PID Test 1-Simple Sine Wave
Figure 3: PID Test 2-Two Sine Waves Overlapped

For the rest of this specific post, I will be referring to motors with encoders as just motors. This does not necessarily apply for other posts.

The motors are being programmed on the Arduino which is a C++/C based language. In software, the motors were packaged in a Motor class to hold all the important parameters about a motor with encoder. The header file for the class is shown below. If you want a more detailed look at the code go here: https://github.com/bohrm1/Arduino-Motor-Control/tree/main/MotorEncoder_main .

class Motor 
{
  private:
    int PWM;          //creating member variables to describe motor with encoder
    int In1;
    int In2;
    int ActualPos = 0; 
    int Dir;

    int Kp = 0;       //constants for PID controller internal to class
    int Ki = 0;
    int Kd = 0;

    long prevT = 0;
    float eprev = 0;
    float eintegral = 0;
    
  public:
    Motor(void);
    void CreateMotor(int pwm, int in1, int in2);

    void SetMotor(int target, int kp, int ki, int kd);
    void Drive(int dir, int pwr);
    void SetPos(int pos);
    int GetPos(void);
};