Sparki / Python Library

Hi all, this post is going to contain a lot of background, so for those of you looking for the tldr: I’ve written a library that you can upload to your Sparki, which can then be used with a library I’ve written for Python. You can write Python programs with this library and control your Sparki with Python. The github can be found here: https://github.com/radarjd/sparki_learning

Okay, so now the background, which will be cathartic for me if not interesting to anyone else. I teach a class in Robot Programming using the Institute for Personal Robotics in Education (IPRE) Myro library using the Scribbler 2 / Fluke robot combo. The IPRE provides a textbook free of charge, and use of this particular robot and the text predates my involvement with the class. The Myro API itself is fine, but the Calico Project IDE gives me and my students lots of problems. Moreover, it has its own internal implementation of Python, and cannot use many standard libraries.

About a year ago, I got a Sparki and saw its potential as a robot to be used in education. Unfortunately, there wasn’t a python library for it. Fortunately, it had Bluetooth, so I knew one could be written. I did not have the impetus to write the library at the time so I didn’t.

This year a local high school, targeted at poor and underprivileged but smart high school students, was founded and requested my help with the robotics program. We met and I suggested that they use the Sparki, though I noted that there wasn’t a Python library. There was some discussion that either the college (where I am an adjunct) or the high school would pay me for development of the library, but I heard little and forgot about it. Several months later, the high school contacted me and said they’d bought the robots and asked when the library might be available. They used their entire budget on the hardware purchase. Rather than leave them with expensive hardware (for an inner city school) and nothing to show for it, I wrote the libraries which are attached.

The concept behind the libraries is that Sparki runs an interpreter to which Python sends commands over Bluetooth:

