Ayush Chakraborty, Evan Lockwood, Allyson Hur, Krishna Suresh
Nov. 28th 2022
We obtained one of the FunRobo cars to use for our project, specifically an Axial SCX10 II RC Car. We first implemented a basic test of the Servo and ESC controls on an Arduino to provide a proof of concept for our hardware control interface. Above is our first test with driving the car programmatically. This is the wiring diagram for the FunRobo car, excluding unnecessary parts for the project.
In order to interface with the physical robot from an external computer and drive the sensors on the robot, we chose to use a Raspberry Pi 4B. On the Raspberry Pi, we are running ROS 2 Foxy on a Ubuntu 20.04 Server Operating System. Additionally, the Raspberry Pi is configured to connect to a mobile hotspot on startup. This was chosen for the networking strategy due to communication issues that were encountered when attempting to communicate over Olin’s Wifi networks via ROS 2.
While having a ROS interface to command the robot is effective over the network, we decided to implement an object oriented structure to abstract the high level control systems and low level hardware code. Above is an overview of our class structure with the majority of the functionality contained within the Robot class. We plan to use a Drive class to capture the low level control of the hardware and provide interfaces to either the teleop or motion planning controller to direct the robot. This Robot object instance will live within a high level controller which is used to communicate between the high level ROS commands sent by a user and the mid level information such as waypoints.
As a first test of our system integration, we chose to implement a simple teleoperation ROS node to command the robot from a remote controller (laptop). To start, we created a custom ROS message, DriveCommand, that would contain the desired steering angle and linear speed. On the laptop, we created a SendDriveCommand node that would listen to the user’s keyboard and send drive commands based on the inputted key. The speed was set to a constant 0.5 m/s and the direction was based on the key. For example, “q” would correspond to a steering angle of 0.349 radians, where 0 radians is defined as straight. These drive commands would be sent to the ReceiveTeleopNode running on the Raspberry Pi.
Within the ReceiveTeleopNode there are two key functionalities: receiving new drive commands and interfacing with the Robot class to process drive commands. Whenever a new drive command is received, the current drive command stored by the ReceiveTeleopNode is updated. Additionally, there is a run_loop() function that runs every 0.05 seconds that updates the robot’s current drive speed and steering angle. When the steering angle is updated, the robot class dictates the PWM update to the servo, triggering the change in steering angle. Similarly, when the drive speed is updated, the robot class dictates the update to the PWM wave being sent to the ESC. This allows for almost instantaneous updates to the robot’s driving state from a remote controller.
Once we were able to set pin PWM values on the Raspberry Pi, we shifted focus to properly controlling the ESC (Electronic Speed Controller) and Servo position. For the ESC we found that a special initialization sequence is required to inform the ESC what our target PWM signal range will be between. For instance, on our platform, we implemented an ESC calibration script to set the minimum and maximum PWM duty time as 1000 and 2000 microseconds respectively. Next, we added an arming command to allow the ESC to be enabled after a power cycle. Since we are using a bidirectional ESC, the stop command for the controller is at 1500 microseconds and the forward and backward controls are higher or lower signals.
However, this is only the raw signal we are sending to the ESC and isn’t controlling the true forward velocity of the car. To adjust our signal, we needed to find a function which converts meters per second commands to a PWM output. We first found a rough estimate of this conversion by using the motor specifications, output gear ratio and wheel size to convert between max motor speed and max forward velocity. Next, we used this conversion to drive the robot 1 meter forward and adjust the estimated max motor RPM to best match the true max.
For the Servo, we needed to find a correlation between rotation angle and microseconds of the PWM signal. To do so, we adjusted the input signal to perform a 90 degree rotation and used this change in PWM signal to compute our relationship between target angle and output signal.