Project Update 7: Details on Motor Steering and Motor Rotating

The group created functions called DriveRover and RotateRover that could handle all of the processes and math that go into steering and rotating the rover. Essentially, they are functions used for multi-motor control. These functions accept four MotorNoEncoder objects to be passed in, one for each motor, and will generate the proper control and PWM signals for all four motors depending on the user input.

The diagram below shows the physical manifestations of the DriveRover function. Besides the motor objects that were instantiated from our MotorNoEncoder class, it also accepts a power and direction (dir) input to dictate both dictate the direction in which the motor will drive.

Below shows the basic functionality of both the DriveRover and RotateRover function.

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);
};

Project Update 2: Hardware Schematics Version 1

Three schematics were developed, a schematic for the onboard robot, for the onboard power station, and for the Raspberry Pi 4 workstation. Two schematics were developed for the onboard robot–one for a robot with 2 motors with encoders and another with 4 motors without encoders. This is because the group has not finalized the mechanical design of the chassis yet.

Besides the motors, other important components include the servos which we intend on using to create an automatically open enclosure for medical supplies, cameras to be used for the raspberry pi, and temperature and humidity sensors. We intend on using an Arduino Mega for motor and sensor control.