Sunday 26 January 2020

RC Car Steering with PWM and more about Servos

At the end of https://madsmaddad.blogspot.com/2019/07/rc-car-number-3.html I mentioned that I was going to try this. I said that I had binned CAr #2, but it was actually car #1, and #2 was in a box hidden away. This post is about car #2.

After proving that I could use a Raspberry Pi to drive a Servo, I decided to change out the motor drive steering of this car for a servo and adjust the software accordingly to drive it.   The initial video that explained it all was at https://www.youtube.com/watch?v=N5QmZ92uvUo and he explains teh concepts behind PWM control with it. A simpler explanation is at https://www.youtube.com/watch?v=xHDT4CwjUQE

I have got it working but have not yet taken it out on the road because the R-Pi is sitting beside the car like a heart monitor.


Here is the servo in position for steering car I drilled a hole in the steering arm for the servo arm to go through, rather than trying anything fancy like rods as usually seen in RC airplane controls.  The Servo is stuck in place courtesy of my hot glue gun. At the top right of the picture is the original steering motor just pushed out of place. 



Raspberry Pi Model B connected to the Car. All of the pins connected to the second row of the GPIO except for a yellow ground pin.
Pin 2  +5v to Servo Black wire
Pin 6   gnd to Servo Reddish wire
pin 12 to  IC socket pin 11
Pin 16 to IC socket pin 10
Pin 18  PWM to Servo Yellow wire
Pin 9   gnd to IC socket pin 2 (gnd)

See this previous writeup for the IC pinouts on the control board. https://madsmaddad.blogspot.com/2018/03/second-rc-car.html




This shows the IC socket replacing the receiver IC on the driver board. The black connector card connects all the driver outputs to the relevant motor and also brings in the power for the board from the battery pack at the bottom of the picture.

SOFTWARE

This uses  the Flask setup with the Wifi setup as an Access Point so that I can work direct to it from my tablet.

There are three programs required.

Shell script:  Incorporate this in rc.local to make it run at startup,
export FLASK_APP=/home/pi/rc-car/app.py
flask run --host=192.168.1.8

Set IP address to correct address for the Access Point setup.

HTML:

<!DOCTYPE html>

<! developed using https://www.w3schools.com/css/css_grid.asp for the grid 30 Jan2019

<html>
<head>
<title>RC-Car with Flask & PWM steering 20-1-2020</title>
<style>
.grid-container {
  display: grid;
  grid-template-columns: auto auto auto auto;
  background-color: #ffffff;
  padding: 10px;
  grid-column-gap: 20px;
  grid-row-gap: 50px;
}
.grid-item {
  background-color: rgba(255, 255, 255, 0.8);
  border: 3px solid rgba(0, 0, 0, 0.8);
  padding: 20px;
  font-size: 50px;
  text-align: center;
}
</style>
</head>
<body>

<h1 align="center">RC-Car with Flask & PWM 20-1-2020</h1>


<div class="grid-container">
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item">
    <a href="/motor-forwards/" data-toggle="tooltip" title="Forward" class="btn btn-success">Forward</a>
    </div>
   <div class="grid-item"></div>

  <div class="grid-item">
    <a href="/motor-left/" data-toggle="tooltip" title="Left-Left-Left!" class="btn btn-success">Turn Left</a>
    </div>
    <div class="grid-item">
    <a href="/turn-center/" data-toggle="tooltip" title="Left-Left-Left!" class="btn btn-success">Center</a>
    </div>
  <div class="grid-item">
    <a href="/motor-stop/" data-toggle="tooltip" title="Stop Motors"  class="btn btn-danger">STOP</a>
    </div>
  <div class="grid-item">
     <a href="/motor-right/" data-toggle="tooltip" title="Turn right!" class="btn btn-success">Turn Right</a>
    </div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item">
    <a href="/motor-backwards/" data-toggle="tooltip" title="Reverse!"  class="btn btn-warning">Backward</a>
    </div>
  <div class="grid-item"></div>
</div>

</body>
</html>


Note that I have used W3Schools for a lot of help in getting my HTML correct. Some of the bits in each line referencing the contents of a box are possibly redundant. They were there in the code where I pinched the stuff.  [ see below for simplified stuff].

PYTHON:

