Skip to content

Instantly share code, notes, and snippets.

@ddemidov
Last active September 26, 2016 08:15
Show Gist options
  • Save ddemidov/fc6987229e8f846dbf157f6f063aac26 to your computer and use it in GitHub Desktop.
Save ddemidov/fc6987229e8f846dbf157f6f063aac26 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <thread>
#include <chrono>
#include <random>
#include <map>
#include <string>
#include <vector>
#include <stdexcept>
#include <ev3dev.h>
using namespace ev3dev;
template <class T>
T random_choice(const std::vector<T> &v) {
static std::random_device rd;
static std::mt19937 gen(rd());
std::uniform_int_distribution<int> pos(0, v.size()-1);
return v[pos(gen)];
}
class ev3rstorm {
public:
ev3rstorm() : lm("outB"), rm("outC") {
check(lm.connected(), "My left leg is missing!");
check(rm.connected(), "Right leg is not found!");
check(mm.connected(), "My left arm is not connected!");
check(ir.connected(), "My eyes, I can not see!");
check(ts.connected(), "Touch sensor is not attached!");
check(cs.connected(), "Color sensor is not responding!");
lm.reset(); lm.set_stop_action("brake");
rm.reset(); rm.set_stop_action("brake");
mm.reset(); mm.set_stop_action("brake");
quote("initiating");
}
// Shot a ball in the specified direction
// (valid choices are 'up' and 'down').
void shoot(std::string direction = "up") {
mm.set_speed_sp(900)
.set_position_sp(direction == "up" ? -1080 : 1080)
.run_to_rel_pos();
while(mm.state().count("running"))
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
// Enter the remote control loop.
// RC buttons on channel 1 control the robot movement, channel 2 is for
// shooting things. The loop ends when the touch sensor is pressed.
void rc_loop() {
typedef std::vector<led*> led_group;
remote_control rc1(ir, 1);
remote_control rc2(ir, 2);
/*
Generate remote control event handler. It rolls given motor into
given direction (1 for forward, -1 for backward). When motor rolls
forward, the given led group flashes green, when backward -- red.
When motor stops, the leds are turned off.
The generated lambda function has signature required by the
remote_control class. It takes boolean state parameter; true
when button is pressed, talse otherwise.
*/
auto make_roll = [this](large_motor &m, led_group &l, int speed) {
return [&](bool state) {
if (state) {
m.set_speed_sp(speed)
.run_forever();
led::set_color(l, speed > 0 ? led::green : led::red);
} else {
m.stop();
led::set_color(l, led::black);
}
};
};
auto make_shoot = [this](std::string direction) {
return [&](bool state) {
if (state) shoot(direction);
};
};
rc1.on_red_up = make_roll(lm, led::left, 900);
rc1.on_red_down = make_roll(lm, led::left, -900);
rc1.on_blue_up = make_roll(rm, led::right, 900);
rc1.on_blue_down = make_roll(rm, led::right, -900);
rc2.on_red_up = make_shoot("up");
rc2.on_blue_up = make_shoot("up");
rc2.on_red_down = make_shoot("down");
rc2.on_blue_down = make_shoot("down");
while(!ts.is_pressed()) {
rc1.process();
rc2.process();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
private:
large_motor lm;
large_motor rm;
medium_motor mm;
infrared_sensor ir;
touch_sensor ts;
color_sensor cs;
// Recite a random Marvin the Paranoid Android quote on the specified topic.
// See https://en.wikipedia.org/wiki/Marvin_(character)
static void quote(std::string topic) {
using namespace std;
static map<string, vector<string>> marvin_quotes = {
{
"initiating", {
"Life? Don't talk to me about life!",
"Now I've got a headache.",
"This will all end in tears.",
}
},
{
"depressed", {
"I think you ought to know I'm feeling very depressed.",
"Incredible... it's even worse than I thought it would be.",
"I'd make a suggestion, but you wouldn't listen.",
}
}
};
sound::speak(random_choice(marvin_quotes[topic]), true);
}
// Check that condition is true,
// loudly complain and throw an exception otherwise.
static void check(bool cond, std::string message) {
if (!cond) {
sound::speak(message, true);
quote("depressed");
throw std::runtime_error(message);
}
}
};
int main(int argc, char *argv[]) {
ev3rstorm().rc_loop();
}
#!/usr/bin/env python3
import time, random
import ev3dev.ev3 as ev3
random.seed( time.time() )
def quote(topic):
"""
Recite a random Marvin the Paranoid Android quote on the specified topic.
See https://en.wikipedia.org/wiki/Marvin_(character)
"""
marvin_quotes = {
'initiating' : (
"Life? Don't talk to me about life!",
"Now I've got a headache.",
"This will all end in tears.",
),
'depressed' : (
"I think you ought to know I'm feeling very depressed.",
"Incredible... it's even worse than I thought it would be.",
"I'd make a suggestion, but you wouldn't listen.",
),
}
ev3.Sound.speak(random.choice(marvin_quotes[topic])).wait()
def check(condition, message):
"""
Check that condition is true,
loudly complain and throw an exception otherwise.
"""
if not condition:
ev3.Sound.speak(message).wait()
quote('depressed')
raise Exception(message)
class ev3rstorm:
def __init__(self):
# Connect the required equipement
self.lm = ev3.LargeMotor('outB')
self.rm = ev3.LargeMotor('outC')
self.mm = ev3.MediumMotor()
self.ir = ev3.InfraredSensor()
self.ts = ev3.TouchSensor()
self.cs = ev3.ColorSensor()
self.screen = ev3.Screen()
# Check if everything is attached
check(self.lm.connected, 'My left leg is missing!')
check(self.rm.connected, 'Right leg is not found!')
check(self.mm.connected, 'My left arm is not connected!')
check(self.ir.connected, 'My eyes, I can not see!')
check(self.ts.connected, 'Touch sensor is not attached!')
check(self.cs.connected, 'Color sensor is not responding!')
# Reset the motors
for m in (self.lm, self.rm, self.mm):
m.reset()
m.position = 0
m.stop_action = 'brake'
self.draw_face()
quote('initiating')
def draw_face(self):
w,h = self.screen.shape
y = h // 2
eye_xrad = 20
eye_yrad = 30
pup_xrad = 10
pup_yrad = 10
def draw_eye(x):
self.screen.draw.ellipse((x-eye_xrad, y-eye_yrad, x+eye_xrad, y+eye_yrad))
self.screen.draw.ellipse((x-pup_xrad, y-pup_yrad, x+pup_xrad, y+pup_yrad), fill='black')
draw_eye(w//3)
draw_eye(2*w//3)
self.screen.update()
def shoot(self, direction='up'):
"""
Shot a ball in the specified direction (valid choices are 'up' and 'down')
"""
self.mm.run_to_rel_pos(speed_sp=900, position_sp=(-1080 if direction == 'up' else 1080))
while 'running' in self.mm.state:
time.sleep(0.1)
def rc_loop(self):
"""
Enter the remote control loop. RC buttons on channel 1 control the
robot movement, channel 2 is for shooting things.
The loop ends when the touch sensor is pressed.
"""
def roll(motor, led_group, speed):
"""
Generate remote control event handler. It rolls given motor into
given direction (1 for forward, -1 for backward). When motor rolls
forward, the given led group flashes green, when backward -- red.
When motor stops, the leds are turned off.
The on_press function has signature required by RemoteControl
class. It takes boolean state parameter; True when button is
pressed, False otherwise.
"""
def on_press(state):
if state:
# Roll when button is pressed
motor.run_forever(speed_sp=speed)
ev3.Leds.set_color(led_group,
ev3.Leds.GREEN if speed > 0 else ev3.Leds.RED)
else:
# Stop otherwise
motor.stop()
ev3.Leds.set_color(led_group, ev3.Leds.BLACK)
return on_press
rc1 = ev3.RemoteControl(self.ir, 1)
rc1.on_red_up = roll(self.lm, ev3.Leds.LEFT, 900)
rc1.on_red_down = roll(self.lm, ev3.Leds.LEFT, -900)
rc1.on_blue_up = roll(self.rm, ev3.Leds.RIGHT, 900)
rc1.on_blue_down = roll(self.rm, ev3.Leds.RIGHT, -900)
def shoot(direction):
def on_press(state):
if state: self.shoot(direction)
return on_press
rc2 = ev3.RemoteControl(self.ir, 2)
rc2.on_red_up = shoot('up')
rc2.on_blue_up = shoot('up')
rc2.on_red_down = shoot('down')
rc2.on_blue_down = shoot('down')
# Now that the event handlers are assigned,
# lets enter the processing loop:
while not self.ts.is_pressed():
rc1.process()
rc2.process()
time.sleep(0.1)
if __name__ == '__main__':
Marvin = ev3rstorm()
Marvin.rc_loop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment