## Vex Note: How a single flywheel ball shooter minimizes the effect of ball mass variations

May 28, 2015

Nothing but Net 2015/2016 competition game involves shooting 4 inch balls that can have a 10% variation in mass.    We know that trajectory range ,R = V^2/g*sin(2*theta) so it  is dependent upon the square of the ball release speed , V, and shooter elevation, theta.   Mass does not enter into the equation unless it affects V.

Ball release energy :

Suppose we use a Vex 5″ diameter wheel as a flywheel and rotate it a w_wheel angular speed.      As the ball leaves the shooter, it will have a V = r_wheel*w_wheel/2.  e.g. half of the flywheel tangential speed.    The ball will have a spin rate , w_ball = V/r_ball.    The energy of the ball, E_b , is the sum of the ball translational energy and rotational energy.

E_b = 1/2*m_ball*V^2 + 1/2*I_ball*w_ball^2

where I_ball = 2/5*m_ball*r_ball^2 (solid sphere of uniform density).

so Eb =  1/2*m_ball*V^2( 1+2/5)  .   (corrected 5/29 Was 1/2*m_ball*V^2( 1+4/5)  So the rotational energy adds  40% more to the translational energy.  Rewriting in terms of w_ball gives

E_b = .7*m_ball*w_ball^2*r_ball^2

Wheel Energy:

E_wheel = .5*I_wheel*w_wheel^2.  where

I_wheel = m_wheel*(r_wheel*.84)^2  (ref blog post https://vamfun.wordpress.com/2015/05/17/finding-the-moment-of-inertia-of-a-vex-wheel-using-parallel-axis-theorem/)

Energy Conservation:

E_wheel_initial = E_wheel_final + E_ball     This assumes that the wheel is not being powered by the motor during launch and that the extra energy needed for the ball comes from the flywheel.   Also, friction and ball compression energy losses are assumed zero to simplify this analysis but can be significant in actual percentages derived.   I am focusing  on how increasing flywheel mass lowers the percentage range errors caused by ball mass variations.

E_wheel_initial/E_wheel_final = (1 + E_ball/E_wheel_final)

Lets expand E_ball/E_wheel_final

E_ball/E_wheel_final = (.7*m_ball*w_ball^2*r_ball^2)/(.5*I_wheel*w_wheel_final^2)

= 1.4*m_ball*w_ball^2*r_ball^2/(m_wheel*r_wheel^2*.84^2*(2*w_ball*r_ball/r_wheel)^2)

= .4954*m_ball/m_wheel

SInce  m_ball = 60 g and m_wheel = 180 g   m

_ball/m_wheel = 1/3

So  E_ball/E_wheel_final = .165    for a single 5″  wheel flywheel     .165/n for n flywheels.    So the ball energy is almost equal to the 1/6 final energy of the wheel

Range Tolerance analysis:

So how does R vary with m_ball from all this.   Well , we know the range is proportional to V^2 which is proportional to w_wheel_final^2 which is proportional to E_wheel_final.

From above E_wheel_final = E_wheel_initial/(1+ .4954*m_ball/m_wheel)

So due to proportionality of R and E_wheel_final we can say

R/R_0 = ((1+ .4954*m_ball_0/m_wheel)/(1+ .4954*m_ball/m_wheel))

where R_0 and m_ball_0 are the nominal values without errors.

We can use R range= R_0(1+ %e_r)   and m_ball = m_ball_0*(1 + %e_m_ball) to work with % changes.

Then with some manipulation we can get %e_r as a function of %e_m_ball

%e_r  = -%e_m_ball/(2.02*m_wheel/m_ball_0 +1 + %e_m_ball)

Now m_wheel = n*.180 kg   and m_ball= .06 kg  so we can write an approx.

%e_r = -%e_m_ball /( n*6.06 +1)     where n is the number of 5″ vex wheels.

Lets put in a few numbers:

Assume %e_m_ball = 10%  then the range error is

n = 1, %e_r =  -1.42%

n = 2, %e_r =  -.76%

n = 3, %e_r =  -.52%

n = 4, %e_r =  -.40%

n = 5, %e_r =  -.32%

So you see the benefits of having a higher  flywheel mass to ball mass ratio.   The use of  two 5″ wheels in a single wheel design can reduce a potential 10% range error from ball mass variations  to  1% ( less than a ball radius).   To keep the spin up time to a reasonable number of seconds requires about 2 393 motors per wheel so 2 wheels costs 4 motors.   So there is a motor tradeoff to get that  higher accuracy with heavier flywheels.

## Finding the moment of inertia of a Vex wheel using parallel axis theorem

May 17, 2015

The new Vex game “nothing but net” might involve rotating shooter wheels.  We know that if all the mass of a wheel was located on its rim then the moment of inertia about its rotating axis  (I_rim) would be

I_rim = r^2 * m   where m is the mass of the wheel and r = radius of wheel.   But we know that the wheels actually  have mass that is unevenly distributed along the radius so the moment of inertia I_wheel will be less than I_rim.

Easy experiment to determine I_wheel if we know its mass.

We can determine I_wheel experimentally using the parallel axis theorem and the dynamics of a pendulum.

Parallel axis theorem says that any object that is rotated about an axis parallel to and a distance , d, from an axis going through the centroid of the object will add an amount =  m*d^2 to the moment of inertia about its centroid.  I.e.

I_parallel = I_centroid + m*d^2 .

Suppose we now swing the mass, m,  about the parallel axis like a pendulum  using just the torque from gravity pulling on the mass.      It is easy to show that the period, T , of the pendulum is related to the distance , d, and the moment of inertial , I_parallel, by the following formula:

T = 2*pi*sqrt(I_parallel/(d*m*g))     .   g is gravitational constant and assumes swing angles smaller than say 10 degs from the lowest point on the pendulum path.

If we measure the period of the pendulum we can rearrange the equation and find I_parallel

I_parallel = T^2*d*m*g/(2*pi)^2

Once we have I_parallel, we can now use the parallel axis theorem to determine I_wheel.

I_wheel = I_parallel –  d^2*m  =  d^2*m * (T^2*g/d/(2*pi)^2 -1)

(This assumes  that the string has negligible mass relative to the mass of the wheel)

Vex 5 in Wheel experiment:

Given….r_wheel = 2.5 inches ,

wheel mass,   m = 180 gm (0.180  kg)

The pendulum is created by suspending the wheel with a thread 2.75 inches from its center so

d =. 07 m (approx. 2.75 inches)

The average period  T = .668 sec

I_wheel  = d^2*m*(T^2/d*9.8/(6.28)^2 -1)

= d^2*m*( .248*T^2/d -1)

= .07^2*.180*(.248*.668^2/.07 -1) = 0.00051 kg m^2

Equivalent radius with a rim only mass r_e

r_e = sqrt( I_wheel/m) = .0533 m ( 2.1 inches)

This  means that the wheel behaves as if the mass if located at 84 %  of the radius of the wheel which one could almost guess by looking at it.

## Getting my feet wet with Arduino Uno

July 18, 2013

Arduino Uno

I have tried to stay away from Arduino mainly because I didn’t want to learn a whole new culture. However, my AlgalitaROV project uses the OPENROV electronic architecture which employs a Cape that uses the Arduino Uno processor which in turn attaches to a BeagleBone Black(rats…another processor culture to learn).
Downloaded and installed the Arduino SDK 1.0.5 from arduino.cc and read through the getting started and reviewed the types of commands it uses. I bought a Arduino Uno starter kit from amazon (\$32) which has a breadboard and some jumper wires. plugged in the Arduino Uno and it installed automatically without updating the drivers as suggested in the instructions. First observations:

1) the general purpose I/O (GPIO) are 5 volt at the breakouts. This is great since it is compatible with Vex parts. Current is o limited to 40ma per pin.

2) it can be powered from the USB cable or an external supply that must range from 6v to 20v with a recommendation of 7v to 12v.

