Third order curve for position, second order for velocity, linear acceleration. We usually go one better, and try to minimize jerk over the whole journey.
Acceleration/Deceleration is continuous
The result is a fourth order curve in position, third order in velocity, which is what you try to achieve when you drive.
The idea is that the person who programmed acceleration/deceleration into the train was lazy, so there's probably one basic function used over and over again
We are trying x(t) as a fourth order polynomial in t.
It is easiest to express the polynomial in terms of y = ( t-t1 )/(t2 - t1). Why?
Then write
and use the equations above to solve for the five parameters in terms of t1. Then, you need only measure t1 to know the relevant kinematic functions.
We discussed how to measure t1 in the second step.
You test the measured values by
When you have the disagreement which is, by definition non-zero, but which may be measured as zero, you have to decide the cause:
Have fun.
We all, even most programmers (!), have effective intuitions about human relations
Tasks are independent entities
Why do servers need attendant tasks?
Proprietor `owns' a service, which usually means a resource.
Kernel is handling hardware in this example
Receive( &serverTid, eventId ); Reply( serverTid, ... );
FOREVER { data = AwaitEvent( eventid ); // data includes event type and volatile data switch( data.event-type ) { case RCV_INT: Send( serverTid, {NOT_RCV, data.byte}, ... ); break; case XMT_INT: // test transmitter, turn interrupt off and on? Send( serverTid, {NOT_XMIT}, byte ); // byte is to be transmitted store( UART..., byte ) break; default: ASSERT( "This never happens because our kernel is bug-free." ); }
// queues & fifos notifierPid = Create( notifier ); //Should notifier code name be hard coded? Send( notifierTid, MyTid( ), ... ); //On return notifier is known to be okay RegisterAs( ); //On return requests can begin.
FOREVER { requesterTid = Receive( request, {request-type, data} ); switch ( request-type ) { case NOT_RCV: Reply( requesterTid, ... ); enqueue( rcvfifo, data ); if ( ! empty( rcvQ ) ) Reply( dequeue( rcvQ ), dequeue( rcvfifo ) ); break; case NOT_XMIT: enqueue( xmitQ, requesterTid ); if ( ! empty( xmitfifo ) ) Reply( dequeue( xmitQ ), dequeue( xmitfifo ) ); break; case CLIENT_RCV: enqueue( rcvQ, requesterTid ); if ( !empty( rcvfifo ) Reply( dequeue( rcvQ ), dequeue( rcvfifo ) ); break; case CLIENT_XMIT: Reply( requesterTid, ... ); enqueue ( xmitfifo, data ); if ( ! empty( xmitQ ) ) Reply( dequeue( xmitQ ), dequeue( xmitfifo ) ); break; default: ASSERT( "Never executed because notifiers and clients are bug-free." ) } }
Simplest is best
Receive( &courierTid, ... ); Reply( courierTid, ... );
FOREVER { Receive( &courierTid, byte ); load( UART..., byte ) data = AwaitEvent( eventid ); Reply( courierTid, NOT_XMIT, ); }
Receive( &serverTid, notifierTid ); Send( notifierTid, ... ); Reply( serverTid );
FOREVER { Send( notifierTid, {data} ); Send( serverTid, {req}, {data} ); }
// queues & fifos notifierTid = Create( notifier ); courierTid = Create( courier ); Send( courierTid, notifierTid, ... ); // On return courier & notifier are known to be okay RegisterAs( ); //On return client requests will begin.
FOREVER { requesterTid = Receive( request, {request-type, data} ); switch ( request-type ) { case NOT_XMIT: enqueue( requesterTid, xmitQ ) if ( ! empty( xmitFifo ) ) Reply( dequeue( xmitQ ), dequeue( xmitFifo ) ); break; case CLIENT_XMIT: Reply( requesterTid, ... ); enqueue ( xmitFifo, data ); if ( ! empty( xmitQ ) ) Reply( dequeue( xmitQ ), dequeue( xmitFifo ) ); break; default: ASSERT( "..." ); } }
This gets you through a bottleneck where no more than two events come too fast.
Remember that all the calls provide error returns. You can/should use them for error recovery
Another possible arrangement for task creation
Another possible arrangement for initialization
Distributed gating
I am showing you collections of tasks implemented together because sets of related tasks is a level of organization above the individual task.
E.g., the decision to add a courier requires revision of code within the group, but not outside it.
Return to: