/
Final_Project-Report.txt
1671 lines (1189 loc) · 64 KB
/
Final_Project-Report.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Final Project Report:
--------------------
This assignment has taken about 10 hours so far.
Project Description:
-------------------
Starting from "My Project Initial Notes.docx"...
Implement some semi-autonomous behavior in my m3pi Robot,
where "semi-autonomous" means:
independent exploratory behavior,
with real-time ongoing reporting of location estimates and room dimensions
responding to queries
executing commands
Sensors to use:
--------------
I have several types of Sonar and IR Transceiver Sensors to draw from, as well as a
3-Axis Magnetometer, for which I have code that implements a Tilt-Compensated Compass
on it.
I propose having Sonar facing forward, and IR Transceivers pointing in the other three
directions, to detect/prevent tangential and backing-up collisions, and ensure parallel
following of walls, with no veering towards or away from them.
Potential Goals/Sub-Tasks/Behaviors/Negative Sensor Feedback Loops:
------------------------------------------------------------------
1. My first Sensor<->Robot Feedback Loop to implement is Robot Rotation tied to the
Compass. This will require using the existing m3pi Library to drive the wheels,
line-follower Sensors, PZ Speaker, etc., and implementing I2C communication with
my existing 3-Axis Magnetometer and its Tilt-Compensated Compass code.
1a. Calibration for Tire Scrub losses, etc., will be attempted by using the Sonar
with some sort of Training Jig, i.e., one or two rings of Construction Paper with
10-degree wide slots cut in them, where I rotate one ring, to progressively narrow
the slots, and/or perhaps use the built-in Line-Following Sensors for rotational
calibration on top of a 36-arm Starfish-like Jig of thin Tape. Both of these Jigs
I could draw in some graphics program, and just print them.
1b. To debug and calibrate the 3-axis Magnetometer (= Tilt-Compensated Compass) and
wall-Following, I’ll implement an analog 2-Axis Joystick.
Pushing the Joystick around in a circle at full-scale deflection will command the
Robot to Rotate either clockwise or counter-clockwise, and a smaller deflection
(with no circular motion) will command the Robot to rotate to that heading, and
start rolling at a speed proportional to the deflection.
Various tutorials for Joystick programming here:
http://learn.parallax.com/KickStart/27800
https://www.sparkfun.com/tutorials/272
http://www.arduino.cc/en/Tutorial/JoystickMouseControl
2. Once Rotation is as calibrated as it can be, I want to implement wall-following,
where the side-looking Sensors prevent gradually veering, either into, or away from,
the wall that the Robot is following.
3. Once wall-following is working as best it can, I'll try to implement wall distance
measurement, to begin the task of creating an X-Y Coordinate System, in which to map
the room.
The distance measurement will be based on combining counting wheel rotations, with
Sonar measurements along a wall, to as great a distance as the Sonar can measure
accurately.
4. Once some basic mapping data collection is working, I want to implement display of
the data on a web page pushed out by the robot via a WiFly on it. I'll try to
implement both Ad-Hoc and DHCP IP Addressing, in case UCSC Extension's Wi-Fi doesn't
allow a Server to be added to it.
5. Once I have implemented a basic Query & Response web page interface, I want to add
either of a HTML5 canvas or svg tag, and in it both display the Robot's path and
wall findings, as well as allow directional guidance to be input.
6. My ultimate GUI goal is to support multi-touch gestures in the map, i.e., Pinch for
Zoom, and 2-finger Twist for rotating the Map. Theoretically my Laptop's Touch
Screen driver can deliver such events to applications, so it's a question if either
Java Apps or some combination of Javascript+HTML5+whichever Browser can receive them.
Issues to resolve along the way:
-------------------------------
Findings along the way:
----------------------
Joystick:
I wanted to check for "unreachable coordinates" with my Joystick, as jerks in its
output data may lead to my Robot crashing into the wall, zooming out of control, etc.
The 1st graph in "x_and_y1_and_y2-scan-data.xlsx" shows when I dragged the Joystick
from left to right, moved down a tiny bit, then did it again. This shows pretty uniform
coverage, except for Quadrant IV.
For the 2nd graph in the .xlsx file, I dragged the Joystick top to bottom, moved right
a tiny bit, then did it again. My first guess is that this shows the Y’s Pot. is very
dirty, and has many dead spots.
I haven't used this Joystick before, so perhaps as I begin to use it more, it will
become better behaved over time. Hope so.
I need to convey my Joystick output to my mbed input (via my XBee Dongle). I was
thinking about writing a little perl script that just reads from COM21 (= my Arduino
Nano) and writes what it read from there to COM27 (= my mbed). Luckily, I found here:
http://perlguru.com/gforum.cgi?post=43583;guest=
where it says that I need to open COM ports > COM9 with this syntax:
open( PORT, "\\\\.\\COM21") || die( "open failed.\n");
So now in the Perl debugger, I can see my Joystick's output data as follows:
DB<7> open( PORT, "\\\\.\\COM21") || die( "open failed.\n");
DB<9> p <PORT>
xVal: -2 :yVal: 1
xVal: 3 :yVal: 1
xVal: 15 :yVal: 3
xVal: 5 :yVal: 1
xVal: -4 :yVal: 1
[...]
In setting up to use the mbed RPC Library that I described here:
https://groups.google.com/forum/#!topic/spring2015_e4357/Uxt0BtRg5BQ
I found that the mbed Cookbook entry that I referred to is now out-of-date,
so I found another RPC example that does work in developer.mbed.org/compiler
here:
https://developer.mbed.org/users/ban4jp/code/SerialRPC_rtos_example/docs/tip/
I.e., in my main.cpp I have:
#include "mbed.h"
#include "rtos.h"
#include "SerialRPCInterface.h"
#include "RPCVariable.h"
float f = 42;
int i = 43;
char c = 'b';
RPCVariable<float> rpc_f(&f, "f");
RPCVariable<int> rpc_i( &i, "i");
RPCVariable<char> rpc_c(& c, "c");
int main()
{
SerialRPCInterface rpc( USBTX, USBRX);
}
In my developer.mbed.org/compile program, I've imported these libraries:
mbed-rpc
mbed-rtos // Not sure if this one is needed for our purposes.
RPCInterface-rtos // I only use this because the other similar libraries don't compile.
In my Serial Terminal program (connected to my mbed), when I just hit the Enter key,
my mbed sends back this Help message:
c i f SPI Serial Timer PwmOut DigitalInOut DigitalOut DigitalIn RPC
meaning that "c", "i", and "f" are my variables that I can query and set,
as well as typing /RPC/something, DigitalIn/something, etc., as shown here:
/c/read prints:
b
/f/read prints:
42
/i/read prints:
43
The caveat so far is that only the first of the above works, then it just prints out the
Help message in response to further commands.
I'll google more to learn how to clean out the queue, so further commands can work.
And it's bigger than the demo-Keil will allow, so once I get my near-term functionality
implemented (= the Robot is moving following my Joystick motions), I'll google a bit more
to find a non-RTOS version of this, that will fit into the demo-Keil.
Update:
I finally realized (after much google'ing), that the newest version of the SerialRPCInterface
code:
Description: https://developer.mbed.org/cookbook/RPC-Interface-Library
Code: https://developer.mbed.org/users/MichaelW/code/RPCInterface/
is Version #8 (28 Jan 2012), as shown in developer.mbed.org/compiler, by right-clicking on
this Library in Program Workspace under your program, choosing "Revisions...".
That means that in order to get the SerialRPCInterface Library to compile, I need to
right-click on the mbed Library for my program, click on "Revisions...", and click on the
newest version prior to that date, and click on "Switch", which is Version #36 (26 Jan 2012).
Once I switched to this ancient version of the mbed Library, the RPCInterface
(aka SerialRPCInterface) Library compiles just fine, though it still only works
the first time I send it a query.
The good news is that now I can compile and debug into it in Keil. If you have the
32kByte-limited version of Keil, rather than the 30-day-limited version, to get past
the 302kByte-limit, I propose to comment out some of these lines:
SerialRPCInterface.cpp:40:
void SerialRPCInterface::_RegClasses(void){
//Register classes with base
>>> // Base::add_rpc_class<AnalogIn>(); <<<<<<<<<
// ...
Comment out whichever of these add_rpc_class() calls for mbed capabilities that you won't
be using.
I.e., I commented them all out except for <AnalogOut>, and my Keil code size became
28080 bytes during linking, and 30680 bytes loaded into the mbed.
Uncommenting out one add_rpc_class() call added 192 bytes during linking, and 228 bytes
loaded into the mbed, so you can calculate how many more add_rpc_class()'s you can
uncomment out, and still fit into the crippled Keil.
Next I'll debug into it and try to see why it only replies to the first command.
In Keil, I unchecked:
Options for Target->Debug->CMSIS-DAP Debugger->Settings->
Debug->Stop after Bootloader
Doing so causes this error:
Address execution break already exists,
redefine existing breakpoint?
Clicking on either of No or Yes causes this error:
Cannot access target.
Shutting down debug session.
So I left that checked, and tried unchecking this instead:
Options for Target->Debug->Run to main()
This causes the same first error as above, but if you click "No",
it lets the program run to hit your first breakpoint, rather than
stopping at the start just prior to entering main().
Update:
I should mention that the SerialRPCInterface Library receives RPC calls
via interrupts, which (I believe) is superior to the polling approach
in a while (1) loop that you can see here:
https://developer.mbed.org/questions/3897/AnalogIn-not-working-in-rpc/
Update:
Alas, my changes to RPCFunction.cpp were unsuccessful, so I'm setting that
aside for now in favor of implementing my next functional block, which is
the data path between my JoyStick+Arduino, to the m3pi left()/right() and
motor_left()/motor_right() RPC functions, which do work.
To do this, I'll write a very small Perl "bridge" script, which will read
the JoyStick's R+Theta values from COM23, and write the corresponding
m3pi-RPC commands to the mbed, first via USB on COM28, then later via XBee
on COM20. When I make that change, the corresponding mbed code change will
be from:
SerialRPCInterface rpcInterface( USBTX, USBRX);
to:
SerialRPCInterface rpcInterface( p28, p27);
as that's where the m3pi's Radio Socket's TXD and RXD connect to the mbed.
I also have to further increase the noise rejection of the JoyStick program.
I'm thinking of cutting its Theta output into 8 octants. For the R value,
I'll first try cutting it down to be one of 5 values:
< 75 = noise, i.e., ignore
next 1/3rd = 1/3rd of full-speed in the specified direction, after rotation
with reference to the Tilt-Compensated Compass (= 3-axis Magnetometer)
next 1/3rd = 2/3ds of full speed, ditto.
last 1/3rd = full speed, ditto.
> 900 = full-scale deflection, = Rotation mode, rather than Bearing mode.
I'll parameterize the lower-noise and full-scale deflection thresholds and the
number of steps between zero-speed and full-speed, to simplify adjusting them
in response to however noisy the JoyStick turns out to be in actual use.
I found that these noise-filtering settings worked well for this particular JoyStick:
const int numThetaSectors = 8;
const int noiseCeiling = 120;
const int fullScaleFloor = 900;
const int numRadiusRanges = 8;
I also added a check to prevent unwanted points when the JoyStick is snapping back to center.
Update:
------
I'm attempting to abandon the Perl JoyStick->mbed Bridge script in favor of
hosting the JoyStick on an Arduino Fio, which will communicate with the mbed
via XBee.
Initially, I'm programming the Fio using this:
http://moderndevice.com/product/usb-bub-i/
which I've jumper'ed to output 3 Volts to the Fio (both Data lines and Vcc),
as it's a 3V part.
The photo "Arduino-Fio Joystick vs. Arduino-Nano Joystick.jpg" shows the
new Fio JoyStick hosting arrangement in the foreground (the small red board
is the FTDI programmer), and the old Nano host (plus XBee carrier, which is
built into the back of the Fio).
I only wish I had soldered these stackable headers:
http://shop.evilmadscientist.com/partsmenu/251
onto the Fio instead of the usual ones, as then it would be much easier to
wire up the Fio.
Update:
------
Programming the Fio with the USB Bub above works fine, and I can
communicate with the Fio's running program via XBee as well, but
I can't yet program it via XBee.
To get the Wireless Programming of the Fio working, I'm following the
steps in the web pages below, which I'll summarize here:
Referring to these photos...
Fio Wireless Programming Soldering Steps-p1.jpg
Fio Wireless Programming Soldering Steps-p2.jpg
On the Fio (mine's board is black), there is a very tiny solder jumper point,
that needs to be closed to support Wireless Programming.
It may or may not already be soldered in when you buy your Fio. It doesn't
need a wire to close the gap, only a very tiny solder blob.
Your XBee carrier board needs to have a very short wire jumper soldered between
the RTS pad and the Data IO Pin 3 pad.
Solder the wire on the opposite side of the XBee carrier board from where the
XBee socket is, so you can easily see that the jumper is in place, without
having to remove the XBee to check.
If you're using Windows, do this step, which I'm quoting from here:
http://www.jeffhoefs.com/2013/06/wireless-firmata-using-xbees/
In the Device Manager, select the USB COM port.
Then right click and select Properties. Click on the Port Settings tab,
and click on Advanced..., then make sure "Set RTS On Close" is selected
and click OK to apply settings.
(these instructions copied from http://arduino.cc/en/Main/ArduinoBoardFioProgramming)
I also got some valuable info from here:
https://www.sparkfun.com/tutorials/122
Referring to those directions above, I updated my XBee's firmware by doing the
following:
Run X-CTU from digi.com, and inside it, ...
Click on Modem Configuration->Modem Parameter and Firmware->Read,
to determine current firmware version and settings
Click on on Modem Configuration->Versions->Download new versions.
It took quite a while to do that, seemingly downloading every firmware
version for every Digi product in the known universe.
Click on the Version pull-down menu, and choose the newest version.
Check the "Modem Parameter and Firmware"->"Always Update Firmware" checkbox.
Click on "Modem Parameter and Firmware"->Write.
Once I'd upgraded my firmware, I next used X-CTU to change the following for my
Remote unit:
Networking & Security->PAN ID->(my id#, anything in the range: 0-0xffff)
RF Interfacing->Power Level->(0) Lowest
Serial Interfacing->Interface Data Rate->(6) 57600 baud
(57600 is the baud rate used by the Fio's Bootloader,
which is why this speed is used)
I/O Settings->D3->(5) DO HIGH # Digital Output, active-high.
I/O Settings->IU->(0) DISABLED
I/O Settings->I/O Line Passing->(FFFF)->Set->OK
Networking & Security->MY 16-bit Source Address->(1) This is unit #1.
then clicked on "Modem Parameter and Firmware"->Write.
For my Base unit, I did the same, except for:
I/O Settings->D3->(5) DI # = Digital Input.
I/O Settings->DIO Change Detect->(8) # = 0b1000, which is Pin 3
(no I/O Line Passing change for the Base unit)
(no Power Level change for the Base unit)
(no Source Address change for the Base unit)
Networking & Security->Destination Address High & Low = ffff
From here:
http://www.arduino.cc/en/Main/ArduinoBoardFioProgramming
I added in the Base settings:
Networking & Security->XBee Retries->(3)
Serial Interfacing->Packetization Timeout->(10)
For safe-keeping, I clicked on Modem Configuration->Profile->Save, and saved
a .pro file for both my Base and Remote XBees' configuration.
If you change the Baud Rate, after you write the new settings to your XBee,
in X-CTU, go back to PC Settings->Com Port Setup->Baud, change it to your
new speed, and click on Test/Query.
If all went well, it will say, "Success". If not, try changing the Baud
pull-down menu back to the original speed (usually 9600), and click on
Test/Query again.
Back in:
https://www.sparkfun.com/tutorials/122#Step4
makes a start at explaining how all this DIO3-fiddling in X-CTU works, to
facilitate Wireless Programming.
It's explained a bit more thoroughly here:
http://www.arduino.cc/en/Main/ArduinoBoardFioTips
Here:
http://forum.arduino.cc/index.php?topic=123835.0
it also suggests doing this to both units in X-CTU:
I/O Settings->DIO7->(0) Disable CTS Flow Control
I'm going to try first without this though.
Some more of the above info is spelled out here:
http://www.semifluid.com/2012/09/07/arduino-fio-low-power-setup/
Update:
------
I was reading here on XBees:
https://www.parallax.com/sites/default/files/downloads/32400-XBee-USB-Adapter-Documentation-v1.0.pdf
https://davidbeath.com/posts/reading-xbee-rssi-with-arduino.html
and thought it might be good to perform this procedure:
Test Communications Link and Establish a Network: Perform a Range Test
as described here:
http://ftp1.digi.com/support/documentation/90002160_A.pdf
I made a few screenshots here:
"XBee-USB Cable-Trim off corner to fit XBee Carrier-p1.png"
"XBee-USB Cable-Trim off corner to fit XBee Carrier-p2.png"
showing how I had to trim off the corner of the USB cable's plug, to allow
it to fit when plugging it into the small XBee carrier board.
To perform the test on pg. 12, I added a jumper between DIN and DOUT on the
XBee carrier board.
In "XBee-Loopback Testing-p1.png", you can see the jumper I added above on
the "Remote" XBee.
To maximize my Robot's Battery Life, I set the Remote XBee's "RF Interfacing->
Power Level" to (0)-LOWEST.
With this setting, I found that dropped very few packets with the Remote XBee
as far away as in the next room, and was able to keep at least intermittent
communication up (= the RSSI light stayed on) until I finally entered the room
at the opposite end of my home.
In the future, I'll want to configure API mode as described in the .pdf file
above, and as described here:
http://knowledge.digi.com/articles/Knowledge_Base_Article/Digi-API-Frame-Maker
but that can wait for now.
Lastly, the XBee's ignal Strength (via the PWM signal on its RSSI pin) can be
monitored as described here:
http://letsmakerobots.com/node/37243
http://log.liminastudio.com/itp/physical-computing/measuring-xbee-signal-strength-from-the-rssi-pin
https://davidbeath.com/posts/reading-xbee-rssi-with-arduino.html
Update:
------
After doing the above, in my Serial Terminal program I clicked on-and-off the RTS
signal, which is what the Arduino IDE does to signal the Arduino's Bootloader that
it's time to receive a new program.
I used an LED+Resistor to confirm on my XBee USB dongle that its RTS pin (now
jumper'ed to XBee pin DIO3) is toggling when I click on my Serial Terminal's RTS
button.
I followed that by using the LED to confirm that on the "Remote" XBee its DIO3 is
also toggling when I click the Serial Terminal's RTS button.
Lastly, I installed the XBee on the Arduino FIO, and confirmed that the DIO3 pin
is still toggling in sync with the clicking the Serial Terminal's RTS button.
After all this, I tried Wireless Programming the Fio again, and now it works :=).
Update:
------
Moral: Just use my Profile (.pro) files to program your XBee's, rather than subjecting
yourself to all the headaches that I encountered above:
https://github.com/NeuroDuck/e4357/tree/master/project/Joystick/
XBee Profile-Base.pro
XBee Profile-Remote.pro
Use the "Base" Profile (.pro file) as is, in digi.com's X-CTU XBee programming tool,
to program the XBee which will be directly connected to your PC. Its node id# is 0.
Use the "Remote" Profile (.pro file) to program the XBees that you connect to each of
your slaves. The node id# in this Profile is 1. Increment the node id# prior to
programming the XBee of any slave.
Both Profile (.pro) files are configured for "Lowest Transmission Power Level", to save
battery life in the embedded application.
The "Base" Profile is configured to set the Base XBee's DIO3 pin as an input, and to
propagate the data that is input into that pin (i.e., from your PC's USB cable),
outward through the radio to all of the slaves.
The "Remote" Profile is configured to set the Remote XBee's DIO3 pin as an output,
and to receive data via the radio from the Base XBee's DIO3 pin, and output that
data on the Remote XBee's DIO3 pin.
I.e., on the Arduio Fio, the XBee's DIO3 Output pin is wired to the MCU's Reset pin,
with a small capacitor in series, to give the Remote's MCU Reset pin a short pulse,
when the XBee's DIO3 signal drops and stays low.
I want to have multiple Robots collaborate on doing various tasks, i.e., as described
here:
http://www.cliffolling.com/ArukuGo/
http://letsmakerobots.com/node/35134
So I'll update again if I have time to look into either of XBee API or Mesh
communication modes.
Update:
------
Checking in first working code that drives the Robot via XBee from a JoyStick
connected to an Arduino Fio, as shown in:
"mbed Controlled via XBee by JoyStick connected to Arduino Fio.png"
Update:
------
As shown in:
"git\e4357\project\Joystick\New JoyStick-Theta-Sector Patterns-to support Steering.txt"
to create turning capability, I switched the JoyStick program to subdivide its circle into
16 sectors, where theta =0 & =8 are Rotate right & left, and =4 and =8 are drive forward
and backward.
I assigned the 3 theta values in between each of these to represent {slight,medium,hard}
turns.
Alas, I discovered that this JoyStick is too coarse to be able to produce/distinguish this
many theta values, at least for radius values <= 50% of full-scale.
To address this, for radius values <= 6 (out of a maximum of 9), I now smash the 3 turn
values into only 1.
[Edit: I should instead smash them into being the largest-radius turn of the 3, rather
than the middle one. I ultimately did this below.]
I imagine that further testing will reveal that I'll basically have to just raise the
noise floor significantly above its current value of r=120, as the JoyStick just doesn't
have enough angular resolution (to support having 3 different radii of turns) with
JoyStick deflections of less than that.
Update:
------
Possibly due to having switched the XBees to the "LOWEST" transmission power setting, the
mbed is now receiving lots of garbled messages from the JoyStick.
To address this, I've implemented a fixed-length 8-byte(+CR) JoyStick message format of
the form "!r tt cc", where:
r == JoyStick radius value
tt = JoyStick Theta value
cc == checksum (= sum of r + tt) value
In the mbed code, I added a simple parser function, that is called like this:
int rVal = 0, thetaVal = 0, checksum = 0, dummy = 0;
char fieldsSpec[] = "!1d1 1d2 1d2";
int* results[] = { &dummy, &rVal, &dummy, &thetaVal, &dummy, &checksum };
int invalidFieldNum = checkFields( cmd, fieldsSpec, results);
if (invalidFieldNum <= -10) // The length was incorrect.
{ ... } // Actual length = 10 + invalidFieldNum;
if (thetaVal < 0 || thetaVal > numThetaSectors - 1) // Theta wasn't valid.
{ ... }
if (rVal + thetaVal != checksum) // Checksum failed.
{ ... }
if (invalidFieldNum != 1) // Fieldnum# -invalidFieldNum
{ ... } // had a problem.
I found that I reached a point with the Keil Debugger, where I needed to let the program
run at full speed to find bugs/hangs, etc., that stepping past breakpoints would not
accomplish.
I suppose I could have made a variable-incrementing if-statement, and set a breakpoint
inside its { block } to fake a conditional-breakpoint, like Visual Studio has.
Instead I decided that I'd rather have a place to print the mbed's debugging messages
during Wireless operations (and to support later new features), so I added this 2x16
ASCII display to the JoyStick:
https://www.parallax.com/sites/default/files/downloads/27979-Parallax-Serial-LCDs-Product-Guide-v3.1.pdf
http://learn.parallax.com/KickStart/27977
On its top line, it displays its outgoing messages, now of the fixed-length form described
above.
On its bottom line, it displays messages received from the mbed, to aid my debugging.
To save the battery, the Display's backlight is toggled by a debounced momentary
pushbutton.
Alas, this Display is a 5V part, my Arduino Fio has no 5V output, and I didn't want to risk
burning it up, so I installed a Voltage Divider off of the 4xNiMH batteries (= 5.41V) as
shown in:
"JoyStick Display+Voltage Divider.jpg"
to step it down to ~5.0V. I found that to get the Display to work, I had to use very low
values in the Voltage Divider ( [vBatt <- ~10 Ohms "." 100 Ohms -> Ground], where the
Display is connected to the "."), or the Display couldn't get enough current to operate.
My resistors are only 1/8W, so to avoid melting them, I put 2 of double the values above in
parallel to achieve each of the values above.
When I get time to buy a 2-Cell LiPo battery, I will replace the Voltage Divider with a
LM7805 7V->5V Voltage Regulator.
In the meantime, I became brave, and hooked the Display directly to the Battery, and it's
working well with no Voltage Divider.
Next I'll wade through the mbed's messages on the JoyStick display, to further debug the
mbed's processing of the JoyStick commands.
Update:
------
I added a (22k Ohm . 10k Ohm) Voltage Divider from Vbat <-> Ground, from which I'm measuring
and displaying the Battery Voltage. I need to knock it down by 2/3rds, to ensure that the
8.4V of a fully-charged 2-Cell LiPo Battery will still be < 3.3V, as that's what the Arduino
Fio's is running on.
The JoyStick's Display now has 3 sections:
Upper-left: JoyStick command sent to Robot
Upper-right: Battery Voltage
Bottom line: Response from Robot, and JoyStick status messages
The momentary toggle-in-software Button (used to cancel waiting, and to toggle the Display
back-lighting) still has a few issues, but otherwise the JoyStick code now has the debug
message printing and "JoyStick blocking when waiting for input"-capability that I was
envisioning.
I'll leave the button functionality as is for now, and use this new JoyStick display to
finally return to debugging the Robot's turning functionality.
The only JoyStick addition remaining that I plan to do, is to add a DIP of 8 tiny switches
connected to pins D2-D9.
This will allow the user to choose which of a multitude of functions to run when the button
is pushed.
I'll also use one of the DIP switches to enable/disable "Wait for Robot reply before
allowing new JoyStick input", which blocks future JoyStick inputs, when awaiting a reply
from the Robot to the previous JoyStick command sent to it.
The photo "JoyStick Display-startup.jpg" shows the startup state of the JoyStick's new
Display, and the Voltage Divider I'm using to measure an (upcoming) 8.4V LiPo 2-Cell battery
with one of the Arduino Fio's 3.3V ADC pins. When I migrate from my current 4xNiMH batteries
to the 8.4V LiPo one, I'll add a Voltage Regulator to provide 5V to the Display.
In this photo, the Display's upper-left corner is blank, indicating that currently no JoyStick
command has been sent to the Robot, thus no response is being waited for, and JoyStick input
is enabled.
As shown in the photo "Sent JoyStick Cmd. to Robot-Awaiting Response.jpg", when the user moves
the JoyStick, a command is sent to the Robot and shown in the Display's upper-left corner.
For debugging purposes, I've set the JoyStick's program to block further JoyStick input while
it is awaiting a response from the Robot. To allow for the Robot never responding, the Display
shows a reminder that pushing the JoyStick's PushButton will cancel the blocking/waiting, and
re-enable JoyStick input.
The photo "Response from Robot.jpg" shows the Robot's response. The Display's upper-left
corner is blank, indicating that no command has been sent/is being waited for, and that
JoyStick input is enabled.
The photo "Wireless Debugging message received from Robot.jpg" shows the JoyStick wirelessly
receiving a debugging message from the Robot.
Update:
------
The JoyStick's debugging Display is starting to bear fruit.
On the minus side, it is apparently suffering from overruns due to data arriving too
fast from the Robot to be pushed to the Display at its max. 19200 baud rate.
I've somewhat addressed this by adding wait_ms() everywhere I send to the JoyStick.
Data on the Display is still intermittently appearing in the wrong place, so some
more wait_ms()'s are no doubt required, to allow the Display time to keep up.
On the plus side, having the Robot's debugging messages appear on the JoyStick Display
while the Robot is driving around is proving helpful, with the result that the Robot
is now much closer to turning in the directions directed by the JoyStick.
For safety during testing, I have the Robot stop itself 2 sec. after receiving any
driving/rotation command.
All of {left,right}{rotation,turn}{forward,backward} seem to be working at at least
a rudimentary level.
The only caveat is that the Rotation speed suddenly increases after a second or so.
This may be due to the base 3pi robot's PID code kicking in. I'll have to check if
it's on by default, and disable it until I iron out most of my bugs.
Now when the Robot detects that its battery is getting low, it sends:
"He's dead, Jim."
to appear on the JoyStick's Display :-).
And for when the Robot is "tethered", I added the capability for the user to type in
arbitrary text in the Robot's Serial Terminal window, which is sent to the JoyStick.
This is handy to unstick the JoyStick, when it's waiting in vain for a response from
the Robot, and to test the sending of future commands to the JoyStick.
Update:
------
I checked in some small tuning changes to the Steering algorithm.
I found that its ease-of-handling was greatly increased by damping down the Rotation
rate.
The Steering code is in lines 99-362 here:
https://github.com/NeuroDuck/e4357/blame/master/project/main.cpp
I fished through those changes, and found that the most helpful steering tweaks were
probably these:
"Tune the Steering algorithm a bit, to make it less twitchy, so it becomes easier
to make small course-corrections, while driving at high speed."
https://github.com/NeuroDuck/e4357/commit/9d38d903fe8e3d9df45eea4f86f53576deec82e0
main.cpp:180:
- float rotationSpeed = 1.0 * r / numRadiusBands;
+ float rotationSpeed = 1.0 * r / numRadiusBands / 8; // (rotate _much_ slower).
as it was just spinning 'way too fast to control which way it ended up pointing.
I also made a temporary trade-off, of allowing faster driving, while blocking the
ability to make the two levels of tighter-radius turns, as shown here:
main.cpp:193-199:
- float fasterWheelRatio = wheelRatios[theta] * r / 500.0 / 4;
- float slowerWheelRatio = (100 - wheelRatios[theta]) * r / 500.0 / 4;
+ else if (theta != forwardTheta) // == We're turning.
+ {
+ theta = 3; // Limit us to the most gradual turn of the 3 for now.
+ }
+
+ float fasterWheelRatio = wheelRatios[theta] * r / 500.0;
+ float slowerWheelRatio = (100 - wheelRatios[theta]) * r / 500.0;
I also went through everywhere main.cpp is sending commands to the underlying 3pi Robot,
and added wait_ms() after each transmission, to allow enough time for it to complete at
the 115200 baud rate being used.
I added wait_ms() in the JoyStick code where it's sending characters to its Display at
the Display's max. 19200 baud rate.
Now I'm starting to test my old Compass that I bought a few years back:
LSM303DLM 3D Compass and Accelerometer Carrier with Voltage Regulators ($5.95)
https://www.pololu.com/product/1273
It is being phased out, so I also bought this new one:
LSM303D 3D Compass and Accelerometer Carrier with Voltage Regulator ($9.95)
https://www.pololu.com/product/2127
Alas, in my m3pi Robot, as shown in:
"project/Compass/m3pi_I2C-Conflict_Schematic.gif"
both pairs of the mbed's I2C bins being used for something else. I.e., the mbed uses
p9 & p10 to tell the “downstairs Robot” to spin the wheels, report the Battery Voltage,
etc., and it uses p27 & p28 to talk with the XBee radio.
Luckily, here:
http://forum.pololu.com/viewtopic.php?f=29&t=6187
I found that there is a SoftwareI2C Library available here:
https://developer.mbed.org/users/p3p/code/SoftwareI2C/docs/8670e78c4b63/SoftwareI2C_8h_source.html
that can do I2C on any two unused Pins, so I'll try that out.
Update:
------
Aside: While working in Panera, where apparently all the Wi-Fi users may make for a noisy
RF environment, I found that when doing my Wireless Programming of my Fio via XBee
(w/transmission power set = "LOWEST"), my max. Wireless Programming range was ~6-7
inches. Really, trying to program from 10 inches away, I was only able to succeed
about 1 time in 10 tries.
Aside: Re: Sonar, Pololu has a very helpful beam width/depth chart here:
https://www.pololu.com/picture/view/0J1969
The manufacturer's Selection Guilde is here:
http://www.maxbotix.com/SelectionGuide/Selection-Guide.htm
And their FAQ is here:
http://www.maxbotix.com/tutorials.htm
Ah, here's a better beam comparison chart:
http://www.maxbotix.com/pictures/HRLV/HRLV-EZ%20Sensor%20Beam%20Patterns.gif
Aside: Re: Thin LiPo Batteries: Can 2 thin 1S 1Ah LiPo's be safely wired together in
series, wire terminals-to-wire terminals (nose-to-nose), to make a thin 2S
battery pack?
Aside: Re: XBees: #0 goes in my USB Dongle (Dest=0xff)
#1 in the JoyStick (Dest=#2)
#2 goes in the mbed Robot (Dest=#1)
#3 goes in the Rover5 Robot (Dest=#0)
All were programmed using my checked-in .pro files with the above changes, using
digi.com's free X-CTU program.
Update:
------
I'm checking in project/Compass/calibrate_Compass.cpp, which is used to determine your
particular Compass's full-scale values for Acceleration and Magnetic Field, in your
particular installed environment, to help it give more accurate readings.
Following up on what I wrote above, the SoftwareI2C library is working well.
I checked in my versions of developer.mbed.org's libraries: LSM303DM & SoftwareI2C,
as I had to slightly modify both to allow them to compile together.
I added a bit of the DIPswitch support to the JoyStick. Now is the point where it
would be handy to use one of the mbed RPC libraries, but they all seem to be out-of-date
(read: they don't compile against the current mbed library).
So instead I'll add to the existing syntax (see the next update below) that I'm already
parsing, and use it to send my commands and queries to the Robot.
The intention is that I will add 8 or more tiny switches (currently they're just wires to
Ground).
When the user pushes "the JoyStick's Button", functions in the Robot will be run, selected
by whichever of the DIPswitches are in their "active" state. I'll probably create some
sort of primitive way for the user to specify an argument to the function invocation as well.
I'll be adding a Compass to both the JoyStick and the Robot, so the Robot can steer
relative to the JoyStick's "forward" direction, rather than relative to the Robot's
"forward" direction.
On the JoyStick's Arduino Fio, D2-D10 (= 9 bits) and A0-A4 (= 5 bits) are available
for use as DIPswitches (14 bits total).
Currently I'm envisioning using 4 of these bits to specify a heading argument for my
function calls to the Robot (the JoyStick only produces 16 possible heading values,
2 of which are Rotate left and right, rather than being any amount of forward/backward
motion.
Likewise 3 bits can be for invoking any one of 8 Robot functions.
The remaining 7 bits for can be for invoking one or all of 7 different Robot functions.
More on this in the next update (already partially fleshed out below).
Update:
------
Next: Write up DIP Switch-driven command syntax to send to the Robot.
To wit:
!r th cc Driving command: r=0-9 speed, th=0-15 direction, cc=checksum.
@xxx[=yyy] Query or set parameter xxx [to yyy] in the Robot's Parameters assoc. array.
%xxx[=yyy] Do the same in the JoyStick.
*xx nn cc Call function xx on the Robot (specified by the JoyStick's DIPswitches),
with nn arguments to follow, and cc=checksum.
(argVal cc An argument for the previous Robot function call.
Update:
------
Some notes for the upcoming Compass Calibration Line-Following Algorithm...
In libpololu-avr library that I downloaded from here:
https://www.pololu.com/docs/0J20/2.a
https://www.pololu.com/file/download/libpololu-avr-150324.zip?file_id=0J865
For completeness, more background is here:
https://www.pololu.com/docs/0J21/7
I'm looking in:
libpololu-avr\examples\atmega328p\3pi-demo-or-serial-slave\serial-slave.c
for the details on its PID algorithm.
I.e., in my Robot code, theoretically I would like to call this to smooth out my driving:
m3pi::PID_start( int max_speed, int a, int b, int c, int d)
I found above, that these arguments are:
proportional_numerator
proportional_denominator
derivative_numerator
derivative_denominator
used as follows:
int power_difference = proportional * p_num / p_den + derivative * d_num / d_den;
The motors will stop if either denominator is 0.
described as follows.
Sets up PID parameters and begins line following. The first data byte
sets the maximum motor speed. The next four bytes, a, b, c, and d,
represent the PID parameters.
Specifically, the difference in the motor speeds will be set to
(L-2000)×a/b + D×c/d, where L is the position of the line as described
above, and D is the derivative of L. The integral term is not implemented
in this program. See Section 7.c for more information on PID line following.
So the purpose of this PID implementation is only to adjust the ratio of wheel speeds
during line-following, and not during more generic driving :-(.
If I want to do line-following, I should call sensor_auto_calibrate() while sitting on
a black line on a white background. This will rotate the m3pi back and forth, so it can
calibrate to accurately see the line.
I found that the 3pi Slave code apparently does support:
0x87 read calibrated sensors (#defined as SEND_CALIBRATED_SENSOR_VALUES)
Reads all five IR sensors and sends calibrated values as a sequence of
two-byte ints, in the range 0-1000.
So after calling placing the Robot on a line and calling sensor_auto_calibrate(),
add a m3pi::read_calibrated_sensors() function, which I will use in my own function
that drives around "Compass\Compass Auto-Calibration Jig.png" to auto-calibrate the
Compass.
Update:
------
Now I'm building my Robot's "3rd Floor".
Aside: Headers: I have 3 different heights of right-angle headers, board-edge ones,
"normal"-height ones, and "tall" ones, ugh.