3) Software wise in the Arduino you write a void setup() function and a void loop() function. These functions are called automatically by the operating system. setup() runs once and the loop() runs continuously…meaning the hidden main() function contains a while(true){loop()} structure that runs after the setup() runs. By contrast the Vex RobotC template calls a function pre_autonomous() once and executes separate tasks autonomous() and usercontrol(). usercontrol contains an explicit while(true){} which the programmer can change. Not sure that Arduino gives us that capability.

3)There are plenty of software examples and the language is close to C. The only function that seemed misnamed was analogWrite(pin,duty). This doesn’t write an analog output to a d/a hardware as one might assume but puts a 5 volt PWM signal output on a PWM capable GPIO pins. On the Uno 6 of the 14 GPIO pins are PWM capable (3,5,6,9,10,11). Not sure why they didn’t just call it PWMWrite().

4)Servo library is available for use but be careful with servo.write(int val).

Here is the function code from the servo library.  Note that if val is >544 then the command is assumed to be in microseconds rather than servo degrees.  Also note if it is less than 544 that the degree values are truncated to valid servo range of [0,180].    So a val = 255 will produce a 180 degree command.

void Servo::write(int value)
{
if(value < MIN_PULSE_WIDTH)
{  // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if(value < 0) value = 0;
if(value > 180) value = 180;
value = map(value, 0, 180, SERVO_MIN(),  SERVO_MAX());
}
this->writeMicroseconds(value);
}

