|
Construction Equipment If it digs, pushes, hauls dirt "off road" post it here. |
|
Thread Tools | Display Modes |
|
#1
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Hi, Fired up!
Thanks! I saw from another thread that you are planning on building your own, and that you want to use standard parts. That sounds very similar to what I'm trying to do here. Keep me updated on your progress! :-) I'm going to share all the 3D files for this build, in case you want to reuse some of the parts from here. Stein :-) |
#2
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
I am using a Raspberry Pi 2 model B as the embedded PC for this project.
The Raspberry Pi will control: - The ESCs (speed controllers) for the seven gear motors via USB serial ports - Individual lights via GPIO pins - Engine sound via the 3.5mm audio jack - Remote control via a USB wireless gamepad - FPV from the CAB with the Raspberry Pi Camera - Configuration, reprogramming and telemetry via a USB WiFi. Amazon links: - Raspberry Pi 2 Model B - 1GB RAM - 900MHz Quad-Core CPU - Raspberry PI 5MP Camera Board Module I'm using a 4GB SD memory card I had laying around. Looks very much like this one: - Kingston 4GB microSDHC Class 10 I downloaded the Raspbian (Debian) image on my computer from here: - http://www.raspberrypi.org/downloads/ and installed it on the SD card as described on that download page. Then I connected it to a monitor, mouse and keyboard and powered it up. In the setup menu, I selected: - Terminal only (no graphical GUI) - Enable camera - Enable ssh - Disable serial port console This completes the setup and the Raspberry is now running with the operating system I want. |
#3
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
I'm adding WiFi because I want to use it for easy programming and for the FPV video link.
It's a good idea to use a very standard WiFi adapter, for example any adapter with a RealTek chipset, like this one: - 150Mbps 11n Wi-Fi USB Adapter, Nano Size because that is known to work well. Just plug it into the Raspberry PI, and then add the name of your WiFi network and the password: 1. Run this command: sudo nano /etc/network/interfaces 2. Edit the file so that it looks like this: Code:
auto lo iface lo inet loopback auto eth0 allow-hotplug eth0 iface eth0 inet manual auto wlan0 allow-hotplug wlan0 iface wlan0 inet dhcp wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf 4. Exit the editor by pressing CTRL-X 5. Run this command: sudo nano /etc/wpa_supplicant/wpa_supplicant.conf 6. Edit the file so that it looks like this: Code:
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="TheNameOfYourNetwork" psk="YourPassword" } network={ ssid="TheNameOfYourOtherNetworkIfAny" psk="YourPassword" } 7. Save the file by pressing CTRL-O 8. Exit the editor by pressing CTRL-X 9. Restart with command: sudo shutdown -r now When the Raspberry has restarted, you can see if the WiFi connection was successful by running this command: - ifconfig wlan0 This command should output something like this Code:
pi@raspberrypi ~ $ ifconfig wlan0 wlan0 Link encap:Ethernet HWaddr 00:0f:13:05:12:4e inet addr:192.168.0.107 Bcast:192.168.0.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:142807 errors:0 dropped:21 overruns:0 frame:0 TX packets:21617 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:34717556 (33.1 MiB) TX bytes:3289493 (3.1 MiB) - ping 8.8.8.8 (CTRL-C to exit) Should output this if successful: Code:
pi@raspberrypi ~ $ ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_req=2 ttl=56 time=30.8 ms 64 bytes from 8.8.8.8: icmp_req=3 ttl=56 time=32.3 ms 64 bytes from 8.8.8.8: icmp_req=4 ttl=56 time=23.2 ms ^C --- 8.8.8.8 ping statistics --- 4 packets transmitted, 3 received, 25% packet loss, time 3005ms rtt min/avg/max/mdev = 23.209/28.797/32.357/4.000 ms pi@raspberrypi ~ $ After I have set up the WiFi, I disconnect the monitor, keyboard and mouse, because I can now logon to the Raspberry Pi from my laptop by using SSH to the IP listed in the ifconfig output. I'm using the program Putty for the connection: - http://www.chiark.greenend.org.uk/~s.../download.html but any SSH-client can be used to connect to the device. |
#4
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
I'm doing most of my work in JavaScript these days. It's a good choice for doing anything, like web pages (all browsers run JavaScript), web server and web services (with node.js) and also robotics and RC with node.js.
To get Node.js (the runtime for JavaScript programs) onto the Raspberry, just run these two commands: 1. wget http://node-arm.herokuapp.com/node_latest_armhf.deb 2. sudo dpkg -i node_latest_armhf.deb Now, you can write a JavaScript program in a text file (e.g. myprogram.js) and run it with node.js like this - node myprogram.js |
#5
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Hi, Kevin!
Wow, 50 kg.. that's a heavy machine! :-) This one is at 30 kg currently, after adding 8 kg lead ballast. It's getting tricky to lift. How do you move yours? Stein :-) |
#6
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Just a couple of pictures showing the scale VS a 1/14 Bruder man:
|
#7
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Wiring the electronics:
I ended up buying the motor controllers and the Arduinos on Ebay. The Arduinos ar Nhduinos, a Chinese clone that is a bit cheaper than the original Arduino. Soldering the Monster motor shield: I think the motor shield usually ships without the through-hole components soldered. The ones I bought also came without the screw terminals, so I had to use some that I had laying around. I used a quite big one on the battery connector, so that I can add a standard XT60 connector and leads to it: I cut away the ISP header on the Arduino as it was in the way of the bigger screw terminal and I'm not going to use it anyway: The monster motor shield then snaps onto the Arduino. Adding a standard XT60 connector: This is how the motor controller connects to the Raspberry Pi (USB) and a gear motor: Adding a 3S LiPo battery and a 5V BEC. The standard servo connector on the BEC incidentally fits exactly onto the 5V header input on the Raspberry PI: Finally, adding the wireless gamepad and receiver. The setup isn't that different from a normal RC setup. In this picture, each of the components have the same role as their normal RC counterpart: - Remote control: Wireless gamepad - Receiver: Raspberry Pi - ESC: Monster motor shield - Battery: Battery - BEC: BEC - Motor: Motor To control six gear motors, I use three motor drivers. To control them all at the same time, I use a self-powered USB hub: And I made this crude power switch with three outputs: |
#8
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
To program the motor drivers so that they are Pololu Qik compatible (for the commands "GetDeviceId", "SetMotor1Speed" and "SetMotor2Speed"), follow these steps:
1. Connect the USB cable to a PC 2. Download the Arduino programmer: https://www.arduino.cc/en/Main/Software 3. Copy and paste the code below into the programming tool 4. Set the device ID on the second line (any number from 0 to 255, used to identify the controller later) I'm using device IDs 10, 11 and 12 for this build. 5. Click the "Upload" button Done! I also added a serial command timeout, which means that the motor driver will stop the motor if it has not received a motor command for one second. Usually the Raspberry Pi will send a motor command 50 times per second, but in the case it loses power or is disconnected for some reason, the motor will stop. I've not added current sensing or limiting yet. Code:
/* Based on the MonsterMoto Shield Example Sketch by: Jim Lindblom */ int deviceId = 10; #define BRAKEVCC 0 #define CW 1 #define CCW 2 #define BRAKEGND 3 #define CS_THRESHOLD 100 // VNH2SP30 pin definitions int inApin[2] = {7, 4}; // INA: Clockwise input int inBpin[2] = {8, 9}; // INB: Counter-clockwise input int pwmpin[2] = {5, 6}; // PWM input int cspin[2] = {2, 3}; // CS: Current sense ANALOG input int enpin[2] = {0, 1}; // EN: Status of switches output (Analog pin) // Serial state int inByte = 0; int command = 0; unsigned long lastCommandTime = 0; unsigned long timeoutMillis = 1000; void setup() { setPwmFrequency(5, 8); setPwmFrequency(6, 8); // Initialize digital pins as outputs for (int i=0; i<2; i++) { pinMode(inApin[i], OUTPUT); pinMode(inBpin[i], OUTPUT); pinMode(pwmpin[i], OUTPUT); } // Initialize motors braked motorGo(0, BRAKEGND, 0); motorGo(1, BRAKEGND, 0); // start serial port at 9600 bps: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } } void loop() { // if we get a valid byte, read analog ins: if (Serial.available() > 0) { // get incoming byte: inByte = Serial.read(); if (inByte > 127) command = inByte; else if (command != 0) { int speed = inByte * 2; // From 0-127 range to 0-254 range int motor = -1; int direction = CW; switch(command) { case 0x88: motor = 0; direction = CW; break; case 0x8A: motor = 0; direction = CCW; break; case 0x8C: motor = 1; direction = CW; break; case 0x8E: motor = 1; direction = CCW; break; case 0x83: motor = -1; Serial.write(deviceId); break; } if (motor != -1) { motorGo(motor, direction, speed); } command = 0; lastCommandTime = millis(); } } else { if (millis() - lastCommandTime > timeoutMillis) { motorGo(0, BRAKEGND, 0); motorGo(1, BRAKEGND, 0); } } // if ((analogRead(cspin[0]) < CS_THRESHOLD) && (analogRead(cspin[1]) < CS_THRESHOLD)) } /* motorGo() will set a motor going in a specific direction the motor will continue going in that direction, at that speed until told to do otherwise. motor: this should be either 0 or 1, will selet which of the two motors to be controlled direct: Should be between 0 and 3, with the following result 0: Brake to VCC 1: Clockwise 2: CounterClockwise 3: Brake to GND pwm: should be a value between 0 and 255 */ void motorGo(uint8_t motor, uint8_t direct, uint8_t pwm) { if (motor <= 1) { if (direct <=4) { // Set inA[motor] if (direct <=1) digitalWrite(inApin[motor], HIGH); else digitalWrite(inApin[motor], LOW); // Set inB[motor] if ((direct==0)||(direct==2)) digitalWrite(inBpin[motor], HIGH); else digitalWrite(inBpin[motor], LOW); analogWrite(pwmpin[motor], pwm); } } } /** * Divides a given PWM pin frequency by a divisor. * * The resulting frequency is equal to the base frequency divided by * the given divisor: * - Base frequencies: * o The base frequency for pins 3, 9, 10, and 11 is 31250 Hz. * o The base frequency for pins 5 and 6 is 62500 Hz. * - Divisors: * o The divisors available on pins 5, 6, 9 and 10 are: 1, 8, 64, * 256, and 1024. * o The divisors available on pins 3 and 11 are: 1, 8, 32, 64, * 128, 256, and 1024. * * PWM frequencies are tied together in pairs of pins. If one in a * pair is changed, the other is also changed to match: * - Pins 5 and 6 are paired on timer0 * - Pins 9 and 10 are paired on timer1 * - Pins 3 and 11 are paired on timer2 * * Note that this function will have side effects on anything else * that uses timers: * - Changes on pins 3, 5, 6, or 11 may cause the delay() and * millis() functions to stop working. Other timing-related * functions may also be affected. * - Changes on pins 9 or 10 will cause the Servo library to function * incorrectly. * * Thanks to macegr of the Arduino forums for his documentation of the * PWM frequency divisors. His post can be viewed at: * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235060559/0#4 */ void setPwmFrequency(int pin, int divisor) { byte mode; if(pin == 5 || pin == 6 || pin == 9 || pin == 10) { switch(divisor) { case 1: mode = 0x01; break; case 8: mode = 0x02; break; case 64: mode = 0x03; break; case 256: mode = 0x04; break; case 1024: mode = 0x05; break; default: return; } if(pin == 5 || pin == 6) { TCCR0B = TCCR0B & 0b11111000 | mode; } else { TCCR1B = TCCR1B & 0b11111000 | mode; } } else if(pin == 3 || pin == 11) { switch(divisor) { case 1: mode = 0x01; break; case 8: mode = 0x02; break; case 32: mode = 0x03; break; case 64: mode = 0x04; break; case 128: mode = 0x05; break; case 256: mode = 0x06; break; case 1024: mode = 0x7; break; default: return; } TCCR2B = TCCR2B & 0b11111000 | mode; } } |
#9
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
On the Raspberry PI I run the below code. I keep it in a file /home/pi/dev/excavator/control.js
To run this program automatically when the Raspberry Pi gets power applied, just add this one line to /etc/rc.local (just before the "exit 0" line): Code:
cd /home/pi/dev/excavator/ && sudo /usr/local/bin/node control.js & The contents of /home/pi/dev/excavator/control.js: Code:
var fs = require('fs'); // Set a deadzone of +/-0 (no deadzone) (out of +/-32k) and a sensitivty of 100 to reduce signal noise in joystick axis var joystick = new (require('joystick'))(0, 0, 100); // State / config var speeds = { leftTrack: { current: 0, wanted: 0, accel: 1 }, rightTrack: { current: 0, wanted: 0, accel: 1 }, swing: { current: 0, wanted: 0, accel: 1 }, boom: { current: 0, wanted: 0, accel: 1 }, stick: { current: 0, wanted: 0, accel: 1 }, bucket: { current: 0, wanted: 0, accel: 1 } } // Upate current speeds based on wanted speed from joystick and accelleration limits var accelInterval = 20; setInterval(function () { for (var propName in speeds) { if (speeds.hasOwnProperty(propName)) { var speed = speeds[propName]; var accel = speed.accel * accelInterval / 1000; if (Math.abs(speed.current - speed.wanted) < accel) { speed.current = speed.wanted; } else { speed.current += speed.current > speed.wanted ? -accel : accel; } } } }, accelInterval); var leftTrackReverse = false; var rightTrackReverse = false; // Read the remote control joystick.on('axis', function (event) { // console.log(JSON.stringify(event)); // Typical event: { time: 1585158, value: 8783, number: 0, type: 'axis', id: 0 } var value = event.value / 32768; // Now in the -1 -> 0 -> 1 range value = value * Math.abs(value); // Exponential switch (event.number) { case 0: speeds.swing.wanted = -value; break; // Left stick horizontal / swing case 1: speeds.stick.wanted = -value; break; // Left stick vertical / stick case 3: speeds.bucket.wanted = -value; break; // Rigth stick horizontal / bucket case 4: speeds.boom.wanted = -value; break; // Rigth stick verical / boom case 2: speeds.leftTrack.wanted = (leftTrackReverse ? -1 : 1) * ((value + 1) / 2); break; case 5: speeds.rightTrack.wanted = (rightTrackReverse ? -1 : 1) * ((value + 1) / 2); break; } }); joystick.on('button', function (event) { // console.log(JSON.stringify(event)); // Typical event: { time: 1607722, value: 0, number: 0, type: 'button', id: 0 } if (event.number === 4) { // Left top shoulder leftTrackReverse = event.value !== 0; } if (event.number === 5) { // Rigt top shoulder rightTrackReverse = event.value !== 0; } }); // The motor controllers var SerialPort = require("serialport").SerialPort; function startMotorControllerOn(devicePath) { var serialPort = new SerialPort(devicePath, { baudrate: 9600 }); serialPort.on('open', function () { serialPort.on('data', function (data) { var deviceId = data[0]; console.log('Got device id: ' + deviceId + ' from ' + devicePath); clearInterval(idInterval); setInterval(function () { var motor0Speed = 0; var motor1Speed = 0; switch (deviceId) { case 10: motor0Speed = speeds.leftTrack.current; motor1Speed = speeds.rightTrack.current; break; case 11: motor0Speed = speeds.swing.current; motor1Speed = speeds.boom.current; break; case 12: motor0Speed = speeds.stick.current; motor1Speed = speeds.bucket.current; break; } var cmd = motor0Speed >= 0 ? 0x88 : 0x8A; serialPort.write([cmd, Math.abs(motor0Speed) * 127]); cmd = motor1Speed >= 0 ? 0x8C : 0x8E; serialPort.write([cmd, Math.abs(motor1Speed) * 127]); // console.log(JSON.stringify({ d: deviceId, a: motor0Speed, b: motor1Speed})); }, 50); }); var idInterval = setInterval(function () { console.log('Sending request for device id... to ' + devicePath); serialPort.write([0x83, 0]); console.log('Sent request for device id... to ' + devicePath); }, 1000); }); } startMotorControllerOn('/dev/ttyUSB0'); startMotorControllerOn('/dev/ttyUSB1'); startMotorControllerOn('/dev/ttyUSB2'); |
#10
|
||||
|
||||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Stein,
Thanks for the great detail in your build thread! Jim |
#11
|
||||
|
||||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
This is awsome, I really enjoy seing the all electric builds and this one is top shelf.
Travis
__________________
AKA "00" Biddle RIP FreddyGearDrive 2-12-59/12-19-11 |
#12
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
|
#13
|
||||
|
||||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
<- This smiley pretty much sums up my ability to fully comprehend your elaborate programming code to make this beasty of a model function.
It's looking pretty good so far... it'll be even more interesting to see you get it dialed in for digging dirt. What's a rough calculation of the total investment so far with this innovative creation?
__________________
Sharing knowledge is one thing that defies basic arithmetic logic --- the more you share, the more you get! Joe |
#14
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Hi Lil Giants!
Quote:
Best regards, Stein :-) |
#15
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Hi all!
Thanks for all the comments! I've not posted many updates lately because I've started working on the finish that will go over the skeleton and make the excavator look more like the CAT 390F that is the basis for this model. Here is a sneak peak at my current design: Best regards, Stein :-) |
#16
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Your job is complete, thanks for links, and the instructions, etc.
Awesome! |
#17
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Very impressive craftsmanship!
|
#18
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
nice build and the links are very helpful
|
#19
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Question....
Will the gamepad/pc controller give you proportional control of the gearmotors or just on/off control? Nice build! |
#20
|
|||
|
|||
Re: 90 ton 1/14 metal excavator scratch build w/embedded PC
Hi Machfab!
> Will the gamepad/pc controller give you proportional control of the gearmotors or just on/off control? The gamepad gives full proportional control for all the gear motors, including the track motors. I'm using the front analog triggers for the track motors, and I use the two front buttons to reverse the track directions. The swing, boom, stick and bucket controls are on the two joysticks and equal to running a normal excavator (ISO-mode). This particular gamepad (the Logitech F710) doesn't stand back in sensitivity or accuracy in control from any of my normal RC transmitters. But most cheaper gamepads have less accurate analog control and also a larger deadspace in the middle / neutral position. I would say the pros and cons VS a normal RC transmitter: - Pros: Smaller, cheaper, 2 analog joysticks, 2 analog triggers, 1 digital four-directional pad and 10 digital buttons - Cons: Short range (10m), no telemetry Machfab, are you by any chance affiliated with http://machfabengineering.co.uk/ ? I just asking, because it would be interesting to get a quote on how much it would cost to get all the aluminum parts cut at a professional shop. I'd buy a set myself if someone could make it (depending on the price of course). Best regards, Stein :-) |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
|
|