Container Portal Crane with rainbow LED dash board
This example shows a Container Portal Crane and a colorful control board to load and unload 20’ and 40’ Container on model trains in gauge H0 (1/87); controlled by Arduino UNO R4 MINIMA. It explains a possible solution for a very general pick ’n place machine with man-machine-interface (MHI) on a joyful way with the Arduino and some professional components in industrial quality. Enjoy the flexibility of Arduino in this pick ´n place machine for loading 20`and 40`Container on model trains, all controlled and monitored from a colorful, rainbow LED dash board.
Devices & Components
Arduino® UNO R4 Minima
Neo Pixel 90° circle
drylin® SLW-0620 Linearmodul SLWC-0620AR-C0BE2-F0A0B-CC0A0AA-250 1 (anti-reflex)
Grove Bar LED
Linear actuator with stepper motor
Joy-stick, analog, x/y and push button
Hardware & Tools
Digital Multimeter
Soldering Iron, ESD
Software & Tools
Arduino IDE
Arduino Maker Platform
Project description
Code
260123 code of Container PortalCrane formated
cpp
// used Arduino R4 MINIMA, or others
1// used Arduino R4 MINIMA, but it works also on other Arduinos 2/* 3 Example sketch to control a stepper motor with A4988 (resp. 8825) stepper motor driver, 4AccelStepper library and Arduino: acceleration and deceleration. 5More info: https://www.makerguides.com 6*/ 7// Include the AccelStepper library, for X- resp. left/right 8// and Z- resp. up/down-axe movement: 9#include <AccelStepper.h> 10#include <Adafruit_NeoPixel.h> // visualisation of X-axe 11 12// include the servo library for up/down movement, Z-axe, not used here 13// #include <Servo.h> 14#include <Grove_LED_Bar.h> // visualisation of up/down movement, Z-axe 15 16// Define stepper motor connections and motor interface type. 17//stepper motor for up/down connected to: 18#define dirPin 2 19#define stepPin 3 20//stepper motor for Left_Right connected to: 21#define stepPin_L_R 5 22#define dirPin_L_R 10 23// Motor interface type must be set to 1 when using a driver 24 #define motorInterfaceType 1 25 // Define number of steps per revolution: 26const int stepsPerRevolution = 400; // depends on 1/n step mode on driver 27// Create a new instance of the AccelStepper class(an object): 28 AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin); 29 AccelStepper stepper_L_R = AccelStepper(motorInterfaceType, stepPin_L_R, dirPin_L_R); 30 31// Create a new instance of the servo class (an object): no servo used here 32// Servo up_down_servo; 33 34 35// Digital IO pin connected to the button. This will be driven with a 36// pull-up resistor so the switch pulls the pin to ground momentarily. 37// On a high -> low transition the button press logic will execute. 38#define BUTTON_PIN_bl 4 39 40#define PIXEL_PIN 7 // Digital IO pin connected to the NeoPixels; displays movement of the crane left/right. 41// potentiometer on joy stick for left/right axeis connected to analog pin A0: 42#define rotaryResistor A0 // Left_Right movement on joy-stick 43 44//potentiometer on joy stick for up/down is connected to analog pin A1: 45#define potiResistor A1 // up/down movement on joy-stick 46// int CLK Pin = 8, 47// int DATA Pin = 6, 48// int Orientation = 0 49// Typ Grove LED Bar v2.1 mit 10 LEDs 8xgrün 1xgelb 1xrot 50// Declare our LED Bar for up/down object: 51Grove_LED_Bar bar(8, 6, 0); 52 53 54int PIXEL_COUNT = 30; // Number of NeoPixels LED on my ring 30 55int buzzer = 12; // control IO pin mode for buzzer, digital pin 12 for level_z 56int NewPotentiometerValue = 0; 57int lastPotentiometerValue = 0; 58float level = 0; 59float level_z = 0; // level for Z-axe magnetic picker up/down 60float value_z = 0; 61 62 63 64int Button_magneticPicker = 13; // red button 65int SwitchRelayMagnetcurrent = 11; 66 67 68// Declare our NeoPixel strip object for left/right display: 69Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); 70// Argument 1 = Number of pixels in NeoPixel strip 71// Argument 2 = Arduino pin number (most are valid) 72// Argument 3 = Pixel type flags, add together as needed: 73// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 74// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 75// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 76// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 77// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) 78uint32_t magenta = strip.Color(255,0,255); 79uint32_t greenishwhite = strip.Color(0,64,0,64); 80uint32_t Blue = strip.Color(0,0,255); 81uint32_t Red = strip.Color(255,0,0); 82uint32_t whiteblue = strip.Color(130,127,80); 83 84void setup() { 85 pinMode(buzzer, OUTPUT); 86 pinMode(BUTTON_PIN_bl, INPUT); // blue button starts rainbow loop 87 pinMode(Button_magneticPicker, INPUT); // red button 88 pinMode(SwitchRelayMagnetcurrent, OUTPUT); 89 90 strip.begin(); // Initialize NeoPixel strip object (REQUIRED) 91 strip.setBrightness(7); //set global brightness to n% 92 rainbow(10); 93 strip.show(); // Initialize all pixels to 'off' 94 //begin the communikation with the LED Bar: 95 bar.begin(); 96 //.. if joy stick poti is changed 97 //it shall move from green over yellow to red 98 bar.setGreenToRed(true); 99// Set the maximum speed and acceleration for the stepper motor: 100// .. for up/down 101stepper.setMaxSpeed(18000); 102stepper.setAcceleration(50); 103// Declare pins for up/down as output: 104 pinMode(stepPin, OUTPUT); 105 pinMode(dirPin, OUTPUT); 106 107// Set the maximum speed and acceleration for the stepper motor: 108// .. for Left_Right 109stepper_L_R.setMaxSpeed(19000); 110stepper_L_R.setAcceleration(500); 111// Declare pins for Left_Right movement as output: 112 pinMode(stepPin_L_R, OUTPUT); 113 pinMode(dirPin_L_R, OUTPUT); 114 115/* Set the servo interface for up/down movement : 116up_down_servo.attach(5); // create an instance (object) and attach it to pin 5 117.. servo not used here */ 118 119 // open a serial connection to display values 120Serial.begin(9600); 121Serial.println("Ohoh"); 122} 123 124void loop() { 125 126boolean buttonState = digitalRead(BUTTON_PIN_bl); 127if (buttonState == HIGH) { 128 strip.begin(); // Initialize NeoPixel strip object (REQUIRED) 129 strip.setBrightness(3); //set global brightness to n% 130 rainbow(10); 131 theaterChaseRainbow(20); 132 strip.show(); // Initialize all pixels to 'off' 133 //turn_off(); 134 //strip.show(); 135 buttonState = digitalRead(BUTTON_PIN_bl); 136}; 137 138boolean magnetState = digitalRead(Button_magneticPicker); 139if (magnetState == HIGH) 140{ 141digitalWrite(SwitchRelayMagnetcurrent, HIGH); 142} 143else 144{ 145 digitalWrite(SwitchRelayMagnetcurrent, LOW); 146 } 147magnetState = digitalRead(Button_magneticPicker); 148 149 150 //read value of analogen Pin A0, Left_Right movement 151 int value = analogRead(rotaryResistor); 152 readAndSendPotentiometerDataIfChanged(); 153 154 // control the movement Left_Right: 155 int rotaryResistor; 156 157 // Read new position of rotaryResistor 158 int value_poti = analogRead(rotaryResistor); 159while (value_poti >517) { 160//mapping the value to the actual range: 161 float speed = map(value_poti, 517, 1000, -1, -7000); 162 stepper_L_R.setSpeed(speed); 163 stepper_L_R.runSpeed(); 164 readAndSendPotentiometerDataIfChanged(); 165 value_poti = analogRead(rotaryResistor); 166 167} 168while (value_poti < 475) 169{ 170 float speed = map(value_poti, 30, 475, 7000,1); 171 stepper_L_R.setSpeed(speed); 172 stepper_L_R.runSpeed(); 173 readAndSendPotentiometerDataIfChanged(); 174value_poti = analogRead(rotaryResistor); 175 } 176 //short pause of 1 Millisecond 177 delay(1); 178 179// display the movement up/down : 180 //read value of potiResistor up/down: 181 float value_z = analogRead(potiResistor); 182 //mapping the value to the range of the LED Bar 183 float level_z = map(value_z, 0, 990, 0, 10); 184 //write to the LED Bar 185 bar.setLevel(level_z); 186 187 188/* used only if servo drive is used 189 val_up_down = map(value_z, 10, 990, 180, 0); // scale it for use with the servo (value between 0 and 180) 190 up_down_servo.write(val_up_down); // sets the servo position according to the scaled value 191*/ 192 193while (value_z >547) // down movemnt 194{ 195//mapping the value to the actual range: 196 float speed_z = map(value_z, 550, 1000, 1, 2500); 197 stepper.setSpeed(speed_z); 198 stepper.runSpeed(); 199 // display the movement up/down : 200 //mapping the value to the range of the LED Bar 201 level_z = map(value_z, 0, 990, 0, 10); 202 //write to the LED Bar 203 bar.setLevel(level_z); 204 // give alarme sound if the value is to high for the down movement 205 int pitch = map(level_z, 6, 10, 240, 1440); 206 if (level_z > 9) { 207 tone(buzzer, pitch,5); 208 delay(10);} 209 value_z = analogRead(potiResistor); 210} 211while (value_z < 470) // up movemnt 212{ 213 float speed_z = map(value_z, 50, 490, -2500,-1); 214 stepper.setSpeed(speed_z); 215 stepper.runSpeed(); 216 // display the movement up/down : 217 //mapping the value to the range of the LED Bar 218 float level_z = map(value_z, 0, 990, 0, 10); 219 //write to the LED Bar 220 bar.setLevel(level_z); 221 value_z = analogRead(potiResistor); 222 } 223 //short pause of 1 or more Milliseconds 224 delay(1); 225 226 digitalRead(BUTTON_PIN_bl); 227} 228 229// Fill strip pixels one after another with a color. Strip is NOT cleared 230// first; anything there will be covered pixel by pixel. Pass in color 231// (as a single 'packed' 32-bit value, which you can get by calling 232// strip.Color(red, green, blue) as shown in the loop() function above), 233// and a delay time (in milliseconds) between pixels. 234/* 235void colorWipe(uint32_t color, int wait) { 236 for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip... 237 strip.setPixelColor(i, color); // Set pixel's color (in RAM) 238 strip.show(); // Update strip to match 239 delay(wait); // Pause for a moment 240 } 241} 242*/ 243// Rainbow cycle along whole strip. Pass delay time (in ms) between frames. 244void rainbow(int wait) { 245 // Hue of first pixel runs 3 complete loops through the color wheel. 246 // Color wheel has a range of 65536 but it's OK if we roll over, so 247 // just count from 0 to 3*65536. Adding 256 to firstPixelHue each time 248 // means we'll make 3*65536/256 = 768 passes through this outer loop: 249 for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) { 250 for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip... 251 // Offset pixel hue by an amount to make one full revolution of the 252 // color wheel (range of 65536) along the length of the strip 253 // (strip.numPixels() steps): 254 int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels()); 255 // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or 256 // optionally add saturation and value (brightness) (each 0 to 255). 257 // Here we're using just the single-argument hue variant. The result 258 // is passed through strip.gamma32() to provide 'truer' colors 259 // before assigning to each pixel: 260 strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue))); 261 } 262 strip.show(); // Update strip with new contents 263 delay(wait); // Pause for a moment 264 } 265} 266 267// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames. 268void theaterChaseRainbow(int wait) { 269 int firstPixelHue = 0; // First pixel starts at red (hue 0) 270 for(int a=0; a<30; a++) { // Repeat 30 times... 271 for(int b=0; b<3; b++) { // 'b' counts from 0 to 2... 272 strip.clear(); // Set all pixels in RAM to 0 (off) 273 // 'c' counts up from 'b' to end of strip in increments of 3... 274 for(int c=b; c<strip.numPixels(); c += 3) { 275 // hue of pixel 'c' is offset by an amount to make one full 276 // revolution of the color wheel (range 65536) along the length 277 // of the strip (strip.numPixels() steps): 278 int hue = firstPixelHue + c * 65536L / strip.numPixels(); 279 uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB 280 strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' 281 } 282 strip.show(); // Update strip with new contents 283 delay(wait); // Pause for a moment 284 firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames 285 } 286 } 287} 288 289void clearPixels() { 290 uint16_t clearColor = (0, 0, 0); 291 for (int i=0; i<=30; i++){ 292 strip.setPixelColor(i, clearColor);} 293 294 strip.show(); 295 296} 297 298void colorWipe(uint32_t c) { 299 for(uint16_t i = lastPotentiometerValue; i<30; i++){ 300 uint16_t clearColor = (0, 0, 0); 301 strip.setPixelColor(i, clearColor); 302 } 303 for(uint16_t i=0; i<lastPotentiometerValue; i++) { 304 strip.setPixelColor(i, c); 305 delay(0.5); 306 } 307 strip.show(); 308} 309 310 311void colorWipe_down(uint32_t c) { 312 for(uint16_t i=0; i<30;i++){ 313 uint16_t clearColor = (0, 0, 0); 314 strip.setPixelColor(i, clearColor); 315 } 316 for(uint16_t i=15; i<lastPotentiometerValue; i++) { 317 strip.setPixelColor(i, c); 318 delay(0.5); 319 } 320 strip.show(); 321} 322 323 void turn_off () 324 { for (int i = 0; i <= 30; i++) 325 {strip.setPixelColor(i,0,0,0,0);} 326 } 327void readAndSendPotentiometerDataIfChanged(void) { 328 //auslesen des Wertes vom analogen Pin 0 329 int value = analogRead(rotaryResistor); 330if (value <510) 331{ 332//mappen des Wertes auf den Gültigkeitsbereich des LED Streifens 333float level = map(value, 10, 510, 1, 16); 334 int newPotentiometerValue = level; 335 if (newPotentiometerValue != lastPotentiometerValue) 336 { 337 lastPotentiometerValue = newPotentiometerValue; 338 //If the value is 0, we want to clear the pixel values to white 339 if (lastPotentiometerValue >= 18) { 340 clearPixels(); 341 //turn_off(); 342 //strip.show(); 343 } else { 344 /*"Serial.print ("value. :"); Serial.print(value); 345 Serial.print("\t"); 346 Serial.print("level. :"); Serial.print(level); 347 Serial.print("\t"); 348 Serial.print("lastPotentiometerValue :"); 349 Serial.println(lastPotentiometerValue);*/ 350 colorWipe(magenta); 351 } 352 } 353 } 354 else 355if (value >510) 356 { 357 //mappen des Wertes auf den Gültigkeitsbereich des LED Streifens 358 float level = map(value, 510, 1000, 16, 30); 359 int newPotentiometerValue = level; 360 if (newPotentiometerValue != lastPotentiometerValue) 361 { 362 lastPotentiometerValue = newPotentiometerValue; 363 //If the speed is 0, we want to clear the pixel values to dark 364 if (lastPotentiometerValue <= 15) { 365 clearPixels(); 366 for(uint16_t i=0; i=14;i++) 367 { 368 uint16_t clearColor = (0, 0, 0); 369 strip.setPixelColor(i, clearColor); 370 } 371 //turn_off(); 372 strip.show(); 373 } else { 374 /*Serial.print ("value. :"); Serial.print(value); 375 Serial.print("\t"); 376 Serial.print("level. :"); Serial.print(level); 377 Serial.print("\t"); 378 Serial.print("lastPotentiometerValue :"); 379 Serial.println(lastPotentiometerValue); 380 */ 381 colorWipe_down(Blue); 382 } 383 } 384 } 385}
Downloadable files
260123s handbook ContainerPortalCrane in H0 copy
describes the whole project and used components
260123s handbook ContainerPortalCrane in H0 Kopie.pdf
16 linear actuator Nema 08
16 Linearantrieb Schrittmotor NEMA08-04LA_Datenblatt.pdf
15 IGUS linear axe with stepper Nema 11
15 Igus Data sheet linear axe _2024_SLWC_and_SLW-XY_0620_EN_1.pdf
11 driver 8825 Stepper motor
11 DRV 8825 Stepper Motor Driver with Arduino Tutorial (4 Examples).pdf
10 Stepper Motor driver PoStep 25 -256
10 PoStep25-256 -joy-it--schrittmotor-treiber-25-a-schraubklemme.pdf
5 electro magnet 12 V DC not magnetic if no current
5 E-Magnet data sheet-intertec-elektromagnet 12vdc.pdf
Documentation
1 parametrische Resonanzen SPS 1984
1 parametrische Resonanzen SPS 1984.pdf
3 original patent SMIK
3 Patent SMIK steppermotor InstabilityKiller.pdf
Comments
Only logged in users can leave comments