First Script.
We need an r/c brushless motor driver. The ESC needs a standard servo drive signal. So I hooked up a Vex pot to the board and read its value [0, 1023] and scaled it to [0,180] which is given to a canned servo program object which has a servo.write which generates the proper servo output to a specified pin.  A motor is a continuous rotation servo  so 0 value represents max reverse speed and 180 value gives max forward speed.   I also included a serial printout of the value to the laptop console.
Hardware Setup:
[click on picture to expand to full size]

Shows breadboard wiring , motor 7.2v battery and external board 5 volt power supply

It is important to note that the motor is powered by a separate battery since it draws more current than the board can supply.

Closeup of arduino wiring

Full test setup

Mymotorcontrol.ino

```// Controlling a servo/motor position using a potentiometer (variable resistor)
// by Chris Siegert:  vamfun@yahoo.com   https://vamfun.wordpress.com
// adapted from  Michal Rinott servo code
// connect the center pin of a potentiometer (pot) to the potpin.  Connect the other two pins to the arduino 5v and ground pins.
// connect the white wire of the motor pwm cable to the servopin.
// Important!! Connect the red and black wires to an external motor power source.
// The arduino is not designed to deliver enough current to drive a servo/motor.
#include <Servo.h>

Servo myservo;  // create servo object to control a servo or motor.
int servopin = 9; //connects servo to pin 9 which is a pwm pin.
int potpin = 0;  // analog pin A0 used to connect the potentiometer
int val;    // variable to read the value from the analog pin
int cmd = 0; // cmd to motor [0 to 180]
int cnt = 0; // program cycle counter
int cnt_max = 33;   // this is the number of delay cycles between serial printouts. (15ms per cnt) 33 counts gives about 2 per second)
void setup()
{
Serial.begin(9600);   //start up the serial data port at 9600 baud
myservo.attach(servopin);  // attaches the servo on servopin number to the servo object
}

void loop()
{
val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
cmd = map(val, 0, 1023, 0, 180);     // scale it in degrees of servo rotation(value between 0 and 180)

myservo.write(cmd);                  // sets the servo position according to the scaled value in deg
cnt++;
if(cnt > cnt_max)                  // this sets time between serial print outs to cnt_max cycles  or about (15 ms*cnt_max)
{
Serial.println(cmd);
cnt = 0;      // debug value
}
delay(15);                           // waits for the servo to get there
}```

