Shape-Changing Rotacaster Flexi-Bot
The Shape-Changing Rotacaster Flexi-Bot acts like a Chameleon, but instead of changing colour, it can morphs into a variety of different leg configurations. The front and rear pairs of arms are controlled as a pairs change the configuration of the Rotacaster Omni-wheels relative to the Robots body. Each Rotacaster Omni-wheel is driven individually via a Small Lego Power Functions Motor. The Arm pairs are driven individually by a pair of Lego Mindstorms NXT Servo Motors.
The home position for the arms is controlled via a set of 4x Lego Mindstorms RCX type Touch Sensors before the position of the NXT Servo Motors is set. The Power Function Motors are controlled via a Hitechnic Infra-red Link Sensor and 2x Lego Power Function Infra-red receivers. The Robot is controlled via a Sony PlayStation2 Controller interfaced to a Mindsensor PSP-Nx-v3: Sony PlayStation2 Controller interface for the NXT.
Lego Mindstorms NXT Rotacaster Flexi-Bot in Action!
I was forced to make a few minor changes between the Robot in the Video and the Photographs to accommodate the size of the stage. I was forced to change the gear ratio by a factor of 1:3 for the drive to the Rotacasters instead of the pictured direct-drive. This was primarily to slow it down so I was able to keep it on the mat.
The other change was to move the Battery Box for the PowerFunction Motors, from under the NXT to beside it, to aid in ease of battery changing.
The Flexi-Bot does work on carpet, but due to the weight of the Robot it bogs down somewhat. Also the Rotacasters don't have the surface area to ensure good tracking with the wheels off-set from each other. Larger Rotacasters would solve this issue I feel. But, most Robot designs tend to be somewhat lighter than this example. My post: Rotacaster Omni-wheels in Action! preforms very well on my 100% wool carpet.
All-in-all, I'm very happy with the Flexi-Bot results. For it to preform at it's best it needs a large floor space of at least 5m X 5m. The Rotacasters are at their best on polished wooden or Vinyl floor coverings, which I lack in a large enough scale to allow me too enjoy all the fun the Robot offers.
NXC Source Code:
/* ===================================================
***********************************
****** Rotacaster Flexi Bot ******
***********************************
=================================================== */
#define PS2 S1 // Port Number
#define F_Touch S2 // Port Number
#define R_Touch S3 // Port Number
#define PF_CTL S4 // Port Number
#define ADDR 0x02
#define Deg2Rot 360
#define FrontSW SENSOR_2
#define RearSW SENSOR_3
#include "PSP-Nx-lib.nxc"
const byte PlayStation = PS2;
const int Degrees = (Deg2Rot * 1);
int Position, MovePosition, PositionFront, PositionRear, Direction;
/* ===================================================
Check & Display Sensors State
=================================================== */
task DisplayData()
{
ClearScreen();
while (true)
{
TextOut(0, LCD_LINE1, "Front Sw = ");
NumOut(80, LCD_LINE1, FrontSW);
TextOut(0, LCD_LINE2, "Rear Sw = ");
NumOut(80, LCD_LINE2, RearSW);
TextOut(0, LCD_LINE3, "Position = ");
NumOut(75, LCD_LINE3, Position);
TextOut(0, LCD_LINE4, "Direction = ");
NumOut(75, LCD_LINE4, Direction);
TextOut(0, LCD_LINE7, "PosF ");
NumOut(30, LCD_LINE7, PositionFront);
TextOut(50, LCD_LINE7, "PosR ");
NumOut(80, LCD_LINE7, PositionRear);
Wait (50);
}
}
/* ===================================================
Initilize the Robot
=================================================== */
void Initilize()
{
OnFwd(OUT_AB, 75);
Wait(750);
Off(OUT_AB);
do
{
OnRev(OUT_A, 100);
Wait (50);
}
while (RearSW != true)
Off(OUT_A);
Wait(100);
ResetTachoCount(OUT_A);
do
{
OnRev(OUT_B, 100);
Wait (50);
}
while (FrontSW != true)
Off(OUT_AB);
Wait(100);
PlayTone(1400, 100);
PositionFront = 0; PositionRear = 0;
}
/* ===================================================
Move All Robot Legs
=================================================== */
void Legs(float Angle)
{
if (PositionFront == PositionRear)
{
MovePosition = 0 - PositionRear + Angle;
if (MovePosition == 0 ) { return; }
if ( sign (MovePosition) == -1) { Direction = -100; } else Direction = 100;
Position = abs(MovePosition *100);
OnFwd(OUT_AB, Direction);
RotateMotor(OUT_AB, Direction, Position);
Off(OUT_AB);
PositionRear = Angle;
PositionFront = Angle;
PlayTone(500, 100);
return;
}
PlayTone(750, 100);
TextOut(0, LCD_LINE1, "Angel= ");
NumOut(50, LCD_LINE1, Angle);
MovePosition = 0 - PositionRear + Angle;
if (MovePosition == 0 ) { return; }
if ( sign (MovePosition) == -1) { Direction = -100; } else Direction = 100;
Position = abs(MovePosition *100);
OnFwd(OUT_A, Direction);
RotateMotor(OUT_A, Direction, Position);
Off(OUT_A);
PositionRear = Angle;
PlayTone(500, 100);
MovePosition = 0 - PositionFront + Angle;
if (MovePosition == 0 ) { return; }
if ( sign (MovePosition) == -1) { Direction = -100; } else Direction = 100;
Position = abs(MovePosition *100);
OnFwd(OUT_B, Direction);
RotateMotor(OUT_B, Direction, Position);
Off(OUT_B);
PositionFront = Angle;
PlayTone(500, 200);
}
/* ===================================================
Move Robot Front Legs 'F'
=================================================== */
void LegsF(float Angle)
{
PlayTone(750, 100);
MovePosition = 0 - PositionFront + Angle;
if (MovePosition == 0 ) { return; }
if ( sign (MovePosition) == -1) { Direction = -100; } else Direction = 100;
Position = abs(MovePosition *100);
OnFwd(OUT_B, Direction);
RotateMotor(OUT_B, Direction, Position);
Off(OUT_B);
PositionFront = Angle;
PlayTone(500, 100);
}
/* ===================================================
Move Robot Rear Legs'R'
=================================================== */
void LegsR(float Angle)
{
PlayTone(750, 100);
MovePosition = 0 - PositionRear + Angle;
if (MovePosition == 0 ) { return; }
if ( sign (MovePosition) == -1) { Direction = -100; } else Direction = 100;
Position = abs(MovePosition *100);
OnFwd(OUT_A, Direction);
RotateMotor(OUT_A, Direction, Position);
Off(OUT_A);
PositionRear = Angle;
PlayTone(500, 100);
}
/* ===================================================
Main Tasks
=================================================== */
task main()
{
ResetSensor(F_Touch);
ResetSensor(R_Touch);
SetSensorLowspeed(PS2);
SetSensor(F_Touch, SENSOR_TOUCH);
SetSensor(R_Touch, SENSOR_TOUCH);
SetSensorMode(F_Touch, IN_MODE_BOOLEAN);
SetSensorMode(R_Touch, IN_MODE_BOOLEAN);
ClearSensor(R_Touch);
ClearSensor(F_Touch);
SetSensorLowspeed(PF_CTL);
Wait (10);
psp currState;
start DisplayData;
RotateMotor(OUT_AB, 100, 360);
Off(OUT_AB);
Initilize();
/*--------------------------------------
PS2 Controller button layout:
----------------------------------------
L1 R1
L2 R2
d triang
a c square circle
b cross
l_j_b r_j_b
l_j_x r_j_x
l_j_y r_j_y
-------------------------------------- */
/*
bits as follows:
b1: a b c d x r_j_b l_j_b x
b2: square cross circle triang R1 L1 R2 L2
*/
while (true)
{
Off(OUT_AB);
PSP_ReadButtonState(PlayStation, ADDR, currState);
if (currState.square != true) { Legs(90); }
if (currState.cross != true) { Legs(45); }
if (currState.triang != true) { Legs(135); }
if (currState.circle != true) { Legs(0); }
if (currState.l1 != true) { LegsF(45); }
if (currState.r1 != true) { LegsR(45); }
if (currState.l2 != true) { LegsF(135); }
if (currState.r2 != true) { LegsR(135); }
if (currState.d != true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_REV, PF_CMD_REV); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_FWD, PF_CMD_FWD);
if (currState.d == true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_STOP, PF_CMD_STOP); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_STOP, PF_CMD_STOP); }}
if (currState.b != true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_FWD, PF_CMD_FWD); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_REV, PF_CMD_REV);
if (currState.b == true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_STOP, PF_CMD_STOP); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_STOP, PF_CMD_STOP); } }
if (currState.a != true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_REV, PF_CMD_FWD); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_FWD, PF_CMD_REV);
if (currState.a == true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_STOP, PF_CMD_STOP); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_STOP, PF_CMD_STOP); } }
if (currState.c != true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_FWD, PF_CMD_REV); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_REV, PF_CMD_FWD);
if (currState.c == true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_STOP, PF_CMD_STOP); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_STOP, PF_CMD_STOP); } }
if (currState.l_j_b != true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_REV, PF_CMD_REV); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_REV, PF_CMD_REV);
if (currState.l_j_b == true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_STOP, PF_CMD_STOP); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_STOP, PF_CMD_STOP); } }
if (currState.r_j_b != true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_FWD, PF_CMD_FWD); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_FWD, PF_CMD_FWD);
if (currState.r_j_b == true) { HTPFComboDirect(PF_CTL, PF_CHANNEL_1, PF_CMD_STOP, PF_CMD_STOP); HTPFComboDirect(PF_CTL, PF_CHANNEL_2, PF_CMD_STOP, PF_CMD_STOP); } }
Wait (50);
}
}
loading...
loading...

Download PDF format














