dead reckoning program by spiked3.com

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
Post Reply
flatino
Posts: 2
Joined: 05 Oct 2012, 20:02

dead reckoning program by spiked3.com

Post by flatino »

Hi, i'm trying to run with ROBOC 3.51 a very interesting program of dead reckoning published by Mikep on his blog http://www.spiked3.com/?p=410#comment-185:
#pragma config(Sensor, S2, COMPASS, sensorI2CCustom9V)
#pragma config(Motor, motorB, LEFT, tmotorNormal, PIDControl, encoder)
#pragma config(Motor, motorC, RIGHT, tmotorNormal, PIDControl, encoder)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//

// Xander's driver suite
#include "hitechnic-compass.h"

//**********************************************************//
//* *//
//* PoseNXC - LEGO NXT Robotics with Pose *//
//* *//
//**********************************************************//

#define __POSE_DEBUG__
#include "pose.h"

// shorthand for the typing lazy
intrinsic void _T(const string sFormatString, ...)
asm(opcdStringOps, strOpDebugStreamFormat, variableRefString(sFormatString), varArgList);

intrinsic void _TL(const string sFormatString, ...)
asm(opcdStringOps, strOpDebugStreamFormatWithNewLine, variableRefString(sFormatString), varArgList);

task DisplayPose()
{
while (true)
{
nxtDisplayTextLine(3, "# Pose@ %d", PoseClock);
nxtDisplayTextLine(4, "#-x,y %1.1f, %1.1f", PoseX, PoseY);
nxtDisplayTextLine(5, "#-hdg %d", PoseHdg);
nxtDisplayTextLine(6, "#-spd %1.1f", PoseVelocity);
wait1Msec(500);
}
}

void ShowPose(string t)
{
#ifdef _DEBUG
_TL("-%s", t);
_TL("--x,y %1.1f, %1.1f", PoseX, PoseY);
_TL("--hdg %d, %d", PoseHdg, HTMCreadRelativeHeading(COMPASS));
#endif
}

//**********************************************************//
//* *//
//* Main task *//
//* *//
//**********************************************************//

task main()
{
eraseDisplay();
nxtDisplayCenteredBigTextLine(0, "PoseNXT1");
_TL("");
_TL("***PoseNXT1");

time1[T1] = 0;

// should help to actually measure the tire, LEGO specs it at 81.6
// (float wheelDiameter, float wheelBase, float finalGearRatio, tMotor left, tMotor right, TSynchedMotors useForSynch, int movePower, int turnPower, int updateRate = 5)
PoseStartTask(81.6, 120.0, (float)(16/16), LEFT, RIGHT, synchBC, 50, 30);

StartTask(DisplayPose);
HTMCsetTarget(COMPASS);
PlaySound(soundBeepBeep);

// PilotMove(250.0);
// wait1Msec(500);
// PilotMove(-250.0);

// a lap done with moves and turns
for (int i = 0; i < 4; i++)
{
ShowPose("*move");
PilotMove(200.0);
PilotWaitDrivesIdle();
ShowPose("#move");

// simple
// PilotTurn(90);

// using corrected Turn
// PilotTurn(PilotQuickestTurnTo(PoseHdg, (i+1)*90));

// using TurnTo (which will internally correct)
// correct PoseHdg before we turn if compass available (will work with or without)
PoseHdg = PilotHdg360(HTMCreadRelativeHeading(COMPASS));
PilotTurnTo((i+1)*90);

wait1Msec(50); // give it as little time to update Pose
ShowPose("#turn");
}

// another lap done with GoTo
// PilotGoTo(0.0, 200.0);
// PilotGoTo(200.0, 200.0);
// PilotGoTo(200.0, 0.0);
// PilotGoTo(0.0, 0.0);
// PilotTurnTo(0);

PlaySound(soundBeepBeep);

bFloatDuringInactiveMotorPWM = true;
motor[LEFT] = 0;
motor[RIGHT] = 0;

ShowPose("final");
StopTask(PoseUpdate);

while (bSoundActive)
wait1Msec(100);

_TL("###PoseNXT");

while(true)
EndTimeSlice(); // use dark grey button to exit
}

The program was written for a previous version of ROBOTC and mikep kindly modified the library pose.h in this way to work under 3.5 version:

/changes
// 9/12/12 - update to work with robotc 3.5

bool _hasBeenInitialized = false;

// geometry info

float _wheelDiameter; // in some global unit
float _finalGearRatio; // generally spur / pinion
float _wheelBase;
int _PoseUpdateRate; // times per second
int _movePower, _turnPower;
tMotor _left, _right;
TSynchedMotors _useForSynch;

float _wheelTravelPerRevolution;
int _ticksPerWheelRevolution;
float _wheelBaseDiameter;
int _ticksForFullPilotTurn;

// Global Pose Variables
long PoseClock = 0; /*!< time (in ticks) the last update occurred */
short PoseHdg = 0; /*!< current heading in degrees */
float PoseX = 0.0, /*!< current X location */
PoseY = 0.0, /*!< current Y location */
PoseVelocity; /*!< current velocity */

task PoseUpdate();

/*!
* Initialize geomtery variables, Performs one time calculations, and starts the task PoseUpdate().
* All measurements must be in the same units, angles are in degrees. The example uses MM.
* @param wheelDiameter wheel diameter
* @param wheelBase wheel base
* @param finalGearRatio usually calculated as spur (the gear on the wheel) / pinion (the gear on the motor)
* @param left the motor that is driving the left wheel
* @param right the motor that is driving the right wheel
* @param useForSynch the syncMode to use for robotc, typically synchBC
* @param movePower the power to apply for a straight line move
* @param turnPower the power to apply when rotating to a new heading
* @param updateRate times per second the pose should be updated, the default is 5
*/
void PoseStartTask(float wheelDiameter, float wheelBase, float finalGearRatio, tMotor left, tMotor right, TSynchedMotors useForSynch, int movePower, int turnPower, int updateRate = 5)
{
_wheelDiameter = wheelDiameter;
_wheelBase = wheelBase;
_finalGearRatio = finalGearRatio;
_useForSynch = useForSynch;
_movePower = movePower;
_turnPower = turnPower;
_PoseUpdateRate = updateRate; // times per second
//_CompassInterval = compassInterval;
_left = left;
_right = right;

// one time calculated values
_wheelTravelPerRevolution = _wheelDiameter * PI;
_ticksPerWheelRevolution = 360 * _finalGearRatio;
_wheelBaseDiameter = _wheelBase * PI;
_ticksForFullPilotTurn = _wheelBaseDiameter * _ticksPerWheelRevolution / _wheelTravelPerRevolution;

#ifdef __POSE_DEBUG__
writeDebugStreamLine("PoseStartTask");
writeDebugStreamLine("wd %1.1f", _wheelDiameter);
writeDebugStreamLine("wb %1.1f", _wheelBase);
writeDebugStreamLine("fgr %1.1f", _finalGearRatio);

writeDebugStreamLine("wtpr %1.1f", _wheelTravelPerRevolution);
writeDebugStreamLine("tpwr %d", _ticksPerWheelRevolution);
writeDebugStreamLine("wbd %1.1f", _wheelBaseDiameter);
writeDebugStreamLine("tfft %d", _ticksForFullPilotTurn);
#endif

_hasBeenInitialized = true;
StartTask(PoseUpdate);
}

void PoseException()
{
hogCPU();
eraseDisplay();
PlaySound(soundException);
nxtDisplayCenteredTextLine(0, "Missing call to");
nxtDisplayCenteredTextLine(1, "PoseStartTask");
nxtDisplayCenteredTextLine(2, "Program aborted");
writeDebugStreamLine("Missing call to");
writeDebugStreamLine("PoseStartTask");
writeDebugStreamLine("Program aborted");
wait1Msec(10000);
StopAllTasks();
}

/*!
* This task is called by the NXT OS and will update the global pose variables to their current value.
* PoseStartTask() must be called before this task is started, and is automatically initially started by it.
* This task may be stopped and restarted by the user, and it will re-initialize Pose information.
*/
task PoseUpdate()
{
long lastEncoderLeft = 0;
long lastEncoderRight = 0;
long nowEncoderLeft;
long nowEncoderRight;
float leftDistance;
float rightDistance;
float poseTheta = 0.0;
float distance;
float xChange, yChange;
long deltaLeft, deltaRight;

if (!_hasBeenInitialized)
PoseException();

nSchedulePriority = 10; // we are pretty important

PoseX = 0.0;
PoseY = 0.0;
PoseHdg = 0;
PoseVelocity = 0.0;
nSyncedMotors = synchNone; // so we can reset both encoders
nMotorEncoder[_left] = 0;
nMotorEncoder[_right] = 0;
nSyncedMotors = _useForSynch; // back to 'normal' mode

while (true)
{
long elapsedTime;

hogCPU();
long nowTime = time1[T1];
elapsedTime = nowTime - PoseClock;
PoseClock = nowTime;

nowEncoderLeft = nMotorEncoder[_left];
nowEncoderRight = nMotorEncoder[_right];

deltaLeft = nowEncoderLeft - lastEncoderLeft;
deltaRight = nowEncoderRight - lastEncoderRight;

leftDistance = deltaLeft * _wheelTravelPerRevolution / (float)_ticksPerWheelRevolution;
rightDistance = deltaRight * _wheelTravelPerRevolution / (float)_ticksPerWheelRevolution;

distance = (leftDistance + rightDistance) / 2.0;
PoseVelocity = distance / elapsedTime / 1000;

//float poseTheta1 = MSIMUreadGyroZAxis(AIMU)/ 100.0; // using IMU gyro in radians
float poseTheta2 = ((leftDistance - rightDistance ) / _wheelBase); // using odemetry, in radians
poseTheta += poseTheta2;

// these (trig functions) are reversed from normal thinking,
// compass direction of 0 indicates North = a movement up the Y axis
xChange = distance * sin(poseTheta);
yChange = distance * cos(poseTheta);

PoseX += xChange;
PoseY += yChange;
PoseHdg = poseTheta * 180.0 / PI; // in degrees

lastEncoderLeft = nowEncoderLeft;
lastEncoderRight = nowEncoderRight;

releaseCPU();
wait1Msec(1000 / _PoseUpdateRate);
}
}

void PilotChangePower(int movePower, int turnPower)
{
_movePower = movePower;
_turnPower = turnPower;
}

void PilotChangePower(int movePower)
{
_movePower = movePower;
}

int PilotHdg360(int degrees)
{
while (degrees < 0)
degrees += 360;
return degrees % 360;
}

int PilotHdg180(int degrees)
{
degrees = PilotHdg360(degrees);
return degrees > 180 ? degrees - 360: degrees;
}

int PilotQuickestTurnTo(int hdgNow, int hdgNew)
{
hdgNow = PilotHdg360(hdgNow);
hdgNew = PilotHdg360(hdgNew);
if (hdgNow < hdgNew)
hdgNow += 360;
int left = hdgNow - hdgNew;
return (left < 181 ? -left : 360 - left);
}

void PilotWaitDrivesIdle()
{
if (!_hasBeenInitialized)
PoseException();

wait1Msec(20);
bool done = false;
while(!done)
{
done = (nMotorRunState[_left] == runStateIdle && nMotorRunState[_right] == runStateIdle);
EndTimeSlice();
}
wait1Msec(20);
}

void PilotMoveAsync(float distance)
{
long ticks;
if (!_hasBeenInitialized)
PoseException();

ticks = abs(distance * (float)_ticksPerWheelRevolution / _wheelTravelPerRevolution);

#ifdef __POSE_DEBUG__
writeDebugStreamLine("PilotMove:ticks %d", ticks);
#endif

nSyncedTurnRatio = 100;
nSyncedMotors = _useForSynch;
nMotorEncoderTarget[_left] = ticks;
motor[_left] = _movePower * sgn(distance);
}

void PilotTurnAsync(int degrees)
{
// this function is sensitive to which motor pairs we are using and in their order
// degrees may be flipped for BC or BA

long delta;

if (!_hasBeenInitialized)
PoseException();

// test this before uncommenting
// if (_useForSynch == synchBA || _useForSynch == synchCA || _useForSynch == synchCB)
// degrees = -degrees; ??

delta = (degrees * _ticksForFullPilotTurn / 360.0);

#ifdef __POSE_DEBUG__
writeDebugStreamLine("PilotTurn:%d", degrees);
writeDebugStreamLine(" LRe %d %d", nMotorEncoder[_left], nMotorEncoder[_right]);
writeDebugStreamLine(" ticks %d", delta);
#endif

nSyncedMotors = _useForSynch;
nSyncedTurnRatio = -100; // always turn opposite

nMotorEncoderTarget[_left] = abs(delta);
motor[_left] = _turnPower * sgn(delta);
}

void PilotTurnToAsync(int heading)
{
if (!_hasBeenInitialized)
PoseException();
PilotTurnAsync(PilotQuickestTurnTo(PoseHdg, heading));
}

void PilotGoToAsync(float x, float y)
{
float distance, hdgRadians;
int hdg;

distance = sqrt( (PoseX - x) * (PoseX - x) + (PoseY - y) * (PoseY - y) );
hdgRadians = atan2((y - PoseY), (x - PoseX)); // relative to 0,0
hdg = (int)(hdgRadians * 180.0 / PI);

#ifdef __POSE_DEBUG__
writeDebugStreamLine("GoTo: %1.1f, %1.1f", x, y);
writeDebugStreamLine(" frm: %1.1f, %1.1f", PoseX, PoseY);
writeDebugStreamLine(" hdgR: %1.1f", hdgRadians);
writeDebugStreamLine("dst hdg: %1.1f, %d", distance, hdg);
#endif

PilotTurnToAsync(hdg);
PilotWaitDrivesIdle(); //go to wait before we start moving
PilotMoveAsync(distance);
}

void PilotMove(float distance)
{
PilotMoveAsync(distance);
PilotWaitDrivesIdle();
}

void PilotTurn(int degrees)
{
PilotTurnAsync(degrees);
PilotWaitDrivesIdle();
}

void PilotTurnTo(int heading)
{
PilotTurnToAsync(heading);
PilotWaitDrivesIdle();
}

void PilotGoTo(float x, float y)
{
PilotGoToAsync(x,y);
PilotWaitDrivesIdle();
}

I tryed to run the program but i received these errors:

**Error**:Undefined variable 'strOpDebugStreamFormat'. 'short' assumed.
**Error**:Undefined variable 'varArgList'. 'short' assumed.
**Error**:Undefined variable 'strOpDebugStreamFormatWithNewLine'. 'short' assumed.
**Error**:Calling procedure 'ShowPose'. 'const' expressions does not fit. Parameter: 'string & t'. Expression: '"*move"'. Type: 'char *'
**Error**:Calling procedure 'ShowPose'. 'const' expressions does not fit. Parameter: 'string & t'. Expression: '"#move"'. Type: 'char *'
**Error**:Calling procedure 'ShowPose'. 'const' expressions does not fit. Parameter: 'string & t'. Expression: '"#turn"'. Type: 'char *'
**Error**:Calling procedure 'ShowPose'. 'const' expressions does not fit. Parameter: 'string & t'. Expression: '"final"'. Type: 'char *'

Can you help me to fix the problem?
I'd like to test my robot!!

Thank you in advance
flatino
inxt-generation
Posts: 290
Joined: 03 Oct 2011, 00:06
Location: Gallifrey
Contact:

Re: dead reckoning program by spiked3.com

Post by inxt-generation »

Hi flatino,

This is probably best asked on the RobotC forums [LINK], as only a few people are using/are experienced with RobotC here.

P.S. In the future, please use the

Code: Select all

[code]
[/code] tags for code, as it preserves the spacing.
A.K.A. NeXT-Generation.
"A kingdom of heaven for RobotC now has recursion!"
flatino
Posts: 2
Joined: 05 Oct 2012, 20:02

Re: dead reckoning program by spiked3.com

Post by flatino »

hi inxt-generation,
thank you for the answer. I'll post it in the right place
sorry for my errors
flatino
Post Reply

Who is online

Users browsing this forum: No registered users and 13 guests