├── LICENSE ├── README.md ├── autonomous-rover ├── README.md └── images │ ├── EbayRover.jpg │ ├── EdgeDetectionTest.png │ ├── Rover1.png │ └── Rover2.png └── donkey-car ├── README.md ├── download ├── Magnet_Plate_v7.stl ├── Magnet_Roll_Cage_v2.stl └── OpenMV_Donkey_Mount.stl ├── images ├── build │ ├── step(1).jpg │ ├── step(1)small.jpg │ ├── step(10).jpg │ ├── step(10)small.jpg │ ├── step(11).jpg │ ├── step(11)small.jpg │ ├── step(12).jpg │ ├── step(12)small.jpg │ ├── step(13).jpg │ ├── step(13)small.jpg │ ├── step(14).jpg │ ├── step(14)small.jpg │ ├── step(15).jpg │ ├── step(15)small.jpg │ ├── step(16).jpg │ ├── step(16)small.jpg │ ├── step(17).jpg │ ├── step(17)small.jpg │ ├── step(18).jpg │ ├── step(18)small.jpg │ ├── step(19).jpg │ ├── step(19)small.jpg │ ├── step(2).jpg │ ├── step(2)small.jpg │ ├── step(20).jpg │ ├── step(20)small.jpg │ ├── step(21).jpg │ ├── step(21)small.jpg │ ├── step(22).jpg │ ├── step(22)small.jpg │ ├── step(23).jpg │ ├── step(23)small.jpg │ ├── step(24).jpg │ ├── step(24)small.jpg │ ├── step(25).jpg │ ├── step(25)small.jpg │ ├── step(26).jpg │ ├── step(26)small.jpg │ ├── step(27).jpg │ ├── step(27)small.jpg │ ├── step(28).jpg │ ├── step(28)small.jpg │ ├── step(29).jpg │ ├── step(29)small.jpg │ ├── step(3).jpg │ ├── step(3)small.jpg │ ├── step(30).jpg │ ├── step(30)small.jpg │ ├── step(31).jpg │ ├── step(31)small.jpg │ ├── step(32).jpg │ ├── step(32)small.jpg │ ├── step(33).jpg │ ├── step(33)small.jpg │ ├── step(34).jpg │ ├── step(34)small.jpg │ ├── step(35).jpg │ ├── step(35)small.jpg │ ├── step(36).jpg │ ├── step(36)small.jpg │ ├── step(37).jpg │ ├── step(37)small.jpg │ ├── step(38).png │ ├── step(39).png │ ├── step(4).jpg │ ├── step(4)small.jpg │ ├── step(40).jpg │ ├── step(40)small.jpg │ ├── step(41).png │ ├── step(42).png │ ├── step(43).png │ ├── step(44).png │ ├── step(5).jpg │ ├── step(5)small.jpg │ ├── step(6).jpg │ ├── step(6)small.jpg │ ├── step(7).jpg │ ├── step(7)small.jpg │ ├── step(8).jpg │ ├── step(8)small.jpg │ ├── step(9).jpg │ └── step(9)small.jpg ├── donkey-car-clean.jpg ├── donkey-car-raw.jpg ├── donkey-car-web.jpg └── parts │ ├── adapters.jpg │ ├── arduino.jpg │ ├── base.jpg │ ├── cage.jpg │ ├── camera-mount.jpg │ ├── camera.jpg │ ├── controller.jpg │ ├── extensions.jpg │ ├── headers.jpg │ ├── lipo-charger.jpg │ ├── lipo.jpg │ ├── long.jpg │ ├── magnet-car.jpg │ ├── male.jpg │ ├── musb.jpg │ ├── nuts.jpg │ ├── programmer.jpg │ ├── screws.jpg │ ├── servos.jpg │ ├── shorts.jpg │ ├── ties.jpg │ ├── uusb.jpg │ ├── wide.jpg │ └── wifi.jpg ├── line_follower_main.py ├── pca9685.py ├── servo.py ├── servo_controller └── servo_controller.ino └── video └── 10.20.2018.mp4 /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 OpenMV 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # OpenMV Proejcts 4 | 5 | A home for projects using the OpenMV Cam: 6 | 7 | * [Donkey Self-Driving Car - by OpenMV](donkey-car/README.md) 8 | * [Autonomous Rover - by: mjs513](autonomous-rover/README.md) 9 | -------------------------------------------------------------------------------- /autonomous-rover/README.md: -------------------------------------------------------------------------------- 1 | # Teensy 3.5/OpenMV Rover 2 | 3 | This project was based off a couple of other rover's that I built using multi-sonar sensors for obstacle detection and avoidance. Needless to say they eye sores with everything hanging off the platform. For many years wanted to do something with machine vision but most of the papers and projects used stereo vision vs monocular vision. This also required you to send back to the PC the image to process and then send the commands back. I wanted to keep the whole system closed on the rover platform with the need for any desktop software. That’s where the OpenMV camera came into play. Forgot how I found out about it but when I saw it I knew I was going to start another project. 4 | 5 | About the same time I found another project that used a web camera and OpenCV to identify objects and associated avoidance code. Peter Neal of [Big Face Robotics](https://bigfacerobotics.wordpress.com/2014/12/18/obstacle-detection-using-opencv/) describes the process as follows: 6 | >      The method I am using involves capturing an image, converting it to grayscale, blurring it slightly 7 | and then using canny edge detection to highlight the edges in the image. Using the edge detected image, starting from the left and moving 8 | along the width of the image in intervals, I scan from the bottom of the image until I reach a pixel that is white, indicating the first 9 | edge encountered. I am left with an array that contains coordinates of the first edges found in front of the robot. Using this array, I 10 | then look for changes in the direction of the slope of the edges that may indicate an object is present. At the moment I am ignoring 11 | anything in the top half of the image as anything found here will probably be far enough away from the robot to not be too concerned 12 | about. This will change depending on the angle of the head. If the head is looking down towards the ground, obviously everything in the 13 | scene may be of interest. With the changes of slope found, I then scan in both directions to try and find the edge of the object, 14 | indicated by a sharp change in values in the array of nearest edges. 15 | 16 | With the help of Nyamekye over at OpenMV I was able to implement a similar method. Instead of changing the head angle, as Mr. Neal does, I determined the center position of large gaps (you can specify the gap size in pixels in the code) and found the center point. Using this I was able to determing the angluar position in the FOV and then transmitted over the OpenMV UART to the Teensy 3.5 which does the rest. I did add WiFi capabality to send the images but it slows the frame rate down too much. The results of this process is illustrated in following figure: 17 | 18 | ![EdgeDetection Test](https://github.com/mjs513/TeensyOpenMV/blob/master/images/EdgeDetectionTest.png) 19 | 20 | Now for the Rover design itself. I used an off the shelf tracked chasis that I picked up off ebay quite a while ago. Couldn't find the link to the exact one that i am using but a similar one is still available, http://www.ebay.com/itm/Tracked-Robot-Smart-Car-Platform-Aluminum-alloy-Chassis-with-Dual-DC-9V-Motor-/282615264298?hash=item41cd2eb42a:g:~FQAAOSw3ntZkVza . One of the nice things about the chasis is that it had a Hall Effector Sensor that I could use for odometry. A little different than the quad encoders but usuable. 21 | 22 | Angular information is passed to the T3.5 which does the Obstacle avoidance stuff. It uses a single VL53L0X TOF sensor for distance measures, a BN055 for orientation which is used for turn control once the obstacle free direction is picked, a RC TX/Receiver and a RF module for telemetry and commands. As in my other project it has an odometry module for relative tracking based on the hall effect sensors on the motors (fixed the errors in my other code). It also has a manual mode for just sending motor commands. The odometry module receives manual commands individually in the format fx, bx, ly,ry where x is distance you want to travel in cm's and y is the relative angle you want to turn. I also use odometry once a direction is picked by the detection algorithm and then move half that distance before another round of image analysis is performed. 23 | 24 | The whole thing is powered from a single 7.4 battery. For power to the OpenMV camera the battery power goes to a 3.3v Pololu regulator. 25 | 26 | I designed custom break out board for the T3.5 so it would fit on a Arduino Mega type foot print with a custom IO board where I break out where i can mount Arduino break out boards. In this case i use a Adafruit Motor Shield V2 to control the motors and a breadboard shield to hold a Adafruit TSL2561 light sensor. 27 | 28 | If the camera can not see an edge, can happen if it gets too close to walls the obstacle avoidance algorith Tuses a modified vfh/bubble alogithm is the camera can not detect edge which relies on the VL53 sensor to get distances. 29 | 30 | To see it in action check the video out, https://photos.app.goo.gl/JIc3378SOzJR2bSn1. Discussion of the process and challenges can be seen in the OpenMV forum. 31 | 32 | Source Code and this readme is found on the TeensyOpenMV github page: https://github.com/mjs513/TeensyOpenMV 33 | 34 | Here are a couple of screen shots of the rover: 35 | 1. http://forums.openmv.io/viewtopic.php?f=5&t=276 36 | 2. http://forums.openmv.io/viewtopic.php?f=6&t=393 37 | 38 | ![Front View](https://github.com/mjs513/TeensyOpenMV/blob/master/images/Rover2.png) 39 | ![Side View](https://github.com/mjs513/TeensyOpenMV/blob/master/images/Rover1.png) 40 | -------------------------------------------------------------------------------- /autonomous-rover/images/EbayRover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/autonomous-rover/images/EbayRover.jpg -------------------------------------------------------------------------------- /autonomous-rover/images/EdgeDetectionTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/autonomous-rover/images/EdgeDetectionTest.png -------------------------------------------------------------------------------- /autonomous-rover/images/Rover1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/autonomous-rover/images/Rover1.png -------------------------------------------------------------------------------- /autonomous-rover/images/Rover2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/autonomous-rover/images/Rover2.png -------------------------------------------------------------------------------- /donkey-car/README.md: -------------------------------------------------------------------------------- 1 | # Donkey Self-Driving Car 2 | 3 | This instructable shows off how to create a [DIY Robocar](https://diyrobocars.com/) forked off of the ["Donkey"](http://www.donkeycar.com/) Self-Driving car platform using the OpenMV Cam instead of the RaspberryPi. You can see the car in action in this video [here](https://youtu.be/Pm88BEz3upM). 4 | 5 | ![OpenMV Cam powered Donkey Car](images/donkey-car-web.jpg "OpenMV Cam powered Donkey Car") 6 | 7 | ## Parts 8 | 9 | The OpenMV Cam Donkey Car is designed to be easy to build out of parts that you can buy online and assemble together with basic tools. Below is the list of essential parts you'll need to build the self-driving car. 10 | 11 | Part Description | Part Link | Part Count | Part Cost 12 | ---------------- | --------- | ---------- | --------- 13 | 1/16 2.4Ghz Exceed RC Magnet Car
![1/16 2.4Ghz Exceed RC Magnet Car](images/parts/magnet-car.jpg "1/16 2.4Ghz Exceed RC Magnet Car") | https://www.amazon.com/2-4Ghz-Exceed-RC-Magnet-Electric/dp/9269803775 | 1 | $79.95 14 | Magnet Car Base Plate
![Magnet Car Base Plate](images/parts/base.jpg "Magnet Car Base Plate") | https://www.shapeways.com/product/6YD3XR9ND/magnet-car-base-plate