# 2020-1-20 Modifications to drive steering using a servo and PWM.  Because I
# don't know if gpiozero and RPi.GPIO can work together I'll remove the GPIOzero and motor
# command.  motor = Motor(forward=12, backward=16)
# look at ancient code for motor handling.
#  2018-04-05 Modified from Les Pounder program to handle two motors
# one for steering and one for motion
# steering is Left = 10, right = 11
# changing it trying to add Turn for motor control
# 2018-10-31 changing toggle LED to stop motors

from flask import Flask, render_template
from time import sleep
import RPi.GPIO as GPIO

#Set GPIO Numbering mode

GPIO.setmode(GPIO.BOARD)

# set pins for motor control

GPIO.setup(12,GPIO.OUT)
GPIO.setup(16,GPIO.OUT)

# set pin 18 as Output for Servo Steering
GPIO.setup(18,GPIO.OUT)
servo_st = GPIO.PWM(18,50)

#start PWM running on servo, init value 0 (pulse off)
servo_st.start(0)
# servo runs from duty cycle 2 to duty cycle 12, 7 being central position  for servo used in youtube demo.
# define variable duty
duty = 2

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/motor-stop/')
def on():
    GPIO.output(12,False)
    GPIO.output(16,False)
    return render_template('index.html')

@app.route('/motor-forwards/')
def motorforwards():
    GPIO.output(12,True)
    GPIO.output(16,False)
    return render_template('index.html')

@app.route('/motor-backwards/')
def motorbackwards():
    GPIO.output(12,False)
    GPIO.output(16,True)
    return render_template('index.html')

@app.route('/motor-left/')
def motorleft():
    duty = 2
    servo_st.start(duty)
    sleep(1.3)
    servo_st.ChangeDutyCycle(0)
    return render_template('index.html')

@app.route('/turn-center/')
def centersteering():
    duty = 7
    servo_st.start(duty)
    sleep(0.3)
    servo_st.ChangeDutyCycle(0)
    return render_template('index.html')

@app.route('/motor-right/')
def motorright():
    duty = 15
    servo_st.start(duty)
    sleep(0.3)
    servo_st.ChangeDutyCycle(0)
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')


The major changes in this, other than PWM operation, is the change to GPIO Board numbering rather than GPIO Name numbering.  Also I stopped using GPIOzero, so have reverted to direct control of pins in the software. I like this better. Comments can be used to explain functions that are not clear.


Questions: I am happy to answer them, but they may be already answered in previous posts.

27/1/2020  corrections and simplifications
The  line
 <a href="/motor-forwards/" data-toggle="tooltip" title="Forward" class="btn btn-success">Forward</a>

can be simplified by removing things that don't serve any purpose in this case. It becomes:
 <a href="/motor-forwards/" >Forward</a>


SERVOS

I was given a box of Servos and after having problems with the one that I had put in the car, I went through them plugging them into the Raspberry Pi.

Four of them totally didn't work and caused the R-Pi to shut down.  These were all small ones without labels.

Some of them partially worked.

Here is a breakdown of what happened. The software is set to duty cycle 2 for a Left turn, 7 for a centre position, and 15 for a right turn. I noticed that in some cases the servo shaft turned CCW when I expected CW, and am now confused as to which is left and right.

Device                                               Left               Centre           Right
small unit with black arm.                   x                     ?                    ?

Small unit with white arm                  -90                    0                 +90 (CW)

Digifleet FPS-20                                 -60                    0                 +60

Digifleet FPS-30   dead kills Pi.

Aristocraft HS-100                            -90                increments              increments
'increments' possibly means that I have to extend the range. needs testing

GWS Mini STD                                +90                    0                  -90

Tower Pro Airplane 99                            iffy, slow to respond

Small Black with arm                       +110             no response         -100

Black, short wires                            +110                                          -90

Digifleet FPS33 (2)       dead

Black with black arm.           dead

Powermax Skyranger 5 white-X arm      +75                steps                           -70

Steps/increments probably means that I have to expand the range from 2-7-15.

Another bothersome feature of these servos is that the arms, or whatever the proper term for them is, are different sizes and shapes so are not transferrable from one unit to another. Most are splined, but some are square.

2020-02-08  See https://en.wikipedia.org/wiki/Servo_control

It is not duty cycle that is important, it is pulse width, generally between 1msec to 2 msec wide.
Now I am using a value of duty 2-7-12  with a pulse rate of 50 Hertz.


Also:
https://learn.adafruit.com/adafruit-raspberry-pi-lesson-9-controlling-a-dc-motor/software

and

https://github.com/sarfata/pi-blaster








No comments: