Difference between revisions of "RaspberryPiRoboter"

From Ghoulwiki
Jump to: navigation, search
(Gallery)
(i2c protocol notes)
Line 114: Line 114:
 
defaults:
 
defaults:
 
#define COMMAND_NONE 0xFF
 
#define COMMAND_NONE 0xFF
uint gTimeout           = 800; // 6.4ms * 800 = ca 5sec
+
uint gTimeout     = 800; // 6.4ms * 800 = ca 5sec
char gPortCMode        = 2;
+
char gStepCycleLen = 32; // ca 32 x ~200us = 6.4ms   (100u sleep, but prolly another 100u exec-command even if empty)
char gMotorSpeedMask    = 0xff; // 0xff = full speed
 
char gStepCycleLen     = 64; // ca 64 x 100us = 6.4ms
 
  
 
char cmd = (c >> 4);    // hi nibble
 
char cmd = (c >> 4);    // hi nibble
 
char x  = (c & 0x0f);      // low nibble
 
char x  = (c & 0x0f);      // low nibble
  
bool a;
+
    switch (cmd)
switch (cmd)
+
    {
{
+
        // start/stop motor commands
// start/stop motor commands
+
        case 0x0: // panic, stop all motors
case 0x0: a = (x==0)?0:1; // 0=stop
+
            MOTOR_0_F = 0;
  gMainActive = a; MAIN_MOTOR_PIN = a; gMyCounter = 0; gMyCounterEnd = x*10;     gMySensor = 0; gMySensorTarget = SENSOR_IGNORE; break; // motor duration x 10
+
            MOTOR_0_B = 0;
case 0x1: gMainActive = 1; MAIN_MOTOR_PIN = 1; gMyCounter = 0; gMyCounterEnd = x*100;   gMySensor = 0; gMySensorTarget = SENSOR_IGNORE; break; // motor duration x 100
+
            MOTOR_1_F = 0;
case 0x2: gMainActive = 1; MAIN_MOTOR_PIN = 1; gMyCounter = 0; gMyCounterEnd = gTimeout; gMySensor = 0; gMySensorTarget = x; break;   // motor sensor
+
            MOTOR_1_B = 0;
case 0x3: gMainActive = 1; MAIN_MOTOR_PIN = 1; gMyCounter = 0; gMyCounterEnd = gTimeout; gMySensor = 0; gMySensorTarget = x*10; break; // motor sensor x 10
+
            MOTOR_2_F = 0;
case 0x4: gMainActive = 1; MAIN_MOTOR_PIN = 1; gMyCounter = 0; gMyCounterEnd = gTimeout; gMySensor = 0; gMySensorTarget = x*100; break; // motor sensor x 100
+
            MOTOR_2_B = 0;
 +
            MOTOR_3_F = 0;
 +
            MOTOR_3_B = 0;
 +
            MOTOR_4_F = 0;
 +
            MOTOR_4_B = 0;
 +
            MOTOR_5_F = 0;
 +
            MOTOR_5_B = 0;
 +
            for (int x=0;x<NUM_MOTORS;++x) { gMotors[x].counterEnd = 0; gMotors[x].sensorTarget = 0; }
 +
        break;
 +
        case 0x1: if (x==0) { SetMotorPins(m,0,0); } // 0x00=stop (fast)
 +
                  pm->counter = 0; pm->counterEnd = x*gParamFactor; pm->sensor = 0; pm->sensorTarget = SENSOR_IGNORE; break; // motor duration
 +
        case 0x2: pm->counter = 0; pm->counterEnd = gTimeout;       pm->sensor = 0; pm->sensorTarget = x*gParamFactor; break; // motor sensor
 +
        case 0x3: if (x < NUM_MOTORS) gSelectedMotor = x; break;
  
// config commands
+
        // config commands
case 0x6: gPortCMode = x; break; // PORTC "LEDs" 0=reserved, 1=counter, 2=sensor, 3=counter-mod8-circle-LEDs 4=like 3 but slower
+
        case 0x6: // motor direction fwd/reverse, misc
case 0x7:
+
            switch (x) {
switch (x) {
+
                case 0x00: pm->reverse = 0; break;
case 0x08: gMotorSpeedMask = 0xff; break; // 11111111 8/8 100%
+
                case 0x01: pm->reverse = 1; break;
case 0x07: gMotorSpeedMask = 0xfe; break; // 11111110 7/8
+
            }
case 0x06: gMotorSpeedMask = 0xee; break; // 11101110 6/8 75%
+
        break;
case 0x05: gMotorSpeedMask = 0xD5; break; // 10110101 5/8
+
        case 0x7: // motorspeed
case 0x04: gMotorSpeedMask = 0xCC; break; // 10101010 4/8 50%
+
            switch (x) {
case 0x03: gMotorSpeedMask = 0x92; break; // 10010010 3/8
+
                case 0x08: pm->speedMask = 0xff; break; // 11111111 8/8 100%
case 0x02: gMotorSpeedMask = 0x88; break; // 10001000 2/8 25%
+
                case 0x07: pm->speedMask = 0xfe; break; // 11111110 7/8
case 0x01: gMotorSpeedMask = 0x80; break; // 10000000 1/8
+
                case 0x06: pm->speedMask = 0xee; break; // 11101110 6/8 75%
 +
                case 0x05: pm->speedMask = 0xD5; break; // 10110101 5/8
 +
                case 0x04: pm->speedMask = 0xCC; break; // 10101010 4/8 50%
 +
                case 0x03: pm->speedMask = 0x92; break; // 10010010 3/8
 +
                case 0x02: pm->speedMask = 0x88; break; // 10001000 2/8 25%
 +
                case 0x01: pm->speedMask = 0x80; break; // 10000000 1/8
  
case 0x0A: gMotorSpeedMask = 0xFC; break; // 11111100 special
+
                case 0x0A: pm->speedMask = 0xFC; break; // 11111100 special
case 0x0B: gMotorSpeedMask = 0xF0; break; // 11110000 special
+
                case 0x0B: pm->speedMask = 0xF0; break; // 11110000 special
case 0x0C: gMotorSpeedMask = 0xC0; break; // 11000000 special
+
                case 0x0C: pm->speedMask = 0xC0; break; // 11000000 special
case 0x0D: gMotorSpeedMask = 0xCC; break; // 11001100 special
+
                case 0x0D: pm->speedMask = 0xCC; break; // 11001100 special
default:  gMotorSpeedMask = 0xff; break; // full speed
+
                default:  pm->speedMask = 0xff; break; // full speed
}
+
            }
break;
+
            break;
case 0x8: gTimeout = x*10; break;  // set timeout x 10
+
        case 0x8: gTimeout = x*gParamFactor; break;   // set timeout
case 0x9: gTimeout = x*100; break; // set timeout x 100
+
        // 0xA = read (see interrupt!)
// 0xA = read (see interrupt!)
+
        case 0xB: gStepCycleLen = x*gParamFactor; break; // 1 is a little more than 100usec, step gets called once per cycle, 100u x 64 = every 6.4msec
case 0xB: gStepCycleLen = x; break; // 1 is a little more than 100usec, step gets called once per cycle, 100u x 64 = every 6.4msec
+
        case 0xD:
case 0xC: gStepCycleLen = x*10; break;
+
            // maybe also gParamOption = x; for extended commands
}
+
            if (x < 8) gParamFactor = 1 << x;
 +
            // else another option...  x in 0..15
 +
        case 0xE: // timer0 and prescaler  0..8 : x1..x256
 +
    }
  
 
// interrupt: read
 
// interrupt: read
Line 164: Line 182:
 
switch (x)
 
switch (x)
 
{
 
{
case 0x0: i2c_mysend = 42; break; // ultimate answer
+
                        case 0x0: SSPBUF = 42; break; // ultimate answer
case 0x1: i2c_mysend = 0x01; break; // version
+
                        case 0x1: SSPBUF = 0x01; break; // version
case 0x2: i2c_mysend = 0x00; break; // reserved
+
                        case 0x2: SSPBUF = 0x00; break; // reserved
case 0x3: i2c_mysend = (gMyCounter >> 4) & 0xff; break; // gMyCounter
+
                        case 0x3: SSPBUF = (gMotors[gSelectedMotor].counter >> 4) & 0xff; break; // gMyCounter
case 0x4: i2c_mysend = gMySensor; break; // gMySensor
+
                        case 0x4: SSPBUF = gMotors[gSelectedMotor].sensor; break; // gMySensor
case 0x5: i2c_mysend = (gTimeout >> 4) & 0xff; break; // gTimeout
+
                        case 0x5: SSPBUF = (gTimeout >> 4) & 0xff; break; // gTimeout
case 0x6: i2c_mysend = gCommandExecLater; break; // command buffer, do not send new commands if this is different from COMMAND_NONE=0xff
+
                        case 0x6: SSPBUF = gCommandExecLater; break; // command buffer, do not send new commands if this is different from COMMAND_NONE=0xff
case 0x7: i2c_mysend = gMotorSpeedMask; break; // gMotorSpeedMask
+
                        case 0x7: SSPBUF = gMotors[gSelectedMotor].speedMask; break; // gMotorSpeedMask
default: i2c_mysend = 0; break; // unknown
+
                        default: SSPBUF = 0; break; // unknown
 
}
 
}
 
break;
 
break;

Revision as of 00:29, 3 May 2015

Info

Plan : 4/6-beinige Spinne mit RaspberryPi als Steuereinheit, Webcam, ferngesteuert via UMTS/LTE stick, Offroad gelände (noch nicht fertig)

  • Beine 2 gleidrig
    • 1 achse zw Unterschenkel und Oberschenkel
    • 2-3 achsen Obersch. zu Körper
    • Beine lang,dünn,leicht, z.b. dünne stange aus metall oder holz
    • Beine ca 0.5-1m lang, stelzende bewegung
  • Outdoor verwendung, z.b. wiese, waldboden, also mittelschweres-schweres gelände mit hindernissen und pflanzenfasern die räder oder raupen antriebe nicht passieren können
  • treppensteigen sollte auch möglich sein
  • webcam + umts stick für fernsteuerung
  • später dickere plastiktüten-hülle um körper für schutzt gegen regen
  • evtl solarzelle
  • gewicht ca 2-5kg bei 4 beinen mit je 30+40cm = theoretisch ca 150cm spannweite mit voll ausgestreckten beinen, in praxis aber immer gewinkelt
  • lowbudget projekt, ziel < 10 Euro pro achse(Motor+Getriebe+Sensor) (4 beine mit je 1+3 achsen = 16 motoren)
    • gleichstrom motoren mit "getriebe"/übersetzung durch mechanik statt schrittmotoren, ca 3-5 euro / motor
  • materialkosten spinne inklusive raspberry+webcam und batterien vorraussichtlich unter 300 euro
  • siehe auch RaspberryPiRoboter-archiv

Gallery

Hauptprobleme

Motoren

Lowbudget, 4 Beine a 1+3 achsen -> 16 Motoren, also vermutlich Gleichstrom Motoren

Gewinde

  • statt getriebe aus zahnrädern (teuer,kaum verfügbar) werden gewindestangen verwendet, billige meterware im baumarkt, versch. steigung(feingewinde)
  • querverstrebung zwischen ober+unterschenkel ähnlich muskel, abstand der befestigung zum knie/achse bestimmt tradeoff schnell vs kraftvoll
  • http://de.wikipedia.org/wiki/Metrisches_ISO-Gewinde
  • führung mit kippbar gelagerter mutter

Auslenkungserkennung der Beine

  • IR lichtschranke: an scheibe an gewindestange, 10 IR-LED+sensor paare für €1 pollin -> detect auf PIC chips, zähler mit i2c an raspberry pollbar
  • kontakt bei gewindestange zur regelmässigen justierung einmal pro durchlauf. bei zahnrad+schnecke an gewindestange auch am zahnrad.

Ideen :

  • verbrauchs-strom-messung der motoren
  • regelmässige korrektur mit drehbarer webcam
  • gefederte normalhaltung und motoren nur für auslenkung -> kein strom -> null position
  • mausrad-sensor verbauen (1 kugel maus mit wheel = 3 sensoren -> 5-6 mäuse)

Energie : Batterie + Solar

funkverbindung

  • optional da umts-stick genutzt werden kann, aber interessant
  • wiki: Richtfunkantennen lassen sich bei Sichtkontakt mehrere Kilometer überbrücken. Rekorde bis zu hundert Kilometer
  • schobi longrange bluetooth bis 1km bei sichtverbindung

PIC features

  • matrix at http://www.microchip.com for 8/16/32bit
  • I2C bus <-> raspberry comm
  • ADC,DAC,PWM,timer,USB,Ethernet,watchdog,
  • segment LCD
  • ICSP programming, JTAG, single wire debug
  • Configurable Logic Cell (CLC) : programmable combinational and sequential logic (also flipflop!, Operation while in Sleep), on-chip interconnection of peripherals and I/O micro e.g. PIC16F1713,
  • Zero Cross Detect : AC signal crosses through the ground potential, e.g. audio, wave.. micro e.g. PIC16F1703
  • Slope compensation : powersupply micro
  • CTMU Charge Time Measurement Unit (CTMU) e.g. PIC24F08KM202
  • Input Capture (interrupt) !!!! e.g. PIC24FJ16GA002 example
  • CWG complementary waveform generator micro
  • PSMC Programmable Switch Mode Controller : PWM, motor,power... micro
  • nanoWatt (power saving, hibernate)