You can download the STL file for this part [here](download/Magnet_Plate_v7.stl).

*Magnet Base Plate by Adam Conway*. | 1 | $55.10 15 | Magnet Car Roll Cage
![Magnet Car Roll Cage](images/parts/cage.jpg "Magnet Car Roll Cage") | https://www.shapeways.com/product/74VXFV7AT/magnet-car-roll-cage

You can download the STL file for this part [here](download/Magnet_Roll_Cage_v2.stl).

*Magnet Car Roll Cage by Adam Conway*. | 1 | $66.92 16 | OpenMV Cam Donkey Mount
![OpenMV Cam Donkey Mount](images/parts/camera-mount.jpg "OpenMV Cam Donkey Mount") | https://www.shapeways.com/product/G7YQBUMRC/openmv-cam-donkey-mount

You can download the STL file for these parts [here](download/OpenMV_Donkey_Mount.stl).

*OpenMV Cam Donkey Mount by Chris Anderson*. | 1 | $21.18 17 | M2 Machine Screw Set
![M2 Machine Screw Set](images/parts/screws.jpg "M2 Machine Screw Set") | https://www.amazon.com/Glarks-280-Pieces-Phillips-Stainless-Assortment/dp/B01G0KRGXC | 1 | $11.89 18 | M3 35mm Machine Screws
![M3 35mm Machine Screws](images/parts/long.jpg "M3 35mm Machine Screws") | https://www.amazon.com/M3-3mm-0-50-Stainless-MonsterBolts/dp/B016YZTEB0 | 1 | $4.00 19 | M3 Machine Screw Nuts
![M3 Machine Screw Nuts](images/parts/nuts.jpg "M3 Machine Screw Nuts") | https://www.amazon.com/M3-0-5-3mm-Metric-Stainless-MonsterBolts/dp/B01528BPIU | 1 | $3.49 20 | 30 CM Servo Lead Extension Assemblies
![30 CM Servo Lead Extension Assemblies](images/parts/extensions.jpg "30 CM Servo Lead Extension Assemblies") | http://hobbyking.com/en_us/30cm-servo-lead-extention-jr-with-hook-26awg-5pcs-bag-1.html | 1 | $1.39 21 | OpenMV Cam M7
![OpenMV Cam M7](images/parts/camera.jpg "OpenMV Cam M7") | https://openmv.io/products/openmv-cam-m7

Note: You will need a soldering iron and solder to attach the pin headers for this part. | 1 | $65.00 22 | OpenMV Cam Servo Shield
![OpenMV Cam Servo Shield](images/parts/servos.jpg "OpenMV Cam Servo Shield") | https://openmv.io/products/servo-shield

Note: You will need a soldering iron and solder to attach the pin headers for this part. | 1 | $15.00 23 | Zip Ties
![Zip Ties](images/parts/ties.jpg "Zip Ties") | https://www.amazon.com/Cable-Zip-Ties-Fastening-Organization/dp/B01LPOB2JW | 1 | $9.99 24 | Micro USB Cable
![Micro USB Cable](images/parts/uusb.jpg "Micro USB Cable") | https://www.amazon.com/AmazonBasics-USB-Male-Micro-Cable/dp/B01EK87T9M | 1 | $5.99 25 | 26 | **Sub-Total $339.90** - However, if you can 3D print parts it's significantly cheaper to build the robocar. You may also have some of the above parts lying around (like the Micro USB cable). 27 | 28 | While the above parts list is all you need you may wish to instead control your robocar's servos using the below parts for an arduino based servo controller board which will allow you to control your robot remotely using the RC transmitter that comes with the magnet car. You don't need the servo shield above if you build your car using the below components. **I HEAVILY RECOMMEND THAT YOU BUY THE PARTS FOR THE ARDUINO SERVO SHIELD SO THAT YOU CAN CONTROL YOUR ROBOCAR THROTTLE REMOTELY. YOU WILL LIKELY IMMEDIATELY DAMAGE YOUR ROBOCAR WITHOUT IT BY ACCIDENTALLY DRIVING INTO A WALL!** 29 | 30 | Part Description | Part Link | Part Count | Part Cost 31 | ---------------- | --------- | ---------- | --------- 32 | 5V 16 MHz Arduino Pro Mini
![5V 16 MHz Arduino Pro Mini](images/parts/arduino.jpg "5V 16 MHz Arduino Pro Mini") | https://www.amazon.com/Arducam-Atmega328-Development-Compatible-Arduino/dp/B01981EBBA | 1 | $6.49 33 | Arduino Pro Mini Programmer
![Arduino Pro Mini Programmer](images/parts/programmer.jpg "Arduino Pro Mini Programmer") | https://www.amazon.com/Micro-Basic-Breakout-Module-Arduino/dp/B00N4MCS1A | 1 | $9.95 34 | Servo Controller Board
![Servo Controller Board](images/parts/controller.jpg "Servo Controller Board") | https://oshpark.com/shared_projects/2bKUWmbq

You can download the Gerber files for this part [here](https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/ab7a7db45c3c6b37bcca1d8fc84e26e4.zip).

*Servo Controller Board by Chris Anderson*. | 1 | $10.50 35 | Male Headers
![Male Headers](images/parts/male.jpg "Male Headers") | https://www.amazon.com/SamIdea-15-Pack-Straight-Connector-Prototype/dp/B01M9FCAXW

Note: You will need a soldering iron and solder to attach these pin headers to the above PCB. | 1 | $5.69 36 | 8-pin Stackable Headers
![8-pin Stackable Headers](images/parts/headers.jpg "8-pin Stackable Headers") | https://www.amazon.com/Venel-Electronic-Component-Stackable-Shields/dp/B071454KP1