## Note: Using a Line Sensor to Update Gyro Heading

February 28, 2013

The programming challenge for the 2013 Sack Attack game was attempted by team 1508 LancerBots fully autonomous robot. It uses gyro information to generate a navigation solution and then automatically sequences through several way points to solve the route sequences. Unfortunately as mentioned in earlier posts, the gyro drift causes heading corruption which then causes sacks to by slightly missed. One possible solution I am proposing is to use line sensors to update the gyro.
Figure 1 shows the geometry and formulas required to accomplish the update for a special case when the line is parallel to the truth x axis.    The coordinates used by 1508 were specifically chosen so all lines were parallel to either the x or y  axis.  This simplifies the update equations.

Simply put… when a line sensor event occurs, note the position error  with respect to the line (using the Nav coordinates) and divide it by the range from the origin.    This ratio is the gyro drift error in radians.

Error Contributions:

Errors in the update equation can stem from errors in  the Nav initial condition (<.25 in, 1 deg heading) , encoder scaling (typically <1%) , encoder resolution(< .03 in) , line location measurements (<.25 in), line tape width (<.5 in) and Navigation solution numerical errors (sampling, round off).

The dominant error is the encoder scaling which can add up when the encoder has moved several hundred inches.   Lines can also be use to update the Nav  position solution so that these  errors remain less than 1% distance  from the field origin and not the total distance traveled by an encoder.   This error translates to about .6 deg of heading error from a gyro update.    So we should not expect much better than that from our updates.

General Case: Lines skew to the coordinate axes

To complete this note,  lets consider a more general line that is described by

c = a*x + b*y

where a,b and c are constants and again x and y are truth coordinates.   Now we have three unknowns (x,y and delta) and three equations:

x’ = x*cos(delta) + y*sin(delta)

y’ = -x*sin(delta) + y*cos(delta)

c = a*x + b*y

First we solve for x and y from the first two equations which is a simple inverse:

x = x’*cos(delta) – y’*sin(delta)

y = x’*sin(delta) + y’*cos(delta)

Make the small angle substitution gives

x = x’ – y’*delta

y = x’*delta + y’

Now substitute x and y into the line equation

c = a*(x’ – y’*delta) + b*(x’*delta + y’)

Now solve for delta

c -a*x’ – b*y’ = (b*x’ – a*y’)* delta

or

delta = (c -a*x’ – b*y’ )/(b*x’ – a*y’)

Check the special case above :  y = c, a = 0, b = 1

delta = (y – y’)/(x’)  : checks ok

## 1508 LancerBots reach world top 40 in drive skills at Robodox skills challenge

February 26, 2013

Funny thing happened on the way to qualify for worlds in the programming challenge… the robot  won the Robodox driver challenge instead with our programmer Gevorg as the driver.  Go figure.   Lancerbots brought three robots to the competition  but only one of them was working so the programming robot did double duty as both driver and programming entry.   The drive skill score was 205 which puts it in the top 40 world rankings but you need to be in the top 30 to qualify.  Being in the top 5 of the California robots qualifies it for the California State Championships on March 16th in Santa Clara near San Jose.

I helped the kids construct a solid programming robot that was very close to being qualified for worlds…except for a pesky sack that caused the robot to not complete its route. (robot video)   The robot is a very efficent spatula robot that can pick up and dump a load of 16 sacks over its back.   It is designed with encoders  , line sensors and gyro sensors that are used to provide full navigation ( two axis position and speed as well as  heading).   The line sensors are used to update the navigation solution.

The field geometry is coded by 4 way points  which are at the intersection of  the crossing white lines used for line tracking.   The waypoints  are used to automatically steer toward using a waypoint tracker algorithm that nulls cross track distance and has heading inner loop.   It makes the programming simple and straight forward and works great so long as the gyro doesn’t drift too much.   The gyro is used to generate heading as a compass would.   We know it is not a great sensor to use as a compass because it does drift at about 6 deg/min which is enough to mess you up on the last legs of the route.   But we thought we would give it a try since it is a random phenomonon and sometimes it works great..if you are lucky.       We have some ideas to make the compass heading more reliable by using  a gyro rate deadzone and also blending the gyro with additional encoder data.