i2c protocol notes

// draft version for testing i2c with one motor and IR sensor counting motor rotations
// I2C: rpi sends 1 byte, gets 1 byte in return (0 for commands)
// commands other than read are handled outside interrupt, 
// wait at least 2*gStepCycleLen*100usec or until read 0xA6=gCommandExecLater returns 0xFF=COMMAND_NONE before sending next or it might be cancelled

defaults:
#define COMMAND_NONE 0xFF
uint gTimeout      = 800; // 6.4ms * 800 = ca 5sec
char gStepCycleLen = 32; // ca 32 x ~200us = 6.4ms   (100u sleep, but prolly another 100u exec-command even if empty)

char cmd = (c >> 4);    // hi nibble
char x   = (c & 0x0f);      // low nibble

    switch (cmd)
    {
        // start/stop motor commands
        case 0x0: // panic, stop all motors
            MOTOR_0_F = 0;
            MOTOR_0_B = 0;
            MOTOR_1_F = 0;
            MOTOR_1_B = 0;
            MOTOR_2_F = 0;
            MOTOR_2_B = 0;
            MOTOR_3_F = 0;
            MOTOR_3_B = 0;
            MOTOR_4_F = 0;
            MOTOR_4_B = 0;
            MOTOR_5_F = 0;
            MOTOR_5_B = 0;
            for (int x=0;x<NUM_MOTORS;++x) { gMotors[x].counterEnd = 0; gMotors[x].sensorTarget = 0; }
        break;
        case 0x1: if (x==0) { SetMotorPins(m,0,0); } // 0x00=stop (fast)
                  pm->counter = 0; pm->counterEnd = x*gParamFactor; pm->sensor = 0; pm->sensorTarget = SENSOR_IGNORE; break;  // motor duration
        case 0x2: pm->counter = 0; pm->counterEnd = gTimeout;       pm->sensor = 0; pm->sensorTarget = x*gParamFactor; break; // motor sensor
        case 0x3: if (x < NUM_MOTORS) gSelectedMotor = x; break;

        // config commands
        case 0x6: // motor direction fwd/reverse, misc
            switch (x) {
                case 0x00: pm->reverse = 0; break;
                case 0x01: pm->reverse = 1; break;
            }
        break;
        case 0x7: // motorspeed
            switch (x) {
                case 0x08: pm->speedMask = 0xff; break; // 11111111 8/8 100%
                case 0x07: pm->speedMask = 0xfe; break; // 11111110 7/8
                case 0x06: pm->speedMask = 0xee; break; // 11101110 6/8 75%
                case 0x05: pm->speedMask = 0xD5; break; // 10110101 5/8
                case 0x04: pm->speedMask = 0xCC; break; // 10101010 4/8 50%
                case 0x03: pm->speedMask = 0x92; break; // 10010010 3/8
                case 0x02: pm->speedMask = 0x88; break; // 10001000 2/8 25%
                case 0x01: pm->speedMask = 0x80; break; // 10000000 1/8

                case 0x0A: pm->speedMask = 0xFC; break; // 11111100 special
                case 0x0B: pm->speedMask = 0xF0; break; // 11110000 special
                case 0x0C: pm->speedMask = 0xC0; break; // 11000000 special
                case 0x0D: pm->speedMask = 0xCC; break; // 11001100 special
                default:   pm->speedMask = 0xff; break; // full speed
            }
            break;
        case 0x8: gTimeout = x*gParamFactor; break;    // set timeout
        // 0xA = read (see interrupt!)
        case 0xB: gStepCycleLen = x*gParamFactor; break; // 1 is a little more than 100usec, step gets called once per cycle, 100u x 64 = every 6.4msec
        case 0xD:
            // maybe also gParamOption = x; for extended commands
            if (x < 8) gParamFactor = 1 << x;
            // else another option...  x in 0..15
        case 0xE: // timer0 and prescaler  0..8 : x1..x256
    }

