We bought an electronic compass online so the boat will be able to use the compass in conjunction with the GPS to navigate to each way-point until it reaches its final destination. The compass is about 1/8 of the size of the red arduino uno base-plate. The first thing we did was find a code that we could fool around with to made the almighty program to use. We tried a few codes on the internet and they did not work, but then we found one on Adafruit. (thank you Adafruit). We wired it up according to the diagram below (it worked BTW). We had to calibrate the compass because of magnetic interferences (BTW the motor is a giant spinning magnet... That is a good example). We had to spin the boat 360 degrees and we took the measurements of each axis. This allowed us to calculate how much we had to subtract from the sensor values. (A.K.A fix the offset caused by interference). you can see this in the code below:
COMPASS: /*************************************************************************** These displays use I2C to communicate - following wiring: VCC to 5V GND to GND SCL to A5 SDA to A4 DRDY to n/a we took the adafruit magsensor example program and added a corrected x and y sensor output where we corrected the value to compensate for the offset in the field from local interference. You calculate the ofset as the average of the max and min when rotating the sensor through 360 degrees... ***************************************************************************/ #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_HMC5883_U.h> /* Assign a unique ID to this sensor at the same time */ Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345); float xcorrected, ycorrected; void displaySensorDetails(void) { sensor_t sensor; mag.getSensor(&sensor); Serial.println("------------------------------------"); Serial.print ("Sensor: "); Serial.println(sensor.name); Serial.print ("Driver Ver: "); Serial.println(sensor.version); Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" uT"); Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" uT"); Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" uT"); Serial.println("------------------------------------"); Serial.println(""); delay(500); } void setup(void) { Serial.begin(9600); Serial.println("HMC5883 Magnetometer Test"); Serial.println(""); /* Initialise the sensor */ if(!mag.begin()) { /* There was a problem detecting the HMC5883 ... check your connections */ Serial.println("Ooops, no HMC5883 detected ... Check your wiring!"); while(1); } /* Display some basic information on this sensor */ displaySensorDetails(); } void loop(void) { /* Get a new sensor event */ sensors_event_t event; mag.getEvent(&event); /* Display the results (magnetic vector values are in micro-Tesla (uT)) */ Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print(" "); Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print(" "); Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print(" ");Serial.println("uT"); // Hold the module so that Z is pointing 'up' and you can measure the heading with x&y // Calculate heading when the magnetometer is level, then correct for signs of axis. // float heading = atan2(event.magnetic.y, event.magnetic.x); // Calculate a new heading using the corrected x and y calibrated values xcorrected = event.magnetic.x - 18; ycorrected = event.magnetic.y + 62; float heading = atan2(ycorrected, xcorrected); // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location. // Find yours here: http://www.magnetic-declination.com/ // Mine is: -13* 2' W, which is ~13 Degrees, or (which we need) 0.22 radians // If you cannot find your Declination, comment out these two lines, your compass will be slightly off. float declinationAngle = 7/360 * 6.283; heading += declinationAngle; // Correct for when signs are reversed. if(heading < 0) heading += 2*PI; // Check for wrap due to addition of declination. if(heading > 2*PI) heading -= 2*PI; // Convert radians to degrees for readability. float headingDegrees = heading * 180/M_PI; Serial.print("Heading (degrees): "); Serial.println(headingDegrees); delay(500); } Some images:
0 Comments
The thing we fixed this time is more power issues. The only thing we really did was let one battery power everything. You see, before we had to have two batteries; One for the arduino, and the other for the motor. We fixed this now, and it only needs one battery now. We did this by allowing the LiPo battery flow through the motor, the servo (rudder) and then into the arduino. Another thing we did was the coding for the rudder AND the motor. This allows the thing to drive on its own. If we wanted to, we could have it drive right now and record it, but its winter and all the lakes are frozen... Maybe next time? Here's a video(s) of all the things we did Here's the code we used to program this:
#include <Servo.h> Servo ESC1; // create servo object to control a servo Servo rudder; // create servo object to control a servo // twelve servo objects can be created on most boards int throttle = 0; // variable to store the ESC throttle setting -- max 180, min 0 int pos = 0; // variable to store the servo position void setup() { rudder.attach(10); // attaches the servo on pin 10 to the servo object ESC1.attach(9); // attaches the servo on pin 9 to the servo object ESC1.write(180); // calibrate ESC -- max throttle delay(10000); // calibrate ESC -- plug in control wire then ESC LiPo during this 10 second delay ESC1.write(0); // calibrate ESC -- min throttle for 2 seconds (may be reverse) delay(2000); ESC1.write(90); // calibrate ESC -- mid throttle for 2 seconds (may be zero throttle if bi-directional) delay(2000); ESC1.write(0); // back to min throttle after calibration delay(2000); } void loop() { for (throttle = 0; throttle <= 180; throttle += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree ESC1.write(throttle); // tell servo to go to position in variable 'throttle' delay(20); // waits 20ms for the servo to reach the position } for (throttle = 180; throttle >= 0; throttle -= 1) { // goes from 180 degrees to 0 degrees ESC1.write(throttle); // tell servo to go to position in variable 'throttle' delay(20); // waits 20ms for the servo to reach the position } for (pos = 60; pos <= 120; pos += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree rudder.write(pos); // tell servo to go to position in variable 'pos' delay(10); // waits 10ms for the servo to reach the position } for (pos = 120; pos >= 60; pos -= 1) { // goes from 180 degrees to 0 degrees rudder.write(pos); // tell servo to go to position in variable 'pos' delay(10); // waits 10ms for the servo to reach the position } } so i figured that the best way to start this post was to... Just kidding. So now it is my turn to talk about the boat. 2 posts in one night! (I'm tired ok? Its an hour past when i usually fall asleep). Anyway i should do what my brother did. So actually in arduino code you call the motor by typing servo... Its strange... Why does it say the motor is a servo? No one knows just like a lot of things people don't know about arduino motor code. And that is exactly why i am typing this post out. So be ready to learn about some arduino stuff (even with computer-made photos of the wiring!). Programming We need to make the propellor spin by controlling the motor by sending commands to the ESC. There were a lot of unexpected steps like calibrating the ESC so it knew what maximum and minimum power would look like. We had to call the ESC with a servo command even though it's not a servo! That is because the ESC looks for the same kind of signal as a servo! It's called PWM. Look it up in your spare time! Building The nice diagram below was made with a program called "Fritzing". It worked perfectly except that it did not have an ESC in the parts library so we faked it. (don't tell...!) If you wire up our boat like this you are in business. Look at the captions to understand the picture. Code: ESC: #include <Servo.h> Servo ESC1; // create servo object to control a servo // twelve servo objects can be created on most boards int throttle = 0; // variable to store the ESC throttle setting -- max 180, min 0 void setup() { ESC1.attach(9); // attaches the servo on pin 9 to the servo object ESC1.write(180); // calibrate ESC -- max throttle delay(10000); // calibrate ESC -- plug in control wire then ESC LiPo during this 10 second delay ESC1.write(0); // calibrate ESC -- min throttle for 2 seconds (may be reverse) delay(2000); ESC1.write(90); // calibrate ESC -- mid throttle for 2 seconds (may be zero throttle if bi-directional) delay(2000); ESC1.write(0); // back to min throttle after calibration delay(2000); } void loop() { for (throttle = 0; throttle <= 180; throttle += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree ESC1.write(throttle); // tell servo to go to position in variable 'throttle' delay(20); // waits 20ms for the servo to reach the position } for (throttle = 180; throttle >= 0; throttle -= 1) { // goes from 180 degrees to 0 degrees ESC1.write(throttle); // tell servo to go to position in variable 'throttle' delay(20); // waits 20ms for the servo to reach the position } } Video Here is a quick video of what this code does it is important to start the program and then connect the control wire to the ESC, before connecting power to the ESC. PLEASE NOTE: This is almost like a demo. This is not the final code. It will only pulse the motors a few times. BYE!!!I figured the best way to start this post is to explain to you what a servo is. A servo can be put into multiple forms, but to explain it as what it generally is, we'll just say its a Robotic muscle. Servos can be like a joint (like a knee that can bend), a jaw opening and closing, or really anything that can move on a robot. Programming So in case you don't already know, we have a huge job of trying to program this boat to maneuver around the Great Lakes, and the way this boat steers around is by a rudder. This rudder, is controlled by a servo. It was actually quite challenging to do this, because we were confused on if we had enough power to run it properly from just our 5v Arduino. Building The build was quite simple. First, we had the laptop giving power to the arduino. The arduino basically told the servo everything, but we found out that we needed a power source for the servo, since the arduino failed to give enough power. So we added a battery for the servo, and the arduino told it to move and it was successful. Too complicated? Look at the picture below to get more confused or get explanations. Code: RUDDER: 1. #include <Servo.h> 2. 3. Servo myservo; // create servo object to control a servo 4. // twelve servo objects can be created on most boards 5. 6. int pos = 0; // variable to store the servo position 7. 8. void setup() { 9. myservo.attach(9); // attaches the servo on pin 9 to the servo object 10. } 11. 12. void loop() { 13. for (pos = 60; pos <= 120; pos += 1) { // goes from 60 degrees to 120 degrees 14. // in steps of 1 degree 16. myservo.write(pos); // tell servo to go to position in variable 'pos' 17. delay(10); // waits 10ms for the servo to reach the position 18. } 19. for (pos = 120; pos >= 60; pos -= 1) { // goes from 180 degrees to 0 degrees 20. myservo.write(pos); // tell servo to go to position in variable 'pos' 21. delay(10); // waits 10ms for the servo to reach the position 22. } 23. } Now I bet your REALLY confused when you looked at the code. from line 1 to line 11, its just setting things in place. Telling that the servo is at its natural position and that the servo is the rudder. The other lines make the servo move to the left and right just to test it. |
AuthorMalachi and Ezra's page where we build cool stuff and either break it, set fire to it, etc. in the name of science. Archives
August 2019
Categories
All
|