While I am not the most talented of programmers, these were no small task. The C code which runs on the Sparki is 1199 lines (with internal spaces) and the Python code is 1952 lines (with internal spaces). They implement most of the Myro API, so an educator wishing to do so could make use of the existing materials published by the IPRE (see http://calicoproject.org/Learning_Computing_With_Robots_Using_Calico_Python). Further, using the Python library allows you to teach programming without the compile / upload cycle, and allows the students to get immediate feedback from their work.

I have tested the libraries to the extent I am able – I’m certain there are bugs and edge cases I have missed. The Sparki library was particularly challenging as I haven’t done extensive C++ programming since college, and the Sparki is extremely limited in space – the compiled library uses 28,650 bytes of the 28,672 bytes available. Adding the String data type pushed the robot over the limit, so everything is done with char*. Probably a better coder than I could have done better, and I hope someone will take what I’ve done and improve it. I have limited access to a Mac, so while I have tried the Python code out on it, there may be some implementation specific issues. I have not tried it on Linux at all.

The code is released under the Apache 2.0 license with one exception – I would ask that Arcbotics only link to the library and not distribute it. In an attempt to recoup some of my time, I contacted the company, but it was unwilling to pay anything at all for it. I understand that every business has to weigh costs and benefits, and they don’t see the benefits. That is fine, but it should not be distributed by them, nor should they create derivative works from it.

I hope this code is of use to students and educators. I have commented the code heavily and used a variety of techniques in the Python portion, which again I hope is useful. I did not use OOP – this was partially a stylistic choice, but also because I think it can be challenging for students who are not intending to be computer scientists or professional programmers. It’s not that elementary school students can’t be taught OOP, but I do think it can get in the way. Others can (and I’m sure, do) disagree, and that’s fine – rewrite or wrap it as an OOP library!

Sparki is a fantastic piece of hardware. I hope this library aids in your enjoyment of it and the enjoyment of your students. If anyone has any suggestions or finds any bugs, please let me know and I will try to fix them when I have the opportunity.

Very cool - and more thorough than I would have been.

Learned while connecting to Sparki via BlueTooth on Ubuntu linux:

playground.arduino.cc/Learning/ArduinoBT-Ubuntu

Assuming you bind the bluetooth device to 0, the port string in the init() command will be:

init("/dev/rfcomm0")

When running sparki_myro_test.py, i get the following error every time I execute getName():

File “~/sparki_learning/sparki_myro.py”, line 301, in getSerialBytes
return result.decode()
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xff in position 0: invalid start byte

I tried running setName first (no error) thinking that the problem was that no name had been written to the eeprom, but getName still fails with the error above.

Also, I have observed problems with the motors(), forward(), backward(), turnRight() and turnLeft() commands. turnBy() and turnTo() work fine. The non-working commands seem to run Sparki’s right motor for a very long time at normal speed, and Sparki’s left motor at a very very low speed.

[quote=“banda”]When running sparki_myro_test.py, i get the following error every time I execute getName():

File “~/sparki_learning/sparki_myro.py”, line 301, in getSerialBytes
return result.decode()
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xff in position 0: invalid start byte

I tried running setName first (no error) thinking that the problem was that no name had been written to the eeprom, but getName still fails with the error above.

Also, I have observed problems with the motors(), forward(), backward(), turnRight() and turnLeft() commands. turnBy() and turnTo() work fine. The non-working commands seem to run Sparki’s right motor for a very long time at normal speed, and Sparki’s left motor at a very very low speed.[/quote]

Interesting. What version of Python are you using and what’s your OS?

motors(), forward(), backward(), turnLeft(), and turnRight() all use the motors() command – that is, all of the other commands call motors. I noted an issue with motors() during development that caused a very similar issue, but it “fixed itself” as unhelpful as that is. The code that runs on the Sparki under the motors() command is what gave me fits, and I tried re-writing it many different ways. Eventually, it started working and I had done nothing which I believe should have fixed it. If you’re feeling adventurous, pull the motors() command on the sparki code into its own sketch and see if you can replicate the behavior.

Re: getName() – when the sparki turns on, does it display its name on the LCD? If it does, then things are being stored properly in the EEPROM.

Ubuntu 14.04.3 LTS
Python 3.4
pyserial 2.7 (Tried it with pyserial 3.x, no difference)
The name does not display at startup - rather I get a multi-line block of diamond characters followed by a single # sign. setName executes with no error, getName fails every time.

[quote=“banda”]Ubuntu 14.04.3 LTS
Python 3.4
pyserial 2.7 (Tried it with pyserial 3.x, no difference)
The name does not display at startup - rather I get a multi-line block of diamond characters followed by a single # sign. setName executes with no error, getName fails every time.[/quote]

It looks to me like the name is not being set correctly, which I can’t figure out. I have uploaded a sparki_name_util sketch to the github. Would you try loading sparki_name_util onto your sparki to see if it is able to set the name properly? It should write the name into the same EEPROM location where the sparki_myro library will look for it.

The differences in the functions setName() and loadName() from the main library are:

  1. Much more debugging output in both functions so you can see what is being read / written
  2. The loadName() function zeroes out the buffer that is sent to it – if that fixes things for you, then I will add that change to the main library

sparki_name_util seems to work fine!

[quote=“banda”]
sparki_name_util seems to work fine![/quote]

Great – thanks for trying that! I’ve moved that minor change into the main code. Can you re-upload the main library and get for the same error(s)? I’m thinking you’ll still get them on the Python side, but I’m hoping the Sparki’s LCD will be able to tell us something during startup.

Thanks again for your help with debugging this. Are you still having the same issues with the motors()? (I assume you are, but as I mentioned previously it fixed itself “magically” for me.)

Your update definitely solved the getName() issue. The motor behavior is unchanged. All the motors() based commands still yield the same results - the right motor turns at speed, the left motor inches incredibly slowly, and the command takes more than a minute to complete.

I’ve added a sketch called sparki_motors_util, and then a python program called sparki_myro_test_motors.py to the sparki_learning program. The sketch makes use of code identical to motors in the main library, but has some more debugging info. During the setup() of the sketch, sparki will use the motors command to move forward / backward / left / right. The function itself will display the input it’s getting on the LCD.

Once setup is done, you can run the sparki_myro_test_motors.py program. That will run through several functions, all which use motors. I’m trying to determine if the issue is communication between the libraries, or if there’s something going wrong in motors on the sparki itself. It works on mine, but as I’ve said, I had a problem similar to what you’re having.

Thanks again for your help debugging this. Hopefully we can work it out.

Bit of bad luck, I’m afraid: I was unable to successfully compile the sparki_motors_util.ino sketch. Not enough memory.
I’m using Arduino 1.6.7, and for “Board”, I’ve selected “Arduino Leonardo”. Here’s the verbose output from compilation:

[code]Arduino: 1.6.7 (Linux), Board: “Arduino Leonardo”

/home/bill/Downloads/arduino-1.6.7/arduino-builder -dump-prefs -logger=machine -hardware “/home/bill/Downloads/arduino-1.6.7/hardware” -tools “/home/bill/Downloads/arduino-1.6.7/tools-builder” -tools “/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr” -built-in-libraries “/home/bill/Downloads/arduino-1.6.7/libraries” -libraries “/home/bill/Arduino/libraries” -fqbn=arduino:avr:leonardo -vid-pid=0X2341_0X8036 -ide-version=10607 -build-path “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp” -warnings=none -prefs=build.warn_data_percentage=75 -verbose “/home/bill/Development/Arduino/sparki_learning/sparki_motors_util/sparki_motors_util.ino”
/home/bill/Downloads/arduino-1.6.7/arduino-builder -compile -logger=machine -hardware “/home/bill/Downloads/arduino-1.6.7/hardware” -tools “/home/bill/Downloads/arduino-1.6.7/tools-builder” -tools “/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr” -built-in-libraries “/home/bill/Downloads/arduino-1.6.7/libraries” -libraries “/home/bill/Arduino/libraries” -fqbn=arduino:avr:leonardo -vid-pid=0X2341_0X8036 -ide-version=10607 -build-path “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp” -warnings=none -prefs=build.warn_data_percentage=75 -verbose “/home/bill/Development/Arduino/sparki_learning/sparki_motors_util/sparki_motors_util.ino”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sketch/sparki_motors_util.ino.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sketch/sparki_motors_util.ino.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/home/bill/Arduino/libraries/Sparki/src/Radio.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/home/bill/Arduino/libraries/Sparki/src/SPI.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/home/bill/Arduino/libraries/Sparki/src/Sparki.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/home/bill/Arduino/libraries/Sparki/src/SparkiEEPROM.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/home/bill/Arduino/libraries/Sparki/src/SparkiWire.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sketch/sparki_motors_util.ino.cpp” -o “/dev/null”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sketch/sparki_motors_util.ino.cpp” -o “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/preproc/ctags_target_for_gcc_minus_e.cpp”
"/home/bill/Downloads/arduino-1.6.7/tools-builder/ctags/5.8-arduino5/ctags" -u --language-force=c++ -f - --c+±kinds=svpf --fields=KSTtzns --line-directives “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/preproc/ctags_target_for_gcc_minus_e.cpp”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “-I/home/bill/Arduino/libraries/Sparki/src” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sketch/sparki_motors_util.ino.cpp” -o “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sketch/sparki_motors_util.ino.cpp.o"
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/Radio.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/SPI.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/Sparki.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/SparkiEEPROM.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/SparkiWire.cpp.o
”/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-gcc" -c -g -x assembler-with-cpp -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 ‘-DUSB_MANUFACTURER=“Unknown”’ ‘-DUSB_PRODUCT=“Arduino Leonardo”’ “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino” “-I/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/variants/leonardo” “/home/bill/Downloads/arduino-1.6.7/hardware/arduino/avr/cores/arduino/wiring_pulse.S” -o “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_pulse.S.o"
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/WInterrupts.c.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/hooks.c.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring.c.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_analog.c.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_digital.c.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_pulse.c.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_shift.c.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/CDC.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial0.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial1.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial2.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial3.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/IPAddress.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/PluggableUSB.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/Print.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/Stream.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/Tone.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/USBCore.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/WMath.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/WString.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/abi.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/main.cpp.o
Using previously compiled file: /tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/new.cpp.o
”/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_pulse.S.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/WInterrupts.c.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/hooks.c.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring.c.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_analog.c.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_digital.c.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_pulse.c.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/wiring_shift.c.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/CDC.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial0.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial1.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial2.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/HardwareSerial3.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/IPAddress.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/PluggableUSB.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/Print.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/Stream.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/Tone.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/USBCore.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/WMath.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/WString.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/abi.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/main.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-ar" rcs “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/new.cpp.o”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-gcc" -w -Os -Wl,–gc-sections -mmcu=atmega32u4 -o “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sparki_motors_util.ino.elf” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sketch/sparki_motors_util.ino.cpp.o” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/Radio.cpp.o” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/SPI.cpp.o” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/Sparki.cpp.o” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/SparkiEEPROM.cpp.o” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/libraries/Sparki/SparkiWire.cpp.o” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/core/core.a” “-L/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp” -lm
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sparki_motors_util.ino.elf” “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sparki_motors_util.ino.eep”
"/home/bill/Downloads/arduino-1.6.7/hardware/tools/avr/bin/avr-objcopy" -O ihex -R .eeprom “/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sparki_motors_util.ino.elf” "/tmp/build73e5710f10f17f54cbc99e616750bdf1.tmp/sparki_motors_util.ino.hex"
Using library Sparki at version 1.661 in folder: /home/bill/Arduino/libraries/Sparki

Sketch uses 20,104 bytes (70%) of program storage space. Maximum is 28,672 bytes.
Global variables use 2,588 bytes (101%) of dynamic memory, leaving -28 bytes for local variables. Maximum is 2,560 bytes.
processing.app.debug.RunnerException: Not enough memory; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing your footprint.
at cc.arduino.Compiler.size(Compiler.java:319)
at cc.arduino.Compiler.build(Compiler.java:156)
at processing.app.Sketch.build(Sketch.java:1108)
at processing.app.Sketch.build(Sketch.java:1083)
at processing.app.Editor$BuildHandler.run(Editor.java:2011)
at java.lang.Thread.run(Thread.java:745)
Not enough memory; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing your footprint.[/code]

[quote=“banda”]Bit of bad luck, I’m afraid: I was unable to successfully compile the sparki_motors_util.ino sketch. Not enough memory.
I’m using Arduino 1.6.7, and for “Board”, I’ve selected “Arduino Leonardo”. [/quote]

I have never personally compiled using Arduino software – only the Sparkiduino with the ArcBotics Sparki board selected. It compiles without issue on my machine with those settings. Have you tried the Sparkiduino software?

Wait, you’re on Ubuntu, so maybe that isn’t an option for you? It looks from your error like the global variables are the problem (Global variables use 2,588 bytes (101%) of dynamic memory, leaving -28 bytes for local variables. Maximum is 2,560 bytes.), which is odd, because that sketch should use less global space than the main library.

Hmmm… so, if you’re comfortable editing Sparki.h, you could uncomment //#define NO_MAG and //#define NO_ACCEL (but you’ll have to remember to re-comment those). I don’t know if that will fix the global variable issue, though.

Perhaps the compiler is statically allocating space for the debug strings as globals? I have no idea how the arduino compiler works – I would not call those global variables, but perhaps it includes those… I’m trying to figure out how you could be exceeding the available space. My guess is that Sparki is closest to a Leonardo but not actually a Leonardo, which is why you would get a different amount of memory available – that’s just a guess, though. If you want to try out this theory, you could comment out the printDebugs inside the setup() function (just put a // at the beginning of the line), and then try to re-upload. Sorry I’m not of more help here – I don’t have access to a linux machine to try this. I’ve got a raspberry pi that I could repurpose, but don’t have the time right now.

I uploaded a very minor revision of sparki_motors_util.ino that comments out those strings to see if it fixes the issues.

I also uploaded a revised sparki_myro.py library with the DEBUG version, and a new command: getUptime() which returns the number of milliseconds since the robot was initialized.

I just pushed a new update to the github repository (https://github.com/radarjd/sparki_learning) with version 1.1.0 of the python library containing what I’m calling the “grid commands”. The following commands have been added:
drawFunction(function, xvals) - draws the function given on the coordinate plane; the function given as the argument should be a lambda function which calculates the y coordinate for a given x; the xvals argument should be an iterable of the x values for which to calculate a y value; a test / example python file has also been added demonstrating the use of this function

getAngle() - returns the current heading of the robot in degrees, where Sparki starts at 0 degrees when initialized; only turns done through turnBy() will be “tracked” for the purposes of this command; a heading of 0 is treated as going up the y axis

getPosition() - returns the current position of Sparki on the coordinate plane

moveBy(x,y) - moves to the x,y position relative to the current position; the behavior of this command is exactly the same as a moveTo() executed immediately following initialization

moveTo(x,y) - moves to the x,y position indicated on the coordinate plane

resetPosition() - resets the position to a heading of 0 and a current position of 0,0

setAngle(degrees) - sets the current heading of the Sparki

setPosition(x,y) - sets the current position on the coordinate plane

The turnTo(degrees) command has had its behavior changed since the previous version. It will now turn to the heading given as the argument.

The python library will maintain an internal x,y coordinate on a coordinate plane so long as you’re using the moveTo() and moveBy() commands. drawFunction() uses moveTo() internally, and so will also maintain the current coordinates.

Each integer position is 1cm away from the next. That is, 0,1 is one cm up the y axis from 0,0. 1,1 is sqrt(2) cm from 0,0.

The commands rely on the Sparki’s internal moveBackward(), moveForward(), moveLeft() and moveRight() commands which seem to be quite accurate. The shapes that you can draw with the coordinate plane are very cool.

I have updated the increasingly inaccurately named “quick” reference to include descriptions of the new commands.

For the next update, I’m hoping to get a setup.py working, and then upload the library to Pypi for easy distribution.

Please let me know if any bugs, errors, etc.

edit: noted change in behavior for turnTo()

I just uploaded a new version of the library (https://github.com/radarjd/sparki_learning) which simply moved the files around. I’m preparing to provide a setup.py file, and to post the library on PyPI. To do that, I wanted a more sane directory structure.

All files which might be used on the Sparki itself are now located in the sparkiduino folder. The sparki_myro library to be loaded onto your sparki can be downloaded from there.

Example / test files are found in the examples folder.

Documentation (excepting the readme) are located in the docs folder. I intend to write a non-Word version of the documentation.

The main python library is in the sparki_learning subfolder, which is how this library will be known on PyPI (at least, that’s my intention).

Finally, I wanted to mention that I have tried out the library on Python 2.7 and everything appears so far to work just fine. I’d be interested to know if anyone else has success on 2.7.

The library is now available on PyPI - the Python Package Index - at https://pypi.python.org/pypi/sparki-learning. Note that there’s a dash instead of an underscore. I can’t figure out how to fix that.

So, if you’ve already got the code loaded onto your sparki using the Sparkiduino software, and you have a valid python install, you should just be able to do:

and it will take care of any necessary dependencies and install the library into the proper location.

If you download the code from github, you can install the library from its directory with:

Please let me know if there are problems with this. I’ve tested it some, and I’m going to test it more. I’m intending to look at the sparkiduino software next to see if I can fit a couple more LCD commands onto it. I’ve also got a pair of library commands in testing which are intended to make it easier to sync multiple sparkis actions.

While working on a revision to add some EEPROM commands and allow drawing lines and strings, the motors() problem reported by banta has reappeared. The motors() command works just fine on the sparki itself, but when sent a motors commands from python, it does not work. Specifically, the robot turns the right wheel on full power and the left wheel on at 1% power. I’m trying to figure out why as the python code hasn’t changed at all. My best guess at present is a memory (RAM) issue, but I’m continuing to debug this.

Also, does anyone know if the behavior of systemVoltage() from Sparki.cpp has changed intentionally? Previously, it was returning a voltage which appeared to be accurate, but with the most recent version of Sparkiduino, it appears the voltage is reported as being much lower.

I believe I have figured out the problem and fixed it in the most recent version, which is available on github (github.com/radarjd/sparki_learning and pypi “easy_install sparki-learning”).

Prior to this version, the call to motors() in the .ino file looked like this:

case COMMAND_MOTORS: // int, int, float; returns nothing motors( getSerialInt(), getSerialInt(), getSerialFloat() ); break;
On the version of Sparkiduino I originally used to develop the code, that worked just fine. However, with the newest version of Sparkiduino, the above call would cause the variables to become “jumbled”. The argument passed over the serial part for time was used for the left wheel (which is the first argument), and the argument passed over the serial port for the left wheel speed was used for the time (which is the last argument). I had thought it was a memory issue, because it used to work and then suddenly did not. However, debugging the code, I figured out that the arguments were actually being passed on the wrong order because the compiler was performing the getSerialFloat() call first. Each of the getSerial_____() calls checks the serial port for information and reads off whatever is available up until the terminator character. It is critical, therefore, that the calls happen in the right order. That is, if the data coming in to the serial port looks like this:
50, 50, 1.5
the order that the data must be read should be left_speed, right_speed, time. That’s the order I wrote it in the call above ( getSerialInt(), getSerialInt(), getSerialFloat() ). The compiler, however, processed the calls from right to left instead of left to right, so it was doing the getSerialFloat() first, and passing the value of 50 to the function. To fix this problem, I had to ensure the calls were made in the correct order, so I changed the code to

case COMMAND_MOTORS: // int, int, float; returns nothing { int left_speed = getSerialInt(); int right_speed = getSerialInt(); int time_length = getSerialFloat(); motors( left_speed, right_speed, time_length ); break; } // end COMMAND_MOTORS
This appears to fix the motors issue which user banda first reported some time ago (and if he or she is still around, I’d love to know if this did indeed fix the problem). Several other calls were done the same way in the switch statement, and I changed those to follow this paradigm as well.

The most recent release also includes the following new commands:
EEPROMread(location, amount) - Reads amount bytes of data at location in the EEPROM.

EEPROMwrite(location, data) - Writes data to location in the EEPROM.

LCDdrawLine() - Draws a line from X1, Y1 to X2, Y2 on the LCD.

LCDdrawString()- Prints message to the LCD on the back of Sparki at the X, Y coordinate given.

LCDreadPixel() - Returns True if the color of the pixel at X, Y on the LCD is colored in; otherwise returns False.

Please let me know if you find any issues.

Hi, I want to send commands from my android device to Sparki using sparki_myro. What are the commands and the string format required to send to Sparki. Please advise.

Thank you very much.