I think the robot is capable of competing at the world class level and probably could score 250 points (pending compass problem fixes and optimization).   The world record currently stands at 185 points.   Had it completed its route on Saturday, the score would have matched the current world record.  Woulda shoulda coulda…frustrating to put in hours of work and have a darn sack trip you up.

I will publish the software at a future date.   It uses four tasks: Navigation, System Control, Feedback Control and Task Control.   The User and Autonomous functions generate engage commands for automatic functions and provide  relavent parameters.

As an example:   Suppose we want to track a line crossing through a waypoint.   We simply set the waypoint number (a waypoint has a position and heading) , engage the tracker and use a “move until” distance function that stops the robot when it has reached the desired point along the track.   The lateral tracking is done automatically.   Any virtual line on the field can be tracked independent of the white lines given to the programmer to use.

Relavent posts:

Note: Using a line sensor to update gyro heading

Waypoint steering geometry for a mobile robot

Navigation update equations for a two wheeled robot

## Waypoint steering geometry for a mobile robot

February 5, 2013

Fig 1 shows the geometry that I will use in the waypoint steering algorithms that will be discussed in future posts.  The field geometry is North (N) along the y-axis and East (E) along the x-axis.   The heading angle , psi is defined positive clockwise from North as a compass rose.

Waypoint:   The waypoint is defined with both location (X_p, Y_p) and direction psi_p.   The slope of the center track line m is  1/tan(psi_p).

Cross track and Along track Ranges:

The two parameters of interest are the along track range R_y and cross track range , R_x.   The steering is determined by R_x = R*sin(delta_psi) where delta_psi is the angle between a line drawn from the robot to the waypoint and the actual track line.

Derivation of R_x  and  R_y without sin and cos functions:

We know that the track can be expressed as a line that goes through (X_p,Y_p) and has a slope m.   So we can write the track line as  y= mx + y_0 form but we need y_0.    Plugging in for point p gives  y_0  = Y_p – m*X_p .

Hence the line eq  is   0 =  -y +m*x + Y_p – m*X_p.

It can be shown that the distance R_x  between a point  (x_r, y_r)  and a line  a*x + b*y  + c  = 0  is

|R_x|= | (a*x_r+b*y_r +c)|/sqrt(a^2 + b^2)    (see  wikipedia)

where a = m ,  b= -1 ,  c= Y_p – m*X_p ,    m  = 1/tan(psi_p)

This form can lead to division by zero when psi_p = 0 but can be avoided by using the tan(90 – psi_p)  = 1/ m  .  We  divide the starting equation

0 =  -y +m*x + Y_p – m*X_p

by m   to change its form and use it whenever m >1 or psi_p > 45 degrees.

0 = -y/m + x + Y_p/m – X_p.

Now we have new definitions of a,b,c

a = 1, b = -1 /m, c = Y_p/m – X_p  , 1/m = tan(90 – psi_p).

R_y derivation

We can use a similar method to find R_y.

|R_y| =  |(a’*x_r+b’*y_r +c’)|/sqrt(a’^2 + b’^2) )

where we use the perpendicular line to the track passing  through (X_r,Y_r) with slope  m’ =-1/m and the point as (X_p,Y_p).    This leads to

a’ = -1  , b’ = m’ , c’ = Y_r  – m’*X_r  , m’ = -1/m = -tan(psi_p)  .  We use this when psi_p  < 45 degrees and the modified form

a’ = m , b’ = 1 , c’ = -Y_r*m – X_r    for psi_p > 45 degrees.

Making R_x and R_y signed values