// interrupt: read
case 0xA:
	switch (x)
	{
                        case 0x0: SSPBUF = 42; break; // ultimate answer
                        case 0x1: SSPBUF = 0x01; break; // version
                        case 0x2: SSPBUF = 0x00; break; // reserved
                        case 0x3: SSPBUF = (gMotors[gSelectedMotor].counter >> 4) & 0xff; break; // gMyCounter
                        case 0x4: SSPBUF = gMotors[gSelectedMotor].sensor; break; // gMySensor
                        case 0x5: SSPBUF = (gTimeout >> 4) & 0xff; break; // gTimeout
                        case 0x6: SSPBUF = gCommandExecLater; break; // command buffer, do not send new commands if this is different from COMMAND_NONE=0xff
                        case 0x7: SSPBUF = gMotors[gSelectedMotor].speedMask; break; // gMotorSpeedMask
                        default: SSPBUF = 0; break; // unknown
	}
break;

Bauteil/Werkzeug beschaffung

einkaufslisten

  • 10* 1,65+1* 9,65+3* 2,45+1* 4,95+1* 2,45+1* 1,00+1* 1,50+1* 1,25+1* 0,95+1* 0,75+1* 0,75+1* 0,95+1* 1,25+2* 0,50+1* 0,75+3* 0,85+2* 0,85

2015-02 B

  • keilriemen/zahnriemen ? conrad,voelkner,keilriemen24.de
  • Zahnkranzbohrfutter ebay viele für 5eur + 3,50 versand
  • kreuztisch,coordinatentisch
  • geo-dreieck
  • gehörschutz f. kreissäge
  • BAUMARKT: M6 gewindestange für cnc-fräs? (m6=1mm steigung)
  • BAUMARKT: noch ein blech, trennscheibe alu
  • säge für scheiben von alu-zylinder und holz-winkel
    • elektrische tisch-stichelsäge, 120eur, alu bis 10mm (hagebau auch:190eur -x) hornbach
    • kappsäge (wie kreissäge, gerung/winkel einstellbar) ? hauptsächlich für holz
    • gehrungs-säge (manuell, noch eine im keller? nope) manuell 40eur hagebau hagebau
    • gehrungs-säge (manuell, schobi tipp) hornbach 70euro : http://www.hornbach.de/shop/Gehrungssaege/3869514/artikel.html?WT.svl=artikel_img
    • decoupiersäge = automatische laubsäge, zu schwach
    • kreissäge ?
    • kapp/gehrungssäge (kreissäge) : 70eur hagebau : hagebau
    • kapp/gehrungssäge (kreissäge) : 160eur hagebau : hagebau
    • metall-kappsäge (1-fach gehrung, 170eur) hornbach
  • GPS modul !
  • PIC mit ethernet?
  • grosse metall bohrer, mymax bisher = M6.5 (bohrkranzfutter max = 6.0mm) .... vermutlich geht nix grösseres
  • heinz tipp: firma "fein" : profi sägen (oszillierend/vibrations), ca 300-400euro, aber für alu / fräs stück usw evtl geeignet
  • heinz tipp: andi fragen wegen alu-zylinder scheiben abschneiden gegen bissl was in kaffee kasse bei dem gehäuse menschen ?
  • pollin vielleicht 540 082 = 3,95 € 20m 8-adriges telefon flachkabel.
  • pollin vielleicht 501 501 = 12,95 € kleinbohrer viele grössen, http://www.pollin.de/shop/dt/ODk0ODk0OTk-/Werkstatt/Werkzeuge/Bohrer_Fraeser_Bits/HSS_Minibohrer_DAYTOOLS_SBS_150_150_teilig.html
  • pollin 64-560 290 = 1,00€ widerstandsdraht
  • pollin 64 590 036 = 2,5 solar 95x65mm 0.4W, 2V
  • pollin 64 810 054 = 4,95€ DCF funkuhr empfänger
  • pollin 64 340 316 = 1,25€ zugmagnet 12v
  • pollin xx 640 942 = 0,95€ lautsprecher
  • pollin 64 712 221 = 2,95€ wifi antenne
  • note : trio outdoor cam casing : 64-580 168
  • note : baumarkt : trennscheiben, mal fragen was gerät dafür kostet und ob man damit alu stange 5cm durchmesser schneiden kann
  • 1.50+1.95+2.50+0.95+3.95+2*1.95+1.95 = 16,70€
  • dx.com 37-in-1 (tipp from pi rover book) : http://www.dx.com/p/arduno-37-in-1-sensor-module-kit-black-142834#.VOpVly6IxQJ
  • block für sandpapier, vll noch einer im keller

reichelt 2015-02

links