Note: You will need a soldering iron and solder to attach these pin headers to the above PCB. | 1 | $5.08 37 | RC Receiver Servo Adapters
![RC Receiver Servo Adapters](images/parts/shorts.jpg "RC Receiver Servo Adapters") | https://www.amazon.com/Hobbypower-Futaba-Servo-Extension-Cable/dp/B00RVDVWTC | 1 | $4.49 38 | 39 | **Sub-Total $42.20** - You may have some of the above parts lying around. 40 | 41 | In addition to all of the above I **strongly** recommend that your purchase a wide angle lens for your OpenMV Cam. With the wide angle lens it's much easier for your self-driving car to make tight turns and not lose sight of the road ahead. Without it you *will* have to reduce your maximum speed in-order to make tight turns. 42 | 43 | Part Description | Part Link | Part Count | Part Cost 44 | ---------------- | --------- | ---------- | --------- 45 | OpenMV Cam Wide Angle Lens
![OpenMV Cam Wide Angle Lens](images/parts/wide.jpg "OpenMV Cam Wide Angle Lens") | https://openmv.io/products/ultra-wide-angle-lens | 1 | $15.00 46 | 47 | **Sub-Total $15.00** 48 | 49 | Moving on, for better performance I recommend that you purchase LiPo batteries, adapters, and a LiPo charger. The NiMh battery that comes with the Magnet Car will quickly run out of power making it hard for you to test for hours before a race on the same day. 50 | 51 | Part Description | Part Link | Part Count | Part Cost 52 | ---------------- | --------- | ---------- | --------- 53 | Turnigy 1300mAh 2S 20C LiPo Pack
![Turnigy 1300mAh 2S 20C LiPo Pack](images/parts/lipo.jpg "Turnigy 1300mAh 2S 20C LiPo Pack") | http://hobbyking.com/en_us/turnigy-1300mah-2s-20c-lipo-pack-suit-1-18th-truck.html | 3 | $10.03 54 | Tamiya Mini Female to XT60 Male Adapters
![Tamiya Mini Female to XT60 Male Adapters](images/parts/adapters.jpg "Tamiya Mini Female to XT60 Male Adapters") | http://hobbyking.com/en_us/female-mini-tamiya-gt-male-xt60-3pcs-bag.html | 1 | $3.36 55 | Turnigy E3 Compact 2S/3S Lipo Charger
![Turnigy E3 Compact 2S/3S Lipo Charger](images/parts/lipo-charger.jpg "Turnigy E3 Compact 2S/3S Lipo Charger") | http://hobbyking.com/en_us/turnigy-e3-compact-2s-3s-lipo-charger-100-240v-us-plug.html | 1 | $12.35 56 | 57 | **Sub-Total $45.77** 58 | 59 | Finally, for wireless programming I recommend that you purchase a WiFi shield for the OpenMV Cam. With the WiFi shield you'll be able to comfortably test your self-driving car from one position versus having to follow your car around tethered by a USB cable. 60 | 61 | Part Description | Part Link | Part Count | Part Cost 62 | ---------------- | --------- | ---------- | --------- 63 | OpenMV Cam WiFi Shield
![OpenMV Cam WiFi Shield](images/parts/wifi.jpg "OpenMV Cam WiFi Shield") | https://openmv.io/products/wifi-shield | 1 | $35.00 64 | 65 | *Note, as of 8/15/2017 wireless programming has not yet been implemented for the OpenMV Cam but it is coming soon.* 66 | 67 | **Sub-Total $35.00** 68 | 69 | ## Assembly 70 | 71 | Once you've purchased and received all the parts you want for your DIY Robocar above you can now build it. 72 | 73 | ![Parts](images/build/step(1)small.jpg "Parts") 74 | 75 | Note that you're going to need an exacto knife, a philips screw driver, pliers, a soldering iron, and some solder. 76 | 77 | ![Tools](images/build/step(2)small.jpg "Tools") 78 | 79 | ### Step 1 - Clean up parts: 80 | 81 | Your 3D printed parts are most-likely going to need some cleanup. Using the extaco knife remove any burs on the 3D printed parts and cleanout any excess material in any of the holes in the 3D printed parts. In particular, you're going to want to make sure to clear out material left over in the slots on the sides of the roll bar. 82 | 83 | ![De-bur](images/build/step(3)small.jpg "De-bur") 84 | 85 | Next, try to insert the 3D printed OpenMV Cam mount neck part into its holder. The parts are designed to fit snuggly so this takes a bit of work. If you're having trouble try widening the neck holder with a file. Since we want the most height for the camera you just need to get the neck mount in enough to line up the first set of holes. 86 | 87 | ![Insert](images/build/step(4)small.jpg "Insert") 88 | 89 | ### Step 2 - Assemble the body: 90 | 91 | The rollbar mounts to the base plate using three M2 screws and nuts - a pair for each leg on the rollbar. Feel free to use any M2 screw length that fits. Moving on, before mounting the rollbar to the base plate make sure the screw stands on the base plate are facing up. The screw stands are for a Raspberry Pi and a servo controller which we won't be using, but, the screw holes shouldn't be upside down if you want to mount something else on there later on. 92 | 93 | ![Body](images/build/step(5)small.jpg "Body") 94 | 95 | To attach the rollbar to the base plate you need to insert a nut into the slots on either side of the front two rollbar legs (note that the screws are inserted from the bottom of the base plate). You then have to keep the nuts in place while screwing in the M2 screws. Doing this isn't particularly easy. You may wish to use a tool to keep the nuts from spinning in their slots. 96 | 97 | ![Body](images/build/step(6)small.jpg "Body") 98 | 99 | After you've attached both of the front legs to the base plate you can then attach the third back leg. This should be rather easy as you can just press down on the nut from the top to keep it from spinning as you tighten the M2 screw from the bottom. 100 | 101 | ![Last](images/build/step(7)small.jpg "Last") 102 | 103 | Next, attach the OpenMV Cam neck holder mount to the top of the rollbar using four more medium-length M2 screws. Note that this will take some work since the screw holes are unlikely to lineup exactly. I recommend screwing in all four screws only a little bit to get them started first before screwing each one in all the way. 104 | 105 | ![Align](images/build/step(8)small.jpg "Align") 106 | 107 | Moving on, insert one of the long M3 screws in between the neck holder and the neck part's bottom hole. Use an M3 locknut afterwards to tighten the connection to make sure the neck part is stable. 108 | 109 | ![Lock](images/build/step(9)small.jpg "Lock") 110 | 111 | Now, attach the OpenMV Cam holder to the top of the neck part and use another long M3 screw and locknut secure the holder in place. Make sure to get the orientation right like in the picture below. 112 | 113 | ![Holder](images/build/step(10)small.jpg "Holder") 114 | 115 | Next, remove the plastic hood from your RC car. The hood is held on by four metal pin clips. After removing the hood you should see the guts of your RC car like in the image below. We'll mount the base onto the four posts on your RC car. To secure the base we'll use the same metal clips the hood was held on with. However, we'll have to put some effort into doing this since cutouts on the base to secure the base to the RC car are tight. 116 | 117 | ![Hood](images/build/step(11)small.jpg "Hood") 118 | 119 | So first, bend the four metal clips slightly so we can more easily get them through the holes in the mounting stands after we've attached the base. 120 | 121 | ![Clip](images/build/step(12)small.jpg "Clip") 122 | 123 | Afterwards, cut away material using your exacto knife from the groves in the base to make space for the metal pins to go through the stand holes. 124 | 125 | ![Exacto](images/build/step(13)small.jpg "Exacto") 126 | 127 | Finally, push each pin through each stand hole to firmly attach the base to the RC Car. 128 | 129 | ![Attach](images/build/step(14)small.jpg "Attach") 130 | 131 | Once you've finished this your car should look like this below. 132 | 133 | ![Done](images/build/step(15)small.jpg "Done") 134 | 135 | ### Step 3 - Assemble the head: 136 | 137 | Now we're going to assemble the OpenMV Cam head of your Robocar. First, remove the lens mount from your OpenMV Cam using a screw driver and clean off the camera IC under the lens mount using some isopropyl alcohol and a Q-Tip. Make sure to get off any dirt and don't leave any fibers on the camera IC. 138 | 139 | ![Clean-up](images/build/step(16)small.jpg "Clean-up") 140 | 141 | Then reattach the lens mount. Next, we need to solder the pin headers onto the OpenMV Cam that it comes with. Using a soldering iron attach the two 8-pin headers on each side of the camera so that the 8-pin header legs are sticking out the back of the OpenMV Cam. 142 | 143 | ![Legs](images/build/step(17)small.jpg "Legs") 144 | 145 | Finally, if you bought the wide angle lens above replace the lens that your OpenMV Cam comes with the wide angle lens. 146 | 147 | ![Lens](images/build/step(18)small.jpg "Lens") 148 | 149 | Next, let's build up the servo shield for your OpenMV Cam so that it can control the RC car. 150 | 151 | ![Shield](images/build/step(19)small.jpg "Shield") 152 | 153 | You need to solder on the two 8-pin headers on either side of the servo controller board with the pin legs facing down. Then, solder on the two servo connection headers. The plastic parts on each header should be vertical and not flat against the servo controller board. 154 | 155 | ![Soldered](images/build/step(20)small.jpg "Soldered") 156 | 157 | If you bought a WiFi shield let's build that up too. Solder the two 8-pin headers it came with on either side of it with the legs facing down. 158 | 159 | ![WiFi](images/build/step(21)small.jpg "WiFi") 160 | 161 | Finally, let's stack everything up. You can mount shields on the OpenMV Cam from either the top or bottom of the board. But, let's put the WiFi shield on the bottom of the OpenMV Cam and the servo shield on the top. 162 | 163 | ![Stack](images/build/step(22)small.jpg "Stack") 164 | 165 | ### Step 4 - Putting it together: 166 | 167 | Attach the OpenMV Cam using it's two screw mounting holes to the OpenMV Cam mount on the top of the robocar body. To give ourselves more freedom we're mounting the OpenMV Cam upside down. You'll be able to un-rotate the OpenMV Cam's field of view in software. 168 | 169 | ![Mounting](images/build/step(23)small.jpg "Mounting") 170 | 171 | Next, using the servo extension headers attach channels 0 and 1 from the servo shield to the throttle and steering servo wires respectively. Make sure to thread the servo extension wires through the hole in the base plate. Also, use the zip ties to tie down all your wires so they aren't swaying everywhere. You don't want your robocar accidentally destroying itself by running over one of its wires. Your car should like the picture below once done. 172 | 173 | ![Controller](images/build/step(24)small.jpg "Controller") 174 | 175 | Finally, put the black tube that comes with your RC Car over the antenna to protect the antenna. 176 | 177 | ![Antenna](images/build/step(25)small.jpg "Antenna") 178 | 179 | If you bought the LiPo battery upgrade parts let's install those next. First, attach the XT60 adapters to each LiPo battery. 180 | 181 | ![Adapters](images/build/step(26)small.jpg "Adapters") 182 | 183 | Then, replace the NiMh battery on your RC car with one of the LiPo batteries. Make sure to place the battery with the wires going towards the front of the car like in the picture below. 184 | 185 | ![Lipo](images/build/step(27)small.jpg "Lipo") 186 | 187 | After your done it should look like the picture below. 188 | 189 | ![Done](images/build/step(28)small.jpg "Done") 190 | 191 | **LAST, MAKE SURE TO MOVE THE JUMPER ON YOUR ESC TO THE LIPO POSITION TOO!** 192 | 193 | ![Danger](images/build/step(29)small.jpg "Danger") 194 | 195 | ### Step 5 - Installing the software: 196 | 197 | Because you're using the OpenMV Cam this is going to be the easiest part. Download OpenMV IDE from [here](https://openmv.io/pages/download) and install it on your laptop. Once that's done attach the micro USB cable to your OpenMV Cam and to your laptop. 198 | 199 | ![OpenMV_Cam](images/build/step(40)small.jpg "OpenMV_Cam") 200 | 201 | Next, launch OpenMV IDE and hit the connect button the bottom left hand corner of the IDE. After doing so OpenMV IDE should display on the bottom right hand corner that your OpenMV Cam's firmware is out-of-date. 202 | 203 | ![Update](images/build/step(41).png "Update") 204 | 205 | Click on the text and walk through the dialog to update your OpenMV Cam's firmware. When OpenMV IDE asks you if you want to erase the OpenMV Cam's flash drive select yes. Afterwards, OpenMV IDE will update your OpenMV Cam's firmware. Note that your OpenMV Cam is unbrickable, so, if anything goes wrong you can recover. 206 | 207 | ![Firmware](images/build/step(42).png "Firmware") 208 | 209 | Now that your OpenMV Cam is updated. You need to focus the lens. Please run the hello world script (click the green run arrow) and turn the lens until the picture comes into focus on the frame buffer viewer in OpenMV IDE. 210 | 211 | ![View](images/build/step(43).png "View") 212 | 213 | After doing all of this download the code for the robocar [here](https://github.com/openmv/openmv-projects/blob/master/donkey-car/line_follower_main.py) and open the script in OpenMV IDE. How the script works is documented in the comments. Note that you need to set the ``ARDUINO_SERVO_CONTROLLER_ATTACHED`` variable to ``True`` for the OpenMV Cam to output serial data to control the Arduino Servo Controller Shield and ``False`` for the OpenMV Cam to output serial data to control the Servo Controller Shield (the non-Arduino one). 214 | 215 | ![Script](images/build/step(44).png "Script") 216 | 217 | Finally, once you're done tweaking settings go to ``Tools->Save open script to OpenMV Cam`` and save the script while keeping comments. Then click ``Tools->Reset OpenMV Cam``. You can now disconnect your OpenMV Cam from your laptop and it will run the script by itself. Follow the above two steps each time you want your OpenMV Cam to run the script without the laptop attached to it. For quick testing and debug while your laptop is connected just use the run button and stop button to start and stop the script between edits. 218 | 219 | *If you're using the Servo Controller Shield (the non-Arduino one), you also need to copy two scripts from OpenMV IDE to the OpenMV Cam board for things to work. Please go to ``Files->Examples->15-Servo-Shield->pca9865.py`` and save it on your OpenMV Cam's internal flash drive. Additionally, you also need to save ``Files->Examples->15-Servo-Shield->servo.py`` on your OpenMV Cam's internal flash drive. These two steps only need to be done once (You can also get these two scripts from the directory where this README is located).* 220 | 221 | ### Optional Step 1 - Building the Arduino based Servo Controller: 222 | 223 | If you opted to get the Arduino based Servo Controller so you can use your RC controller to act as a kill switch for your robocar (which is a **VERY** good idea) here's how to build it. 224 | 225 | ![Parts](images/build/step(30)small.jpg "Parts") 226 | 227 | First, solder up the Arduino Pro Mini like the image below. 228 | 229 | ![Arduino](images/build/step(31)small.jpg "Arduino") 230 | 231 | Next, solder the Arduino onto the ``123D Circuits`` circuits main board like below. We're trying to mount this onto the back of the OpenMV Cam board so the layout looks a little bit reversed. Just copy what's in the image below. 232 | 233 | ![Controller](images/build/step(32)small.jpg "Controller") 234 | 235 | It should look like this on the bottom. 236 | 237 | ![Bottom](images/build/step(33)small.jpg "Bottom") 238 | 239 | Now, mount the board onto the back of the OpenMV Cam shield stack-up. Note that we don't need the extra length of the board connectors coming out of the back. Feel free to trim them if you like. Or, leave them on to stack more boards. If you decide to leave them on make sure they don't short with each other. 240 | 241 | ![Stack-up](images/build/step(34)small.jpg "Stack-up") 242 | 243 | Finally, let's connect the steering servo to channel (1) on the Arduino, the throttle servo to channel (2), the RC radio receiver steering output to channel (3), and the RC radio receiver throttle output to channel (4). Note that the RC radio receiver's steering output is channel (1) and its throttle output is channel (2). Also, you're going to need to use the short-length female-to-female RC servo wire extension cables and long extension cables to wire up the RC radio receiver to the Arduino Servo Controller board. 244 | 245 | ![Wire](images/build/step(35)small.jpg "Wire") 246 | 247 | Once you're finished with all of this your robot should look like this below. Note that you should use the cable ties to clean-up the wiring job. 248 | 249 | ![Done](images/build/step(36)small.jpg "Done") 250 | 251 | ### Optional Step 2 - Programming the Arduino based Servo Controller: 252 | 253 | Connect the USB to serial adapter to the 6-pin header sticking out of the top on your Arduino Pro Mini. Make sure to connect ``GND`` to ``GND`` and ``DTR`` to ``DTR``. Next, connect the micro USB cable to the USB to serial converter and your laptop. 254 | 255 | ![Programmer](images/build/step(37)small.jpg "Programmer") 256 | 257 | Install the Arduino IDE from [here](https://www.arduino.cc/en/Main/Software). Download the servo controller code from [here](https://github.com/openmv/openmv-projects/blob/master/donkey-car/servo_controller/servo_controller.ino) and open it using the Arduino IDE. Go to ``Tools->Board`` and select ``Arduino Pro or Arduino Pro Mini`` and ``Tools->Processor`` and select ``Atmega328 (5V, 16Mhz)`` . 258 | 259 | ![Arduino_IDE](images/build/step(38).png "Arduino_IDE") 260 | 261 | Finally, go to ``Tools->Port`` and select the COM port your USB to serial convert is connected to (it's usually the highest numbered COM port) and then click the upload button (round right arrow). The Arduino IDE should then compile the code and start programming the Arduino Pro Mini. Once it's finished remove the USB to serial converter from your Arduino Pro Mini and your servo controller board will be ready to use. 262 | 263 | ![Arduino_IDE_Done](images/build/step(39).png "Arduino_IDE_Done") 264 | 265 | The Arduino Servo Controller board allows you to directly control the robot's throttle and steering when the OpenMV Cam isn't running using the RC transmitter. Once the OpenMV Cam starts running and sending commands to the Arduino the Arduino will only drive the steering servo if the RC transmitter is on and will only drive the throttle if the RC transmitter throttle trigger is engaged (either for going forward or backwards). At any time you can use the steering control on the RC transmitter to override the OpenMV Cam steering. Finally, for fully autonomous control just adjust the throttle trim knob on the RC transmitter after turning it on with the throttle trim knob set to zero. Make sure to set the throttle trim knob back to zero after turning off the RC transmitter. 266 | 267 | ## How does the robocar follow the line? 268 | 269 | The OpenMV Cam uses linear regression to detect where the line is and then follow it. With the OpenMV Cam the machine vision part is simple. Most of the work the script the OpenMV Cam is running has to do with turning the line detection into servo outputs to control the robocar. You can read more about what's going on at the blog post [here](https://openmv.io/blogs/news/linear-regression-line-following). 270 | -------------------------------------------------------------------------------- /donkey-car/download/Magnet_Plate_v7.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/download/Magnet_Plate_v7.stl -------------------------------------------------------------------------------- /donkey-car/download/Magnet_Roll_Cage_v2.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/download/Magnet_Roll_Cage_v2.stl -------------------------------------------------------------------------------- /donkey-car/images/build/step(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(1).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(1)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(1)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(10).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(10).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(10)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(10)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(11).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(11).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(11)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(11)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(12).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(12).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(12)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(12)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(13).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(13).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(13)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(13)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(14).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(14).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(14)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(14)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(15).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(15).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(15)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(15)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(16).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(16).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(16)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(16)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(17).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(17).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(17)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(17)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(18).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(18).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(18)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(18)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(19).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(19).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(19)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(19)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(2).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(2).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(2)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(2)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(20).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(20).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(20)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(20)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(21).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(21).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(21)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(21)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(22).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(22).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(22)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(22)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(23).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(23).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(23)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(23)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(24).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(24).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(24)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(24)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(25).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(25).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(25)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(25)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(26).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(26).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(26)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(26)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(27).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(27).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(27)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(27)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(28).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(28).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(28)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(28)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(29).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(29).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(29)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(29)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(3).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(3).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(3)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(3)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(30).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(30).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(30)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(30)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(31).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(31).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(31)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(31)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(32).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(32).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(32)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(32)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(33).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(33).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(33)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(33)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(34).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(34).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(34)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(34)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(35).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(35).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(35)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(35)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(36).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(36).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(36)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(36)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(37).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(37).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(37)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(37)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(38).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(38).png -------------------------------------------------------------------------------- /donkey-car/images/build/step(39).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(39).png -------------------------------------------------------------------------------- /donkey-car/images/build/step(4).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(4).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(4)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(4)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(40).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(40).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(40)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(40)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(41).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(41).png -------------------------------------------------------------------------------- /donkey-car/images/build/step(42).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(42).png -------------------------------------------------------------------------------- /donkey-car/images/build/step(43).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(43).png -------------------------------------------------------------------------------- /donkey-car/images/build/step(44).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(44).png -------------------------------------------------------------------------------- /donkey-car/images/build/step(5).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(5).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(5)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(5)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(6).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(6).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(6)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(6)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(7).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(7).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(7)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(7)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(8).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(8).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(8)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(8)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(9).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(9).jpg -------------------------------------------------------------------------------- /donkey-car/images/build/step(9)small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/build/step(9)small.jpg -------------------------------------------------------------------------------- /donkey-car/images/donkey-car-clean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/donkey-car-clean.jpg -------------------------------------------------------------------------------- /donkey-car/images/donkey-car-raw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/donkey-car-raw.jpg -------------------------------------------------------------------------------- /donkey-car/images/donkey-car-web.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/donkey-car-web.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/adapters.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/adapters.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/arduino.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/arduino.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/base.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/base.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/cage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/cage.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/camera-mount.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/camera-mount.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/camera.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/camera.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/controller.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/controller.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/extensions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/extensions.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/headers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/headers.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/lipo-charger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/lipo-charger.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/lipo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/lipo.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/long.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/long.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/magnet-car.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/magnet-car.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/male.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/musb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/musb.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/nuts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/nuts.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/programmer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/programmer.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/screws.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/screws.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/servos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/servos.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/shorts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/shorts.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/ties.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/ties.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/uusb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/uusb.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/wide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/wide.jpg -------------------------------------------------------------------------------- /donkey-car/images/parts/wifi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/images/parts/wifi.jpg -------------------------------------------------------------------------------- /donkey-car/line_follower_main.py: -------------------------------------------------------------------------------- 1 | # This file is part of the OpenMV project. 2 | # Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman 3 | # Support for OpenMV Motor Shield by Chris Anderson, DIY Robocars 4 | # This work is licensed under the MIT license, see the file LICENSE for details. 5 | 6 | import sensor, image, time, math, pyb 7 | 8 | 9 | ########### 10 | # Settings 11 | ########### 12 | 13 | COLOR_LINE_FOLLOWING = True # False to use grayscale thresholds, true to use color thresholds. 14 | COLOR_THRESHOLDS = [( 94, 100, -27, 1, 20, 127)] # Yellow Line. 15 | GRAYSCALE_THRESHOLDS = [(240, 255)] # White Line. 16 | COLOR_HIGH_LIGHT_THRESHOLDS = [(80, 100, -10, 10, -10, 10)] 17 | GRAYSCALE_HIGH_LIGHT_THRESHOLDS = [(250, 255)] 18 | BINARY_VIEW = False # Helps debugging but costs FPS if on. 19 | DO_NOTHING = False # Just capture frames... 20 | FRAME_SIZE = sensor.QQVGA # Frame size. 21 | FRAME_REGION = 0.75 # Percentage of the image from the bottom (0 - 1.0). 22 | FRAME_WIDE = 1.0 # Percentage of the frame width. 23 | 24 | AREA_THRESHOLD = 0 # Raise to filter out false detections. 25 | PIXELS_THRESHOLD = 40 # Raise to filter out false detections. 26 | MAG_THRESHOLD = 4 # Raise to filter out false detections. 27 | MIXING_RATE = 0.9 # Percentage of a new line detection to mix into current steering. 28 | 29 | # Tweak these values for your robocar. 30 | THROTTLE_CUT_OFF_ANGLE = 1.0 # Maximum angular distance from 90 before we cut speed [0.0-90.0). 31 | THROTTLE_CUT_OFF_RATE = 0.5 # How much to cut our speed boost (below) once the above is passed (0.0-1.0]. 32 | THROTTLE_GAIN = 0.0 # e.g. how much to speed up on a straight away 33 | THROTTLE_OFFSET = 30.0 # e.g. default speed (0 to 100) 34 | THROTTLE_P_GAIN = 1.0 35 | THROTTLE_I_GAIN = 0.0 36 | THROTTLE_I_MIN = -0.0 37 | THROTTLE_I_MAX = 0.0 38 | THROTTLE_D_GAIN = 0.0 39 | 40 | # Tweak these values for your robocar. 41 | STEERING_OFFSET = 90 # Change this if you need to fix an imbalance in your car (0 to 180). 42 | STEERING_P_GAIN = -15.0 # Make this smaller as you increase your speed and vice versa. 43 | STEERING_I_GAIN = 0.0 44 | STEERING_I_MIN = -0.0 45 | STEERING_I_MAX = 0.0 46 | STEERING_D_GAIN = -12 # Make this larger as you increase your speed and vice versa. 47 | 48 | # Selects motor/servo controller method... 49 | ARDUINO_SERVO_CONTROLLER = False 50 | NATIVE_SERVO_CONTROLLER = True 51 | NATIVE_MOTOR_CONTROLLER = False 52 | 53 | # Tweak these values for your robocar if you're using servos. 54 | THROTTLE_SERVO_MIN_US = 1500 55 | THROTTLE_SERVO_MAX_US = 2000 56 | 57 | # Tweak these values for your robocar. 58 | STEERING_SERVO_MIN_US = 700 59 | STEERING_SERVO_MAX_US = 2300 60 | 61 | ########### 62 | # Setup 63 | ########### 64 | 65 | FRAME_REGION = max(min(FRAME_REGION, 1.0), 0.0) 66 | FRAME_WIDE = max(min(FRAME_WIDE, 1.0), 0.0) 67 | MIXING_RATE = max(min(MIXING_RATE, 1.0), 0.0) 68 | 69 | THROTTLE_CUT_OFF_ANGLE = max(min(THROTTLE_CUT_OFF_ANGLE, 89.99), 0) 70 | THROTTLE_CUT_OFF_RATE = max(min(THROTTLE_CUT_OFF_RATE, 1.0), 0.01) 71 | 72 | THROTTLE_OFFSET = max(min(THROTTLE_OFFSET, 100), 0) 73 | STEERING_OFFSET = max(min(STEERING_OFFSET, 180), 0) 74 | 75 | # Handle if these were reversed... 76 | tmp = max(THROTTLE_SERVO_MIN_US, THROTTLE_SERVO_MAX_US) 77 | THROTTLE_SERVO_MIN_US = min(THROTTLE_SERVO_MIN_US, THROTTLE_SERVO_MAX_US) 78 | THROTTLE_SERVO_MAX_US = tmp 79 | 80 | # Handle if these were reversed... 81 | tmp = max(STEERING_SERVO_MIN_US, STEERING_SERVO_MAX_US) 82 | STEERING_SERVO_MIN_US = min(STEERING_SERVO_MIN_US, STEERING_SERVO_MAX_US) 83 | STEERING_SERVO_MAX_US = tmp 84 | 85 | device = None 86 | 87 | if ARDUINO_SERVO_CONTROLLER: 88 | device = pyb.UART(3, 19200, timeout_char = 1000) 89 | 90 | if NATIVE_SERVO_CONTROLLER: 91 | import servo 92 | import machine 93 | device = servo.Servos(machine.I2C(sda = machine.Pin("P5"), scl = machine.Pin("P4")), address = 0x40, freq = 50) 94 | 95 | if NATIVE_MOTOR_CONTROLLER: 96 | from pyb import Pin, Timer 97 | 98 | # these are motor driver pins, which set the direction of each motor 99 | pinADir0 = pyb.Pin('P0', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE) 100 | pinADir1 = pyb.Pin('P1', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE) 101 | pinBDir0 = pyb.Pin('P2', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE) 102 | pinBDir1 = pyb.Pin('P3', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE) 103 | 104 | # Dir0/1 must be not equal to each other for forward or backwards 105 | # operation. If they are equal then that's a brake operation. 106 | # If they are not equal then the motor will spin one way other the 107 | # other depending on its hookup and the value of channel 0. 108 | 109 | pinBDir0.value(0) 110 | pinBDir1.value(1) 111 | 112 | tim = Timer(4, freq=1000) # Frequency in Hz 113 | ch1 = tim.channel(1, pyb.Timer.PWM, pin=pyb.Pin("P7")) 114 | ch2 = tim.channel(2, pyb.Timer.PWM, pin=pyb.Pin("P8")) 115 | cruise_speed = 50 116 | radians_degrees = 57.3 # constant to convert from radians to degrees 117 | steering_direction = 1 # use this to reverse the steering if your car goes in the wrong direction 118 | steering_gain = 1.0 # calibration for your car's steering sensitivity 119 | steering_center = 0 # set to your car's steering center point 120 | 121 | def constrain(value, min, max): 122 | if value < min : 123 | return min 124 | if value > max : 125 | return max 126 | else: 127 | return value 128 | 129 | def steer(throttle, angle): 130 | global steering_gain, cruise_speed, steering_center 131 | angle = int(round(angle+steering_center)) 132 | angle = constrain(angle, 0, 180) 133 | angle = angle - 90 134 | angle = radians_degrees * math.tan(angle/radians_degrees) # take the tangent to create a non-linear response curver 135 | angle = angle * steering_gain 136 | print ("Calculated angle", angle) 137 | left = angle*steering_direction + throttle + cruise_speed 138 | left = constrain (left, 0, 100) 139 | right = -1*angle*steering_direction + throttle + cruise_speed 140 | right = constrain (right, 0, 100) 141 | print ("left: ", left) 142 | print ("right: ", right) 143 | # Generate a 1KHz square wave on TIM4 with each channel 144 | ch1.pulse_width_percent(left) 145 | ch2.pulse_width_percent(right) 146 | 147 | 148 | # This function maps the output of the linear regression function to a driving vector for steering 149 | # the robocar. See https://openmv.io/blogs/news/linear-regression-line-following for more info. 150 | 151 | old_cx_normal = None 152 | def figure_out_my_steering(line, img): 153 | global old_cx_normal 154 | 155 | # Rho is computed using the inverse of this code below in the actual OpenMV Cam code. 156 | # This formula comes from the Hough line detection formula (see the wikipedia page for more). 157 | # Anyway, the output of this calculations below are a point centered vertically in the middle 158 | # of the image and to the left or right such that the line goes through it (cx may be off the image). 159 | cy = img.height() / 2 160 | cx = (line.rho() - (cy * math.sin(math.radians(line.theta())))) / math.cos(math.radians(line.theta())) 161 | 162 | # "cx_middle" is now the distance from the center of the line. This is our error method to stay 163 | # on the line. "cx_normal" normalizes the error to something like -1/+1 (it will go over this). 164 | cx_middle = cx - (img.width() / 2) 165 | cx_normal = cx_middle / (img.width() / 2) 166 | # Note that "cx_normal" may be larger than -1/+1. When the value is between -1/+1 this means the 167 | # robot is driving basically straight and needs to only turn lightly left or right. When the value 168 | # is outside -1/+1 it means you need to turn VERY hard to the left or right to get back on the 169 | # line. This maps to the case of the robot driving into a horizontal line. "cx_normal" will 170 | # then approach -inf/+inf depending on how horizontal the line is. What's nice is that this 171 | # is exactly the behavior we want and it gets up back on the line! 172 | 173 | if old_cx_normal != None: old_cx_normal = (cx_normal * MIXING_RATE) + (old_cx_normal * (1.0 - MIXING_RATE)) 174 | else: old_cx_normal = cx_normal 175 | return old_cx_normal 176 | 177 | # Solve: THROTTLE_CUT_OFF_RATE = pow(sin(90 +/- THROTTLE_CUT_OFF_ANGLE), x) for x... 178 | # -> sin(90 +/- THROTTLE_CUT_OFF_ANGLE) = cos(THROTTLE_CUT_OFF_ANGLE) 179 | t_power = math.log(THROTTLE_CUT_OFF_RATE) / math.log(math.cos(math.radians(THROTTLE_CUT_OFF_ANGLE))) 180 | 181 | def figure_out_my_throttle(steering): # steering -> [0:180] 182 | 183 | # pow(sin()) of the steering angle is only non-zero when driving straight... e.g. steering ~= 90 184 | t_result = math.pow(math.sin(math.radians(max(min(steering, 179.99), 0.0))), t_power) 185 | 186 | return (t_result * THROTTLE_GAIN) + THROTTLE_OFFSET 187 | 188 | # 189 | # Servo Control Code 190 | # 191 | 192 | 193 | 194 | # throttle [0:100] (101 values) -> [THROTTLE_SERVO_MIN_US, THROTTLE_SERVO_MAX_US] 195 | # steering [0:180] (181 values) -> [STEERING_SERVO_MIN_US, STEERING_SERVO_MAX_US] 196 | def set_servos(throttle, steering): 197 | if NATIVE_MOTOR_CONTROLLER: 198 | steer(throttle, steering) 199 | if ARDUINO_SERVO_CONTROLLER: 200 | throttle = THROTTLE_SERVO_MIN_US + ((throttle * (THROTTLE_SERVO_MAX_US - THROTTLE_SERVO_MIN_US + 1)) / 101) 201 | steering = STEERING_SERVO_MIN_US + ((steering * (STEERING_SERVO_MAX_US - STEERING_SERVO_MIN_US + 1)) / 181) 202 | device.write("{%05d,%05d}\r\n" % (throttle, steering)) 203 | if NATIVE_SERVO_CONTROLLER: 204 | throttle = THROTTLE_SERVO_MIN_US + ((throttle * (THROTTLE_SERVO_MAX_US - THROTTLE_SERVO_MIN_US + 1)) / 101) 205 | steering = STEERING_SERVO_MIN_US + ((steering * (STEERING_SERVO_MAX_US - STEERING_SERVO_MIN_US + 1)) / 181) 206 | device.position(0, us=throttle) 207 | device.position(1, us=steering) 208 | 209 | # 210 | # Camera Control Code 211 | # 212 | 213 | sensor.reset() 214 | sensor.set_pixformat(sensor.RGB565 if COLOR_LINE_FOLLOWING else sensor.GRAYSCALE) 215 | sensor.set_framesize(FRAME_SIZE) 216 | sensor.set_vflip(True) 217 | sensor.set_hmirror(True) 218 | sensor.set_windowing((int((sensor.width() / 2) - ((sensor.width() / 2) * FRAME_WIDE)), int(sensor.height() * (1.0 - FRAME_REGION)), \ 219 | int((sensor.width() / 2) + ((sensor.width() / 2) * FRAME_WIDE)), int(sensor.height() * FRAME_REGION))) 220 | sensor.skip_frames(time = 200) 221 | if COLOR_LINE_FOLLOWING: sensor.set_auto_gain(False) 222 | if COLOR_LINE_FOLLOWING: sensor.set_auto_whitebal(False) 223 | clock = time.clock() 224 | #sensor.set_auto_exposure(False, \ 225 | # exposure_us = 300) 226 | 227 | 228 | ########### 229 | # Loop 230 | ########### 231 | 232 | old_time = pyb.millis() 233 | 234 | throttle_old_result = None 235 | throttle_i_output = 0 236 | throttle_output = THROTTLE_OFFSET 237 | 238 | steering_old_result = None 239 | steering_i_output = 0 240 | steering_output = STEERING_OFFSET 241 | 242 | while True: 243 | clock.tick() 244 | img = sensor.snapshot() 245 | img.binary(COLOR_HIGH_LIGHT_THRESHOLDS if COLOR_LINE_FOLLOWING else GRAYSCALE_HIGH_LIGHT_THRESHOLDS, zero = True) 246 | img.histeq() 247 | 248 | if BINARY_VIEW: img = img.binary(COLOR_THRESHOLDS if COLOR_LINE_FOLLOWING else GRAYSCALE_THRESHOLDS) 249 | if BINARY_VIEW: img.erode(1, threshold = 5).dilate(1, threshold = 1) 250 | if DO_NOTHING: continue 251 | 252 | # We call get regression below to get a robust linear regression of the field of view. 253 | # This returns a line object which we can use to steer the robocar. 254 | line = img.get_regression(([(50, 100, -128, 127, -128, 127)] if BINARY_VIEW else COLOR_THRESHOLDS) if COLOR_LINE_FOLLOWING \ 255 | else ([(127, 255)] if BINARY_VIEW else GRAYSCALE_THRESHOLDS), \ 256 | area_threshold = AREA_THRESHOLD, pixels_threshold = PIXELS_THRESHOLD, \ 257 | robust = True) 258 | 259 | print_string = "" 260 | if line and (line.magnitude() >= MAG_THRESHOLD): 261 | img.draw_line(line.line(), color = (127, 127, 127) if COLOR_LINE_FOLLOWING else 127) 262 | 263 | new_time = pyb.millis() 264 | delta_time = new_time - old_time 265 | old_time = new_time 266 | 267 | # 268 | # Figure out steering and do steering PID 269 | # 270 | 271 | steering_new_result = figure_out_my_steering(line, img) 272 | steering_delta_result = (steering_new_result - steering_old_result) if (steering_old_result != None) else 0 273 | steering_old_result = steering_new_result 274 | 275 | steering_p_output = steering_new_result # Standard PID Stuff here... nothing particularly interesting :) 276 | steering_i_output = max(min(steering_i_output + steering_new_result, STEERING_I_MAX), STEERING_I_MIN) 277 | steering_d_output = ((steering_delta_result * 1000) / delta_time) if delta_time else 0 278 | steering_pid_output = (STEERING_P_GAIN * steering_p_output) + \ 279 | (STEERING_I_GAIN * steering_i_output) + \ 280 | (STEERING_D_GAIN * steering_d_output) 281 | 282 | # Steering goes from [-90,90] but we need to output [0,180] for the servos. 283 | steering_output = STEERING_OFFSET + max(min(round(steering_pid_output), 180 - STEERING_OFFSET), STEERING_OFFSET - 180) 284 | 285 | # 286 | # Figure out throttle and do throttle PID 287 | # 288 | 289 | throttle_new_result = figure_out_my_throttle(steering_output) 290 | throttle_delta_result = (throttle_new_result - throttle_old_result) if (throttle_old_result != None) else 0 291 | throttle_old_result = throttle_new_result 292 | 293 | throttle_p_output = throttle_new_result # Standard PID Stuff here... nothing particularly interesting :) 294 | throttle_i_output = max(min(throttle_i_output + throttle_new_result, THROTTLE_I_MAX), THROTTLE_I_MIN) 295 | throttle_d_output = ((throttle_delta_result * 1000) / delta_time) if delta_time else 0 296 | throttle_pid_output = (THROTTLE_P_GAIN * throttle_p_output) + \ 297 | (THROTTLE_I_GAIN * throttle_i_output) + \ 298 | (THROTTLE_D_GAIN * throttle_d_output) 299 | 300 | # Throttle goes from 0% to 100%. 301 | throttle_output = max(min(round(throttle_pid_output), 100), 0) 302 | 303 | print_string = "Line Ok - throttle %d, steering %d - line t: %d, r: %d" % \ 304 | (throttle_output , steering_output, line.theta(), line.rho()) 305 | 306 | else: 307 | print_string = "Line Lost - throttle %d, steering %d" % (throttle_output , steering_output) 308 | 309 | set_servos(throttle_output, steering_output) 310 | print("FPS %f - %s" % (clock.fps(), print_string)) 311 | -------------------------------------------------------------------------------- /donkey-car/pca9685.py: -------------------------------------------------------------------------------- 1 | import utime 2 | import ustruct 3 | 4 | class PCA9685: 5 | def __init__(self, i2c, address=0x40): 6 | self.i2c = i2c 7 | self.address = address 8 | self.reset() 9 | 10 | def _write(self, address, value): 11 | self.i2c.writeto_mem(self.address, address, bytearray([value])) 12 | 13 | def _read(self, address): 14 | return self.i2c.readfrom_mem(self.address, address, 1)[0] 15 | 16 | def reset(self): 17 | self._write(0x00, 0x00) # Mode1 18 | 19 | def freq(self, freq=None): 20 | if freq is None: 21 | return int(25000000.0 / 4096 / (self._read(0xfe) - 0.5)) 22 | prescale = int(25000000.0 / 4096.0 / freq + 0.5) 23 | old_mode = self._read(0x00) # Mode 1 24 | self._write(0x00, (old_mode & 0x7F) | 0x10) # Mode 1, sleep 25 | self._write(0xfe, prescale) # Prescale 26 | self._write(0x00, old_mode) # Mode 1 27 | utime.sleep_us(5) 28 | self._write(0x00, old_mode | 0xa1) # Mode 1, autoincrement on 29 | 30 | def pwm(self, index, on=None, off=None): 31 | if on is None or off is None: 32 | data = self.i2c.readfrom_mem(self.address, 0x06 + 4 * index, 4) 33 | return ustruct.unpack(' & Kwabena W. Agyeman 3 | // This work is licensed under the MIT license, see the file LICENSE for details. 4 | 5 | #include 6 | 7 | #define SERIAL_RX_PIN 0 8 | #define SERIAL_TX_PIN 1 9 | #define THROTTLE_SERVO_PIN 6 10 | #define STEERING_SERVO_PIN 10 11 | #define RC_THROTTLE_SERVO_PIN 11 12 | #define RC_STEERING_SERVO_PIN 5 13 | 14 | #define SERIAL_BUAD_RATE 19200 15 | 16 | #define RC_THROTTLE_SERVO_REFRESH_RATE 20000UL // in us 17 | #define SERIAL_THROTTLE_SERVO_REFRESH_RATE 1000000UL // in us 18 | #define RC_THROTTLE_DEAD_ZONE_MIN 1400UL // in us 19 | #define RC_THROTTLE_DEAD_ZONE_MAX 1600UL // in us 20 | 21 | #define RC_STEERING_SERVO_REFRESH_RATE 20000UL // in us 22 | #define SERIAL_STEERING_SERVO_REFRESH_RATE 1000000UL // in us 23 | #define RC_STEERING_DEAD_ZONE_MIN 1400UL // in us 24 | #define RC_STEERING_DEAD_ZONE_MAX 1600UL // in us 25 | 26 | Servo throttle_servo, steering_servo; 27 | 28 | unsigned long last_microseconds; 29 | bool last_rc_throttle_pin_state, last_rc_steering_pin_state; 30 | unsigned long last_rc_throttle_microseconds, last_rc_steering_microseconds; 31 | unsigned long rc_throttle_servo_pulse_length = 0, rc_steering_servo_pulse_length = 0; 32 | unsigned long rc_throttle_servo_pulse_refreshed = 0, rc_steering_servo_pulse_refreshed = 0; 33 | 34 | char serial_buffer[16] = {}; 35 | unsigned long serial_throttle_servo_pulse_length = 0, serial_steering_servo_pulse_length = 0; 36 | unsigned long serial_throttle_servo_pulse_refreshed = 0, serial_steering_servo_pulse_refreshed = 0; 37 | 38 | void setup() 39 | { 40 | Serial.begin(SERIAL_BUAD_RATE); 41 | pinMode(LED_BUILTIN, OUTPUT); 42 | 43 | last_microseconds = micros(); 44 | last_rc_throttle_pin_state = digitalRead(RC_THROTTLE_SERVO_PIN) == HIGH; 45 | last_rc_steering_pin_state = digitalRead(RC_STEERING_SERVO_PIN) == HIGH; 46 | last_rc_throttle_microseconds = last_microseconds; 47 | last_rc_steering_microseconds = last_microseconds; 48 | } 49 | 50 | void loop() 51 | { 52 | unsigned long microseconds = micros(); 53 | bool rc_throttle_pin_state = digitalRead(RC_THROTTLE_SERVO_PIN) == HIGH; 54 | bool rc_steering_pin_state = digitalRead(RC_STEERING_SERVO_PIN) == HIGH; 55 | 56 | if(rc_throttle_pin_state && (!last_rc_throttle_pin_state)) // rising edge 57 | { 58 | last_rc_throttle_microseconds = microseconds; 59 | } 60 | 61 | if((!rc_throttle_pin_state) && last_rc_throttle_pin_state) // falling edge 62 | { 63 | unsigned long temp = microseconds - last_rc_throttle_microseconds; 64 | 65 | if(!rc_throttle_servo_pulse_length) 66 | { 67 | rc_throttle_servo_pulse_length = temp; 68 | } 69 | else 70 | { 71 | rc_throttle_servo_pulse_length = ((rc_throttle_servo_pulse_length * 3) + temp) >> 2; 72 | } 73 | 74 | rc_throttle_servo_pulse_refreshed = microseconds; 75 | } 76 | 77 | if(rc_throttle_servo_pulse_length // zero servo if not refreshed 78 | && ((microseconds - rc_throttle_servo_pulse_refreshed) > (2UL * RC_THROTTLE_SERVO_REFRESH_RATE))) 79 | { 80 | rc_throttle_servo_pulse_length = 0; 81 | } 82 | 83 | if(rc_steering_pin_state && (!last_rc_steering_pin_state)) // rising edge 84 | { 85 | last_rc_steering_microseconds = microseconds; 86 | } 87 | 88 | if((!rc_steering_pin_state) && last_rc_steering_pin_state) // falling edge 89 | { 90 | unsigned long temp = microseconds - last_rc_steering_microseconds; 91 | 92 | if(!rc_steering_servo_pulse_length) 93 | { 94 | rc_steering_servo_pulse_length = temp; 95 | } 96 | else 97 | { 98 | rc_steering_servo_pulse_length = ((rc_steering_servo_pulse_length * 3) + temp) >> 2; 99 | } 100 | 101 | rc_steering_servo_pulse_refreshed = microseconds; 102 | } 103 | 104 | if(rc_steering_servo_pulse_length // zero servo if not refreshed 105 | && ((microseconds - rc_steering_servo_pulse_refreshed) > (2UL * RC_STEERING_SERVO_REFRESH_RATE))) 106 | { 107 | rc_steering_servo_pulse_length = 0; 108 | } 109 | 110 | last_microseconds = microseconds; 111 | last_rc_throttle_pin_state = rc_throttle_pin_state; 112 | last_rc_steering_pin_state = rc_steering_pin_state; 113 | 114 | while(Serial.available()) 115 | { 116 | int c = Serial.read(); 117 | memmove(serial_buffer, serial_buffer + 1, sizeof(serial_buffer) - 2); 118 | serial_buffer[sizeof(serial_buffer) - 2] = c; 119 | 120 | if(c == '\n') 121 | { 122 | unsigned long serial_throttle_servo_pulse_length_tmp, serial_steering_servo_pulse_length_tmp; 123 | 124 | if(sscanf(serial_buffer, "{%lu,%lu}", &serial_throttle_servo_pulse_length_tmp, &serial_steering_servo_pulse_length_tmp) == 2) 125 | { 126 | if(!serial_throttle_servo_pulse_length) 127 | { 128 | serial_throttle_servo_pulse_length = serial_throttle_servo_pulse_length_tmp; 129 | } 130 | else 131 | { 132 | serial_throttle_servo_pulse_length = ((serial_throttle_servo_pulse_length * 3) + serial_throttle_servo_pulse_length_tmp) >> 2; 133 | } 134 | 135 | serial_throttle_servo_pulse_refreshed = microseconds; 136 | 137 | if(!serial_steering_servo_pulse_length) 138 | { 139 | serial_steering_servo_pulse_length = serial_steering_servo_pulse_length_tmp; 140 | } 141 | else 142 | { 143 | serial_steering_servo_pulse_length = ((serial_steering_servo_pulse_length * 3) + serial_steering_servo_pulse_length_tmp) >> 2; 144 | } 145 | 146 | serial_steering_servo_pulse_refreshed = microseconds; 147 | 148 | digitalWrite(LED_BUILTIN, (digitalRead(LED_BUILTIN) == HIGH) ? LOW : HIGH); 149 | } 150 | else 151 | { 152 | serial_throttle_servo_pulse_length = 0; 153 | serial_steering_servo_pulse_length = 0; 154 | } 155 | } 156 | } 157 | 158 | if(serial_throttle_servo_pulse_length // zero servo if not refreshed 159 | && ((microseconds - serial_throttle_servo_pulse_refreshed) > (2UL * SERIAL_THROTTLE_SERVO_REFRESH_RATE))) 160 | { 161 | serial_throttle_servo_pulse_length = 0; 162 | } 163 | 164 | if(serial_steering_servo_pulse_length // zero servo if not refreshed 165 | && ((microseconds - serial_steering_servo_pulse_refreshed) > (2UL * SERIAL_STEERING_SERVO_REFRESH_RATE))) 166 | { 167 | serial_steering_servo_pulse_length = 0; 168 | } 169 | 170 | if(rc_steering_servo_pulse_length) 171 | { 172 | if(!steering_servo.attached()) 173 | { 174 | throttle_servo.attach(THROTTLE_SERVO_PIN); 175 | steering_servo.attach(STEERING_SERVO_PIN); 176 | } 177 | 178 | if(serial_steering_servo_pulse_length) 179 | { 180 | if((rc_throttle_servo_pulse_length < RC_THROTTLE_DEAD_ZONE_MIN) 181 | || (rc_throttle_servo_pulse_length > RC_THROTTLE_DEAD_ZONE_MAX)) 182 | { 183 | throttle_servo.writeMicroseconds(serial_throttle_servo_pulse_length); 184 | } 185 | else 186 | { 187 | throttle_servo.writeMicroseconds(1500); 188 | } 189 | 190 | if((rc_steering_servo_pulse_length < RC_STEERING_DEAD_ZONE_MIN) 191 | || (rc_steering_servo_pulse_length > RC_STEERING_DEAD_ZONE_MAX)) 192 | { 193 | steering_servo.writeMicroseconds(rc_steering_servo_pulse_length); 194 | } 195 | else 196 | { 197 | steering_servo.writeMicroseconds(serial_steering_servo_pulse_length); 198 | } 199 | } 200 | else 201 | { 202 | throttle_servo.writeMicroseconds(rc_throttle_servo_pulse_length); 203 | steering_servo.writeMicroseconds(rc_steering_servo_pulse_length); 204 | } 205 | } 206 | else if(steering_servo.attached()) 207 | { 208 | throttle_servo.detach(); 209 | steering_servo.detach(); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /donkey-car/video/10.20.2018.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmv/openmv-projects/efa2baf86708d0112ba1883c3a3f48a1a583b628/donkey-car/video/10.20.2018.mp4 --------------------------------------------------------------------------------