By convention, I want displacement to the right as positive R_x.  (X_r,Y_r) will be to the right of the track if  0< delta_psi  < 180 otherwise we change the sign of R_x.

Similarly, we want the along track distance, R_y,  to be positive if we are heading in the direction of the waypoint along the track and we have not reached the waypoint. This occurs when  0<90 – delta_psi < 180 otherwise R_y is negative.

## smart_PTC_monitor beta code release

August 31, 2012

Ok, I’ve got the RobotC code used in my smart_PTC_monitor developed to a point where I would let others play with it.   I originally used a single timed iterative loop that ran in the same task as  autonomous and user modes.  I decided to create a separate task that simplifies the user interface so normal programming can occur without any of my constraints.  When done, the user functions are easily inserted into my template to seamlessly add the PTC monitor protection capability.    The program is self documented with liberal commenting but I am sure people will have a lot of questions.   I am putting it out without fully testing all the functions to get early user feedback and if it proves to have utility, I will put out a more mature version that includes user feedback.

Below is a copy of the introduction comments in the program:

//*************************************************************************************************************** // smart_PTC_monitor_template.beta.8.27.2012.c   Rev 0

// This program is an open source beta version of a competition template for Sack Attack.  It adds a task // called smart_PTC_monitor which uses current and PTC temperature models to manage a current_limiter function // which can keep hardware PTC fuses in the motors,cortex and power expander from ever tripping.

// Program Author: Chris Siegert aka Vamfun on the Vex forums. // see my blog: vamfun.wordpress.com  for model details and vex forum threads on subject // email: vamfun@yahoo.com // Mentor for team 599 Robodox and team 1508 Lancer Bots

// Teams are authorized to freely use this program , however, it is requested that improvements or additions be // shared with the Vex community via the vex forum.  Please acknowledge my work when appropriate.  Thanks

// Scope and limitations: // Program assumes that servo currents are zero.  If servo position is known, then currents can be modeled. // Testing has been limited to 393 motors and 3wire motors, however, the program handles  269 motors. // Periodic updates to the models will be made and posted on the Vex forum as more testing is done. // Program handles the Power Expander PTC when the ports are entered with provided #defines // All other motor ports are automatically configured to calculate the correct currents for each PTC

// Basic Instructions: // Write your program as you normally would.  When done, put your autonomous code in place of my_autonomous() // and your user code in place of my_user().  Then do a find and replace to change all the “motor” functions to // “motor_input” i.e.  motor[Left_motor] –> motor_input[Left_motor].

// Put all your encoder speed calculations into  void compute_speeds() function and assign speeds to M[port].speed variable. // You can read these speeds from the global array whenever you need them.  This loop runs at about 100ms update rate.

// Use a #define or switch to create a // PTC_monitor_engage boolean and set true to engage the monitor.

// Tell the program which ports are used by the Power Expander as shown in the example below: // #define PE_CH1  UNUSED // if used put port number …. i.e. PE_CH1  port1  else put the #define UNUSED

// #define PE_CH2  Right_drive_motor  //use setup names

// #define PE_CH3  port3  //use port name

// #define PE_CH4  1  // use integer = to port number -1.  This is motor port2

// Initialize the PTC temperatures using these #defines: // #define T_0_DEG_F  (72.) //Set robot ambient temperature here.  If you are in a hot gym…this might be 85 deg

// #define T_M  (100.) //100 deg C =Setpoint temperature for the PTC current monitor.

// Motor currents and PTC temperature data are held in a global state matrix M[] which is a structured array that contains // the motor PTC/current data in the first 10 elements (index 0 to 9) and the non motor PTC’s data in the next three elements. // M[10] , M[11] and M[12] pertain to the cortex1_5,cortex6_10 and power expander PTC states respectively.

// Program uses two update rates: The current_limiter updates at PTC_TASK_DELAY_MS which is 15ms // and the temperature calculations are set to run at about 6 times {PTC_TASK_DELAY_MS + subtasks delays) ~= 100ms. //****************************************************************************************************************