Ich arbeite gerade an einer Kameraslider-Motorisierung mittels Touchscreen und NEMA17+A4988 Stepper System. Ich verlinke ganz unten die bisherigen Threads zu diversen Fragen zum Projekt.
Hier der komplette Sketch in der aktuellen Fassung V2.0:
/* Slider Control V2 for 3.5" Parallel TFT-tft Shield Display with Adafruit_GFX
// Original by Mega-Testberichte.de - Marco Kleine-Albers
// Variant for Adafruit TFT & Moba Tools by gregorurabl.at - Gregor Urabl
//1,8°, 360/1,8 = 200
//200 steps is a full turn in fullstep mode
//use microstepping for smoother motion. see later in code
Standard TFT tft Pin Mappings:
*pin usage as follow:
* tft_CS tft_CD tft_WR tft_RD tft_RST SD_SS SD_DI SD_DO SD_SCK
* Arduino Uno A3 A2 A1 A0 A4 10 11 12 13
*Arduino Mega2560 A3 A2 A1 A0 A4 10 11 12 13
* tft_D0 tft_D1 tft_D2 tft_D3 tft_D4 tft_D5 tft_D6 tft_D7
* Arduino Uno 8 9 2 3 4 5 6 7
*Arduino Mega2560 8 9 2 3 4 5 6 7
*Remember to set the pins to suit your display module!
*/
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // tft Library
#include <TouchScreen.h> // Touchscreen Library
#include <MCUFRIEND_kbv.h> // Touchscreen Hardware-specific library
#include <MobaTools.h> // Motor Control Library
// Colors
#define BLACK 0x0000
#define WHITE 0xFFFF
#define RED 0xF800
#define GREEN 0x07E0
#define BLUE 0x001F
#define ORANGE 0xFD20
#define DARKCYAN 0x03EF
#define DARKGREY 0x7BEF
#define LIGHTGREY 0xC618
//debug/msg
int x, y;
String msg="";
char text_buffer[80];
//////////////////////////////////
// Screen Setup
//////////////////////////////////
#define tft_CS A3 // Chip Select goes to Analog 3
#define tft_CD A2 // Command/Data goes to Analog 2
#define tft_WR A1 // tft Write goes to Analog 1
#define tft_RD A0 // tft Read gies to Analog 0
#define tft_RESET A4 // Can alternately just connect to Arduino's reset pin
// define pins for resistive touchscreen
#define YP A1 // must be an analog pin, use "an" notation!
#define XM A2 // must be an analog pin, use "an" notation!
#define YM 7 // can be a digital pin
#define XP 6 // can be a digital pin
// define touchscreen pressure points
#define MINPRESSURE 10
#define MAXPRESSURE 1000
// Define touchscreen parameters
// Use test sketch to refine if necessary
#define TS_MINX 930
#define TS_MAXX 130
#define TS_MINY 200
#define TS_MAXY 970
#define STATUS_X 10
#define STATUS_Y 65
MCUFRIEND_kbv tft; // Define object for TFT display
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); // Define object for touchscreen / Last parameter is X-Y resistance, measure or use 300 if unsure
//////////////////////////////////
// Motor Setup
//////////////////////////////////
//motor pins
int ENABLE_PIN = 23;
int STEP_PIN = 25;
int DIR_PIN = 27;
int stepsPerRev = 3200; // 360°/1.8° = 200 Steps x 16 Microsteppint = 3200 Microsteps/Rev
//microstepping Pins M1 =A8, M2=A9, M3=A10
//TABELLE, Abschnitt Software: https://www.mega-testberichte.de/testbericht/einen-kameraslider-motorisieren-arduino-a4988-steppermotor-touchdisplay-do-it-yourself
//pin mappings
int M1 = A8;
int M2 = A9;
int M3 = A10;
MoToStepper stepper (stepsPerRev, STEPDIR);
MoToTimer stepperPause; // Pause between stepper moves
short motorDirection = -1; // clockwise
//--basic values for movement
int speed_set = 70;
int raise_speed_by = 70;
int speed_max = 1400;
int distance_set = 5000;
int raise_distance_by = 1000;
int ramp_set = 0;
short ramp_steps_by = 100;
bool return_to_home = true;
bool manual_start_or_stop = true; // true == start, false = stop
//--needed for timelapse, buttons
int time_set = 0; // millisec
short raise_time_by = 100;
int time_max = 30000; // 30sec. For longer Delays change time_set & time_max in Code and increase data type to long. EG 900.000 = 15min
//--subdivisions for timelapse
int steps_set = 2; // Divider for Stops. So minimum drive half of the distance, stop, wait for delay, drive to end. Distnace between stops is distance_set/steps_set
short steps_max = 3200; // REPLACE ME WITH MAX STEPS BASED ON SLIDER LENGTH
short raise_steps_by = 1; //raised by steps
//--slider length in steps
long slider_length = 455000;
//////////////////////////////////
// Draw UI
//////////////////////////////////
char buttonRadius = 10;
char buttonHeight = 60;
char buttonSpacing = 10;
uint16_t smallButtonWidth = 147;
uint16_t bigButtonWidth = 303;
// Define button array object
Adafruit_GFX_Button buttons[10];
void drawButtons() {
// Create Buttons - initButton would create a Button from x and y coordinates in it's center. initButtonUL uses the top left corner
buttons[0].initButtonUL(&tft, buttonSpacing, buttonSpacing, bigButtonWidth, buttonHeight, WHITE, DARKCYAN, WHITE, "NORMAL", 3); // NORMAL Button
int speed_percentage = speed_set/14;
int_to_string(speed_percentage, text_buffer);
sprintf(text_buffer,"%s%s",text_buffer,"%");
buttons[1].initButtonUL(&tft, bigButtonWidth+2*buttonSpacing, buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, text_buffer, 3); // SPEED Button (set number)
buttons[2].initButtonUL(&tft, buttonSpacing, buttonHeight+2*buttonSpacing, bigButtonWidth, buttonHeight, WHITE, RED, WHITE, "MANUAL", 3); // MANUAL Button
int_to_string(distance_set, text_buffer);
buttons[3].initButtonUL(&tft, bigButtonWidth+2*buttonSpacing, 1*buttonHeight+2*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, text_buffer, 3); // DIST Button (set number)
buttons[4].initButtonUL(&tft, buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, "<-->", 3); // RETURN Button
buttons[5].initButtonUL(&tft, smallButtonWidth+2*buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE,">>" , 3); // DIRECTION Button
int_to_string(ramp_set, text_buffer);
buttons[6].initButtonUL(&tft, 2*smallButtonWidth+3*buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, text_buffer, 3);// RAMP Button (set number)
buttons[7].initButtonUL(&tft, buttonSpacing, 3*buttonHeight+4*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, ORANGE, WHITE, "TIMELAP", 3);// TIMELAPSE START Button
int_to_string(time_set*1000, text_buffer);
buttons[8].initButtonUL(&tft, smallButtonWidth+2*buttonSpacing, 3*buttonHeight+4*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, ORANGE, WHITE, text_buffer, 3);// DELAY Button (set number)
int_to_string(steps_set, text_buffer);
buttons[9].initButtonUL(&tft, 2*smallButtonWidth+3*buttonSpacing, 3*buttonHeight+4*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, ORANGE, WHITE, text_buffer, 3); // STEPS Button (set number)
// Draw Buttons
for(uint8_t buttonCounter = 0; buttonCounter <= 9; buttonCounter++)
{
buttons[buttonCounter].drawButton();
}
// Draw Info Texts for set number Buttons
tft.setTextSize(1);
tft.setTextColor(WHITE);
tft.setCursor(bigButtonWidth+2*buttonSpacing+60,buttonSpacing+5); tft.print("SPEED");
tft.setCursor(bigButtonWidth+2*buttonSpacing+50,2*buttonSpacing+buttonHeight+5); tft.print("DISTANCE");
tft.setCursor(bigButtonWidth+2*buttonSpacing+60,3*buttonSpacing+2*buttonHeight+5); tft.print("RAMP");
tft.setCursor(bigButtonWidth+2*buttonSpacing+40,4*buttonSpacing+3*buttonHeight+5); tft.print("SUBDIVISIONS");
tft.setCursor(smallButtonWidth+2*buttonSpacing+60,4*buttonSpacing+3*buttonHeight+5); tft.print("DELAY");
tft.fillRect(0, tft.height()-30, tft.width(), 30, LIGHTGREY); // Infobar
}
/*************************
** Required functions **
*************************/
void setup() {
tft.reset();
// basic motor setup
// Microstepping
pinMode(M1, OUTPUT);
pinMode(M2, OUTPUT);
pinMode(M3, OUTPUT);
//see table for step values: https://lastminuteengineers.com/a4988-stepper-motor-driver-arduino-tutorial/
digitalWrite(M1, HIGH);
digitalWrite(M2, HIGH);
digitalWrite(M3, HIGH);
stepper.attach( STEP_PIN, DIR_PIN );
stepper.attachEnable (ENABLE_PIN,1,LOW); // Set Enable Pin and Turn of Motor per Default
// Setup the Display
tft.begin(tft.readID());
tft.setRotation(1);
tft.fillScreen(BLACK);
//call function to draw our gui
drawButtons();
Serial.begin(115200);
Serial.println("Starting Slider Control V2.0 by Gregor Urabl \r\n");
Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());
}
void loop() {
//touchscreen
uint16_t i;
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
{
p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(),0);
p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(),0);
//debug
//check the area where we drew the buton for touch
/*
Serial.print("Touch X is:");
Serial.print(p.x);
Serial.print("\r\n");
Serial.print("Touch Y is:");
Serial.print(p.y);
Serial.print("\r\n");*/
//--------------------NORMAL button
if ((p.y >= 10) && (p.x >= 40) && (p.y <= 220) && (p.x <= 100) ) {
digitalWrite(ENABLE_PIN, LOW); //motor on
//Set Basic Speed and Acceleration/Ramp of each Steppers at startup
stepper.setMaxSpeed(speed_set); //
stepper.setRampLen(ramp_set); //
stepper.setZero(0); //set current Position as 0
updateStr("Starting Normal Run");
tft.fillRect(0, tft.height()-35, tft.width(), 5, RED); // Create Red Progress Bar Basis
stepper.moveTo(distance_set*10*motorDirection);
while(stepper.stepsToDo() > 0){
Serial.println(stepper.moving());
tft.fillRect(0, tft.height()-35, tft.width()-(tft.width()/100*stepper.moving()), 5, GREEN); // Progress Bar
}
if(return_to_home == true){
Serial.println("Returning Home");
stepper.moveTo(0);
while(stepper.stepsToDo() > 0){ // Progress Bar for Home Run
Serial.println(stepper.moving());
tft.fillRect(tft.width(), tft.height()-35, -(tft.width()-(tft.width()/100*stepper.moving())), 5, BLUE);
}
if(stepper.currentPosition() == 0){ // turn motor of after reaching Home
tft.fillRect(0, tft.height()-35, tft.width(), 5, BLACK); // "Remove" Progress Bar
digitalWrite(ENABLE_PIN, HIGH); //motor off
}
} else{digitalWrite(ENABLE_PIN, HIGH);} //motor off
}
//--------------------SPEED button with UPDATE of number
if ((p.y >= 240) && (p.x >= 40) && (p.y <= 330) && (p.x <= 110) ) {
//one touch raises speed by X up to "speed_max"
if(speed_set < speed_max) {
speed_set = speed_set + raise_speed_by;
}
else {
speed_set = 70;
}
int speed_percentage = speed_set/14;
int_to_string(speed_percentage, text_buffer);
sprintf(text_buffer,"%s%s",text_buffer,"%");
buttons[1].initButtonUL(&tft, bigButtonWidth+2*buttonSpacing, buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, text_buffer, 3); // SPEED Button (set number)
redrawButtons(1,bigButtonWidth+2*buttonSpacing+60,buttonSpacing+5,"SPEED");
String speedMsg = "Speed set to ";
speedMsg.concat(text_buffer);
updateStr(speedMsg);
}
//--------------------MANUAL button
if ((p.y >= 10) && (p.x >= 140) && (p.y <= 220) && (p.x <= 210) ) {
//Set Basic Speed and Acceleration/Ramp of each Steppers at startup
stepper.setMaxSpeed(speed_set); //speed_set
stepper.setRampLen(ramp_set); //ramp_set
if(manual_start_or_stop == true){ //start run on first click
digitalWrite(ENABLE_PIN, LOW); //motor on
Serial.println(speed_set);
stepper.setZero(0); //set current Position as 0
updateStr("Starting Manual Run");
stepper.rotate(motorDirection);
manual_start_or_stop = !manual_start_or_stop;
}
else{ // stop run on second click
updateStr("Stopping Manual Run");
manual_start_or_stop = !manual_start_or_stop;
if(return_to_home == true){
Serial.println("Returning Home");
stepper.moveTo(0);
if(stepper.currentPosition() == 0){ // turn motor of after reaching Home
digitalWrite(ENABLE_PIN, HIGH); //motor off
}
} else{digitalWrite(ENABLE_PIN, HIGH);} //motor off
}
}
//--------------------DISTANCE button with UPDATE of number
if ((p.y >= 235) && (p.x >= 140) && (p.y <= 320) && (p.x <= 220) ) {
//one touch raises Distance by X up to Slider Length
if(distance_set < slider_length) {
distance_set = distance_set + raise_distance_by;
}
else {
distance_set = 0;
}
int_to_string(distance_set, text_buffer);
buttons[3].initButtonUL(&tft, bigButtonWidth+2*buttonSpacing, 1*buttonHeight+2*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, text_buffer, 3); // DIST Button (set number)
redrawButtons(3,bigButtonWidth+2*buttonSpacing+50,2*buttonSpacing+buttonHeight+5,"DISTANCE");
String distMsg = "Travel Distance set to ";
distMsg.concat(text_buffer);
updateStr(distMsg);
}
//--------------------RETURN/ NO RETURN button
if ((p.y >= 10) && (p.x >= 250) && (p.y <= 100) && (p.x <= 310) ) {
return_to_home = !return_to_home;
if(return_to_home == true){
buttons[4].initButtonUL(&tft, buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, "<-->", 3);
buttons[4].drawButton();
updateStr("Return Mode set to RETURN");
} else{
buttons[4].initButtonUL(&tft, buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, "-->|", 3);
buttons[4].drawButton();
updateStr("Return Mode set to SINGLE RUN");
}
}
//--------------------DIRECTION button
if ((p.y >= 125) && (p.x >= 245) && (p.y <=220) && (p.x <= 315) ) {
motorDirection *= -1; // invert it
if(motorDirection == -1){
buttons[5].initButtonUL(&tft, smallButtonWidth+2*buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE,">>" , 3); // DIRECTION Button
buttons[5].drawButton();
updateStr("Direction set set to "); tft.write(0x10);tft.write(0x10);tft.write(" CW");
} else{
buttons[5].initButtonUL(&tft, smallButtonWidth+2*buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE,"<<" , 3); // DIRECTION Button
buttons[5].drawButton();
updateStr("Direction set set to "); tft.write(0x11);tft.write(0x11);tft.write(" CCW");
}
}
//--------------------RAMP button with UPDATE of number
if ((p.y >= 235) && (p.x >= 250) && (p.y <=325) && (p.x <= 320) ) {
//one touch raises Ramp by X up to (slider_length/2)
if(ramp_set < speed_max) {
ramp_set = ramp_set + ramp_steps_by;
}
else {
ramp_set = 0;
}
int_to_string(ramp_set, text_buffer);
buttons[6].initButtonUL(&tft, 2*smallButtonWidth+3*buttonSpacing, 2*buttonHeight+3*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, DARKGREY, WHITE, text_buffer, 3);// RAMP Button (set number)
redrawButtons(6,bigButtonWidth+2*buttonSpacing+60,3*buttonSpacing+2*buttonHeight+5,"RAMP");
String rampMsg = "Ramp set to ";
rampMsg.concat(text_buffer);
updateStr(rampMsg);
}
//------------------------TIMELAPSE START button
if ((p.y >= 10) && (p.x >= 350) && (p.y <= 100) && (p.x <= 420) ) {
updateStr("Starting Timelapse with ");
// TODO
}
//------------------------DELAY button with UPDATE of number
if ((p.y >= 125) && (p.x >= 360) && (p.y <= 220) && (p.x <= 420) ) { // if ((p.y >= 125) && (p.x >= 360) && (p.y <= 220) && (p.x <= 420) ) {
//one touch raises time by X up to time_max
if(time_set < time_max) {
time_set = time_set + raise_time_by;
}
else {
time_set = 0;
}
int_to_string(time_set, text_buffer);
buttons[8].initButtonUL(&tft, smallButtonWidth+2*buttonSpacing, 3*buttonHeight+4*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, ORANGE, WHITE, text_buffer, 3);// DELAY Button (set number)
redrawButtons(8,smallButtonWidth+2*buttonSpacing+60,4*buttonSpacing+3*buttonHeight+5,"DELAY");
String timeMsg = "Delay for Timelapse set to ";
timeMsg.concat(text_buffer);
updateStr(timeMsg);
}
//------------------------STEPS button with UPDATE of number
if ((p.y >= 230) && (p.x >= 360) && (p.y <= 310) && (p.x <= 410) ) {
//one touch raises steps by 10 up to steps_max
if(steps_set < steps_max) {
steps_set = steps_set + raise_steps_by;
}
else {
steps_set = 100;
}
int_to_string(steps_set, text_buffer);
buttons[9].initButtonUL(&tft, 2*smallButtonWidth+3*buttonSpacing, 3*buttonHeight+4*buttonSpacing, smallButtonWidth, buttonHeight, WHITE, ORANGE, WHITE, text_buffer, 3); // STEPS Button (set number)
redrawButtons(9,bigButtonWidth+2*buttonSpacing+40,4*buttonSpacing+3*buttonHeight+5,"SUBDIVISIONS");
String stepsMsg = "Steps set to ";
stepsMsg.concat(text_buffer);
updateStr(stepsMsg);
}
}
}
/***************************************************************************
* update string so we see what has been touched - debug help
****************************************************************************/
void updateStr(String msg){
tft.fillRect(0, tft.height()-30, tft.width(), 30, LIGHTGREY);
tft.setCursor(20,tft.height()-22);
tft.setTextSize(2);
tft.setTextColor(BLACK);
tft.print(msg);
//Serial.println(msg); //Only for Debug
}
/***************************************************************************
* redraw Buttons after Input
****************************************************************************/
void redrawButtons(char buttonNr,short xCursor,short yCursor, String buttonLabel){
buttons[buttonNr].drawButton();
tft.setTextSize(1);
tft.setTextColor(WHITE);
tft.setCursor(xCursor, yCursor);
tft.print(buttonLabel);
}
/*****************************************************************************
* convert X to String
****************************************************************************/
void int_to_string(int val, char* string) {
if(string)
sprintf(string, "%d", val);
return;
}
Im großen und Ganzen funktioniert das ganze bereits wie es sollte, allerdings haben sich bei der letzten Änderung von Accelstepper zu Moba Tools ein paar Fragen ergeben:
1) Geschwindigkeit
Ich habe in der Erstfassung des Sketches mit setSpeed gearbeitet, kam dabei aber aufgrund des Planetengetriebes meines Nema17 auf ziemlich hohe Werte die nicht sehr Userfreundlich einstellbar gewesen wären. Durch einen Multiplikator von ca. 200 auf die 200Steps/Rev vom Nema (mittels myStepper.currentPosition() über Serial Monitor ausgelesen), kam ich da auf ca 40.000 Steps pro Umdrehung. Ich nutze daher jetzt setMaxSpeed.
Um rauszubekommen, was ich dem Motor zumuten kann, habe ich mit einem der Demosketches von Moba Tools getestet und graduell den Wert erhöht.
/* Example for MobaTools
Moving a stepper back and forth
https://raw.githubusercontent.com/MicroBahner/MobaTools/master/examples/_Stepper/back_ForthStepperPause/back_ForthStepperPause.ino
*/
#include <MobaTools.h>
// Adjust pins, steps and time as needed
const byte stepPin = 25;
const byte dirPin = 27;
const int stepsPerRev = 3200; // Steps per Revolution ( example with 800 Steps = 1/4 microsteps )
const long targetPos = 6400; // stepper moves between 0 and targetpos , example with 1600
long nextPos;
MoToStepper myStepper ( stepsPerRev, STEPDIR );
MoToTimer stepperPause; // Pause between stepper moves
bool stepperRunning;
void setup() {
myStepper.attach( stepPin, dirPin );
myStepper.setMaxSpeed( 1400 ); // 60 Rev/Min ( if stepsPerRev is set correctly )
myStepper.setRampLen(0);
stepperRunning = true;
}
void loop() {
if ( stepperRunning ) {
// Wait till stepper has reached target, then set pause time
if ( !myStepper.moving() ) {
// stepper has reached target, start pause
stepperPause.setTime( 1000 );
stepperRunning = false;
}
} else {
// stepper doesn't move, wait till stepperPause time expires
if ( stepperPause.expired() ) {
// stepperPause time expired. Start stepper in opposite direction
if ( nextPos == 0 ) {
nextPos = targetPos;
} else {
nextPos = 0;
}
myStepper.moveTo( nextPos );
stepperRunning = true;
}
}
// The sketch is not blocked while the stepper is moving nor while it is stopped.
// Other nonblocking tasks can be added here
}
Bis 1400 funktionierts toll, ab dann wirds seltsam - teilweise wieder langsamer, teilweise Stillstand. Aber 1400 war ausreichend schnell, also sollte das mein Maximum werden. Daher ist in meinem Projekt die Max Speed jetzt 1400 und die Steps 70, also 5% jeweils.
Interessanterweise ist 1400 in meinem Sketch aber deutlich langsamer als im Demosketch. Kann das an der Speicherauslastung durch die vielen Grafiken etc. liegen? Am Loop sollts ja nicht liegen, genau wegen dieser Limitierung habe ich ursprünglich von Accelstepper auf Moba gewechselt. Wenn ich von 5% auf 100% steppe ist ein dementsprechend höheres Tempo erkennbar, nur kommt es bei weitem nicht an das ran, was 1400 beim Anderen war.
2) Ramp
Ich bin nicht sicher, ob ich den Ramp Parameter verstehe. Sehe ich das richtig, dass das eine lineare Rampe von Tempo 0 auf Tempo MaxSpeed darstellt, die über die Distanz der als Parameter mitgegebenen Steps läuft? Gibt es eine Möglichkeit das auch anders als linear, z.B. logarithmisch zu machen? Und gefühlt ruckelt die Beschleunigung stellenweise wärend der Ramp. Mache ich da was falsch im Code, oder ist das einfach so? Und was sind "gute" Ramp Erfahrungswerte?
3) Progress Bar
Ich lasse während des Normal Runs eine Progress Bar zeichnen. Diese funktioniert auch 1A, allerdings startet sie nicht bei Null sondern immer gleich mit einem "erledigten" Teil. Was kann da das Problem sein?
Also er startet nicht so:
[x------------------------------]
sondern so:
[xxxx--------------------------]
Danke schonmal im Voraus, sind wieder ne Menge Fragen
Und hier noch die angekündigte Thread Historie:
//////////////////////////////////////////////////////////////////