Mining system completegit add .!

This commit is contained in:
2018-07-29 21:46:10 -07:00
parent b79693c855
commit 092318ec10
20 changed files with 1223 additions and 310 deletions

View File

@@ -11,7 +11,7 @@
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="00", SYMLINK+="rover/ttyREAR" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="00", SYMLINK+="rover/ttyREAR"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="rover/ttyLEFT" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="rover/ttyLEFT"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="02", SYMLINK+="rover/ttyRIGHT" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="02", SYMLINK+="rover/ttyRIGHT"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="03", SYMLINK+="rover/ttyIRIS_0_3" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2CZLZF", ENV{ID_USB_INTERFACE_NUM}=="03", SYMLINK+="rover/ttyEffectors"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2HPA6V", ENV{ID_USB_INTERFACE_NUM}=="00", SYMLINK+="rover/ttyIRIS_1_0" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2HPA6V", ENV{ID_USB_INTERFACE_NUM}=="00", SYMLINK+="rover/ttyIRIS_1_0"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2HPA6V", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="rover/ttyTowerAndPanTilt" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="NM2HPA6V", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="rover/ttyTowerAndPanTilt"

View File

@@ -1,3 +1,4 @@
#!/bin/bash #!/bin/bash
sudo cp 99-rover-cameras.rules /etc/udev/rules.d/. sudo cp 99-rover-cameras.rules /etc/udev/rules.d/.
sudo cp 99-rover-usb-serial.rules /etc/udev/rules.d/. sudo cp 99-rover-usb-serial.rules /etc/udev/rules.d/.
sudo reboot

View File

@@ -1,289 +1,335 @@
////////// Includes ////////// ////////// Includes //////////
#include "HX711.h" #include "HX711.h"
#include <ModbusRtu.h>
////////// Hardware / Data Enumerations //////////
enum HARDWARE { ////////// Hardware / Data Enumerations //////////
RS485_EN = 6, enum HARDWARE {
RS485_RX = 9, RS485_EN = 6,
RS485_TX = 10, RS485_RX = 9,
RS485_TX = 10,
MOTOR_LIFT_A = 27,
MOTOR_LIFT_B = 28, MOTOR_LIFT_A = 27,
MOTOR_LIFT_PWM = 25, MOTOR_LIFT_B = 28,
MOTOR_LIFT_CS = 31, MOTOR_LIFT_PWM = 25,
MOTOR_LIFT_EN = 24, MOTOR_LIFT_CS = 31,
MOTOR_LIFT_FB = A10, MOTOR_LIFT_EN = 24,
MOTOR_LIFT_FB = A10,
MOTOR_TILT_A = 30,
MOTOR_TILT_B = 29, MOTOR_TILT_A = 30,
MOTOR_TILT_PWM = 32, MOTOR_TILT_B = 29,
MOTOR_TILT_CS = 26, MOTOR_TILT_PWM = 32,
MOTOR_TILT_EN = 33, MOTOR_TILT_CS = 26,
MOTOR_TILT_FB = A11, MOTOR_TILT_EN = 33,
MOTOR_TILT_FB = A11,
LED_13 = 13,
LED_13 = 13,
LED_RED = 20,
LED_BLUE = 21, LED_RED = 20,
LED_GREEN = 22, LED_BLUE = 21,
LED_GREEN = 22,
SCALE_DOUT = 8,
SCALE_CLK = 7 SCALE_DOUT = 8,
SCALE_CLK = 7
};
};
enum MOTORS {
LIFT = 0, enum MOTORS {
TILT = 1, LIFT = 0,
}; TILT = 1,
};
enum MODBUS_REGISTERS {
// Inputs enum MODBUS_REGISTERS {
SET_POSITION_LIFT = 0, // Inputs
SET_POSITION_TILT = 1, SET_POSITION_LIFT_POSITIVE = 0,
TARE = 2, SET_POSITION_LIFT_NEGATIVE = 1,
CALIBRATION_FACTOR = 3, SET_POSITION_TILT_POSITIVE = 2,
SET_POSITION_TILT_NEGATIVE = 3,
// Outputs SET_POSITION_LIFT_ABSOLUTE = 4,
CURRENT_POSITION_LIFT = 4, SET_POSITION_TILT_ABSOLUTE = 5,
CURRENT_POSITION_TILT = 5, MEASURE = 6,
MEASURED_WEIGHT = 6, TARE = 7,
}; CALIBRATION_FACTOR = 8,
////////// Global Variables ////////// // Outputs
int set_position_lift = 0; CURRENT_POSITION_LIFT = 9,
int set_position_tilt = 0; CURRENT_POSITION_TILT = 10,
int tolerance = 20; //tolerance for position MEASURED_WEIGHT = 11
};
float calibration_factor = -120000; //for the scale
////////// Global Variables //////////
// modbus stuff int set_position_lift = 1023;
const uint8_t node_id = 2; int set_position_tilt = 350;
const uint8_t mobus_serial_port_number = 3; int current_position_lift = 0;
uint16_t modbus_data[] = {0, 0, 0, 0, 0, 0, 0}; int current_position_tilt = 0;
uint8_t num_modbus_registers = 0; int tolerance = 20; //tolerance for position
int8_t poll_state = 0;
bool communication_good = false; float last_calibration_factor = -120000; //for the scale
uint8_t message_count = 0;
// modbus stuff
// nice human words for motor states const uint8_t node_id = 2;
#define BRAKEVCC 0 const uint8_t mobus_serial_port_number = 2;
#define CW 1 uint16_t modbus_data[] = {0, 0, 0, 0, 9999, 9999, 0, 0, 972, 0, 0, 0};
#define CCW 2 uint8_t num_modbus_registers = 0;
#define BRAKEGND 3 int8_t poll_state = 0;
bool communication_good = false;
////////// Class Instantiations ////////// uint8_t message_count = 0;
Modbus slave(node_id, mobus_serial_port_number, HARDWARE::RS485_EN);
// nice human words for motor states
void setup() { #define BRAKEVCC 0
Serial.begin(9600); // debug #define CW 1
#define CCW 2
setup_hardware(); #define BRAKEGND 3
num_modbus_registers = sizeof(modbus_data) / sizeof(modbus_data[0]);
slave.begin(115200); // baud-rate at 19200 ////////// Class Instantiations //////////
slave.setTimeOut(150); HX711 scale(HARDWARE::SCALE_DOUT, HARDWARE::SCALE_CLK);
} Modbus slave(node_id, mobus_serial_port_number, HARDWARE::RS485_EN);
void loop() { void setup() {
poll_modbus(); Serial.begin(9600); // debug
set_leds(); // while(!Serial);
set_motors();
set_scale(); setup_hardware();
poll_scale(); num_modbus_registers = sizeof(modbus_data) / sizeof(modbus_data[0]);
} slave.begin(115200); // baud-rate at 19200
slave.setTimeOut(200);
void setup_hardware() { }
pinMode(HARDWARE::RS485_EN, OUTPUT);
void loop() {
pinMode(HARDWARE::MOTOR_LIFT_A, OUTPUT); poll_modbus();
pinMode(HARDWARE::MOTOR_LIFT_B, OUTPUT); set_leds();
pinMode(HARDWARE::MOTOR_LIFT_PWM, OUTPUT); set_motors();
pinMode(HARDWARE::MOTOR_LIFT_EN, OUTPUT); set_scale();
pinMode(HARDWARE::MOTOR_LIFT_CS, INPUT); poll_scale();
pinMode(HARDWARE::MOTOR_LIFT_FB, INPUT); }
pinMode(HARDWARE::MOTOR_TILT_A, OUTPUT); void setup_hardware() {
pinMode(HARDWARE::MOTOR_TILT_B, OUTPUT); pinMode(HARDWARE::RS485_EN, OUTPUT);
pinMode(HARDWARE::MOTOR_TILT_PWM, OUTPUT);
pinMode(HARDWARE::MOTOR_TILT_EN, OUTPUT); pinMode(HARDWARE::MOTOR_LIFT_A, OUTPUT);
pinMode(HARDWARE::MOTOR_TILT_CS, INPUT); pinMode(HARDWARE::MOTOR_LIFT_B, OUTPUT);
pinMode(HARDWARE::MOTOR_TILT_FB, INPUT); pinMode(HARDWARE::MOTOR_LIFT_PWM, OUTPUT);
pinMode(HARDWARE::MOTOR_LIFT_EN, OUTPUT);
pinMode(HARDWARE::LED_13, OUTPUT); pinMode(HARDWARE::MOTOR_LIFT_CS, INPUT);
pinMode(HARDWARE::LED_RED, OUTPUT); pinMode(HARDWARE::MOTOR_LIFT_FB, INPUT);
pinMode(HARDWARE::LED_BLUE, OUTPUT);
pinMode(HARDWARE::LED_GREEN, OUTPUT); pinMode(HARDWARE::MOTOR_TILT_A, OUTPUT);
pinMode(HARDWARE::MOTOR_TILT_B, OUTPUT);
// set defualt states pinMode(HARDWARE::MOTOR_TILT_PWM, OUTPUT);
digitalWrite(HARDWARE::LED_RED, LOW); pinMode(HARDWARE::MOTOR_TILT_EN, OUTPUT);
digitalWrite(HARDWARE::LED_GREEN, HIGH); pinMode(HARDWARE::MOTOR_TILT_CS, INPUT);
digitalWrite(HARDWARE::LED_BLUE, HIGH); pinMode(HARDWARE::MOTOR_TILT_FB, INPUT);
digitalWrite(HARDWARE::LED_13, LOW);
digitalWrite(HARDWARE::MOTOR_LIFT_EN, HIGH); pinMode(HARDWARE::LED_13, OUTPUT);
digitalWrite(HARDWARE::MOTOR_TILT_EN, HIGH); pinMode(HARDWARE::LED_RED, OUTPUT);
pinMode(HARDWARE::LED_BLUE, OUTPUT);
// Change motor PWM frequency so it's not in the audible range pinMode(HARDWARE::LED_GREEN, OUTPUT);
analogWriteFrequency(HARDWARE::MOTOR_LIFT_PWM, 25000);
analogWriteFrequency(HARDWARE::MOTOR_TILT_PWM, 25000); // set defualt states
digitalWrite(HARDWARE::LED_RED, LOW);
// set the current desired position to the current position digitalWrite(HARDWARE::LED_GREEN, HIGH);
set_position_lift = analogRead(HARDWARE::MOTOR_LIFT_FB); digitalWrite(HARDWARE::LED_BLUE, HIGH);
set_position_tilt = analogRead(HARDWARE::MOTOR_TILT_FB); digitalWrite(HARDWARE::LED_13, LOW);
digitalWrite(HARDWARE::MOTOR_LIFT_EN, HIGH);
// setup scale digitalWrite(HARDWARE::MOTOR_TILT_EN, HIGH);
scale.set_scale();
scale.tare(); //Reset the scale to 0 // Change motor PWM frequency so it's not in the audible range
scale.set_scale(calibration_factor); analogWriteFrequency(HARDWARE::MOTOR_LIFT_PWM, 25000);
} analogWriteFrequency(HARDWARE::MOTOR_TILT_PWM, 25000);
void poll_modbus(){ // set the current desired position to the current position
poll_state = slave.poll(modbus_data, num_modbus_registers); // set_position_lift = analogRead(HARDWARE::MOTOR_LIFT_FB);
communication_good = !slave.getTimeOutState(); // set_position_tilt = analogRead(HARDWARE::MOTOR_TILT_FB);
} current_position_lift = analogRead(HARDWARE::MOTOR_LIFT_FB);
current_position_tilt = analogRead(HARDWARE::MOTOR_TILT_FB);
void set_leds(){
if(poll_state > 4){ // setup scale
message_count++; scale.set_scale(last_calibration_factor);
if(message_count > 2){ scale.tare(); //Reset the scale to 0
digitalWrite(HARDWARE::LED_13, !digitalRead(HARDWARE::LED_13)); }
message_count = 0;
} void poll_modbus(){
poll_state = slave.poll(modbus_data, num_modbus_registers);
digitalWrite(HARDWARE::LED_GREEN, LOW); communication_good = !slave.getTimeOutState();
digitalWrite(HARDWARE::LED_RED, HIGH); }
}else if(!communication_good){
digitalWrite(HARDWARE::LED_13, LOW); void set_leds(){
digitalWrite(HARDWARE::LED_GREEN, HIGH); if(poll_state > 4){
digitalWrite(HARDWARE::LED_RED, LOW); message_count++;
} if(message_count > 2){
} digitalWrite(HARDWARE::LED_13, !digitalRead(HARDWARE::LED_13));
message_count = 0;
void set_motors() { }
set_position_lift = modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT];
set_position_tilt = modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT]; digitalWrite(HARDWARE::LED_GREEN, LOW);
digitalWrite(HARDWARE::LED_RED, HIGH);
current_position_lift = analogRead(HARDWARE::MOTOR_LIFT_FB); }else if(!communication_good){
current_position_tilt = analogRead(HARDWARE::MOTOR_TILT_FB); digitalWrite(HARDWARE::LED_13, LOW);
digitalWrite(HARDWARE::LED_GREEN, HIGH);
if (abs(current_position_lift - set_position_lift) > tolerance) { digitalWrite(HARDWARE::LED_RED, LOW);
if (current_position_lift < set_position_lift) { }
set_motor_output(MOTORS::LIFT, CCW, 255); }
}
else { void set_motors() {
set_motor_output(MOTORS::LIFT, CW, 255); if (modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT_ABSOLUTE] < 1024 ){
} set_position_lift = modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT_ABSOLUTE];
} modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT_ABSOLUTE] = 1024;
else { }else{
motor_off(MOTORS::LIFT); set_position_lift += modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT_POSITIVE] - modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT_NEGATIVE];
} set_position_lift = constrain(set_position_lift, 0, 1023);
if (abs(current_position_tilt - set_position_tilt) > tolerance) { modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT_POSITIVE] = 0;
if (current_position_tilt < set_position_tilt) { modbus_data[MODBUS_REGISTERS::SET_POSITION_LIFT_NEGATIVE] = 0;
set_motor_output(MOTORS::TILT, CCW, 255); }
}
else { if(modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT_ABSOLUTE] < 1024){
set_motor_output(MOTORS::TILT, CW, 255); set_position_tilt = modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT_ABSOLUTE];
} modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT_ABSOLUTE] = 1024;
} }else{
else { set_position_tilt += modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT_POSITIVE] - modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT_NEGATIVE] ;
motor_off(MOTORS::TILT); set_position_tilt = constrain(set_position_tilt, 0, 1023);
}
} modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT_POSITIVE] = 0;
modbus_data[MODBUS_REGISTERS::SET_POSITION_TILT_NEGATIVE] = 0;
void set_scale(){ }
scale.set_scale(modbus_data[MODBUS_REGISTERS::CALIBRATION_FACTOR]);
} current_position_lift = analogRead(HARDWARE::MOTOR_LIFT_FB);
current_position_tilt = analogRead(HARDWARE::MOTOR_TILT_FB);
void poll_scale(){
modbus_data[MODBUS_REGISTERS::MEASURED_WEIGHT] = scale.get_units()*-1 modbus_data[MODBUS_REGISTERS::CURRENT_POSITION_LIFT] = current_position_lift;
} modbus_data[MODBUS_REGISTERS::CURRENT_POSITION_TILT] = current_position_tilt;
//---Set Motor Output---// if (abs(current_position_lift - set_position_lift) > tolerance) {
/* if (current_position_lift < set_position_lift) {
Inputs: motor number, direction, pwm value set_motor_output(MOTORS::LIFT, CCW, 255);
Returns: nothing }
else {
Will set a motor going in a specific direction the motor will continue set_motor_output(MOTORS::LIFT, CW, 255);
going in that direction, at that speed until told to do otherwise. }
}
direct: Should be between 0 and 3, with the following result else {
0: Brake to VCC motor_off(MOTORS::LIFT);
1: Clockwise }
2: CounterClockwise
3: Brake to GND if (abs(current_position_tilt - set_position_tilt) > tolerance) {
if (current_position_tilt < set_position_tilt) {
pwm: should be a value between 0 and 255, higher the number, the faster set_motor_output(MOTORS::TILT, CCW, 255);
it'll go }
---------------- else {
Control Logic: set_motor_output(MOTORS::TILT, CW, 255);
---------------- }
A | B }
Brake VCC: 1 1 else {
CW: 1 0 motor_off(MOTORS::TILT);
CCW: 0 1 }
Brake GND: 0 0 }
----------------
*/ void set_scale(){
void set_motor_output(int motor, int direction, int pwm_input) { float cal_factor = modbus_data[MODBUS_REGISTERS::CALIBRATION_FACTOR] * -100;
if(cal_factor != last_calibration_factor){
int a; scale.set_scale(cal_factor);
int b; last_calibration_factor = cal_factor;
int pwm; }
if (motor == MOTORS::LIFT) { if (modbus_data[MODBUS_REGISTERS::TARE] == 1){
a = HARDWARE::MOTOR_LIFT_A; scale.tare();
b = HARDWARE::MOTOR_LIFT_B; modbus_data[MODBUS_REGISTERS::TARE] = 0;
pwm = HARDWARE::MOTOR_LIFT_PWM; }
} }
else if (motor == MOTORS::TILT) {
a = HARDWARE::MOTOR_TILT_A; void poll_scale(){
b = HARDWARE::MOTOR_TILT_B; if(modbus_data[MODBUS_REGISTERS::MEASURE] == 1){
pwm = HARDWARE::MOTOR_TILT_PWM; // Serial.println(scale.get_units()*-1000);
} modbus_data[MODBUS_REGISTERS::MEASURED_WEIGHT] = scale.get_units()*-1000;
else { modbus_data[MODBUS_REGISTERS::MEASURE] = 0;
return; }
} }
if (direction <= 4) { //---Set Motor Output---//
// Set A /*
if (direction <= 1) { Inputs: motor number, direction, pwm value
digitalWrite(a, HIGH); Returns: nothing
}
else { Will set a motor going in a specific direction the motor will continue
digitalWrite(a, LOW); going in that direction, at that speed until told to do otherwise.
}
direct: Should be between 0 and 3, with the following result
// Set B 0: Brake to VCC
if ((direction == 0) || (direction == 2)) { 1: Clockwise
digitalWrite(b, HIGH); 2: CounterClockwise
} 3: Brake to GND
else {
digitalWrite(b, LOW); pwm: should be a value between 0 and 255, higher the number, the faster
} it'll go
analogWrite(pwm, pwm_input); ----------------
} Control Logic:
} ----------------
A | B
void motor_off(int motor) { Brake VCC: 1 1
int a; CW: 1 0
int b; CCW: 0 1
int pwm; Brake GND: 0 0
----------------
if (motor == MOTORS::LIFT) { */
a = HARDWARE::MOTOR_LIFT_A; void set_motor_output(int motor, int direction, int pwm_input) {
b = HARDWARE::MOTOR_LIFT_B;
pwm = HARDWARE::MOTOR_LIFT_PWM; int a;
} int b;
else if (motor == MOTORS::TILT) { int pwm;
a = HARDWARE::MOTOR_TILT_A;
b = HARDWARE::MOTOR_TILT_B; if (motor == MOTORS::LIFT) {
pwm = HARDWARE::MOTOR_TILT_PWM; a = HARDWARE::MOTOR_LIFT_A;
} b = HARDWARE::MOTOR_LIFT_B;
else { pwm = HARDWARE::MOTOR_LIFT_PWM;
return; }
} else if (motor == MOTORS::TILT) {
a = HARDWARE::MOTOR_TILT_A;
digitalWrite(a, LOW); b = HARDWARE::MOTOR_TILT_B;
digitalWrite(b, LOW); pwm = HARDWARE::MOTOR_TILT_PWM;
analogWrite(pwm, 0); }
} else {
return;
}
if (direction <= 4) {
// Set A
if (direction <= 1) {
digitalWrite(a, HIGH);
}
else {
digitalWrite(a, LOW);
}
// Set B
if ((direction == 0) || (direction == 2)) {
digitalWrite(b, HIGH);
}
else {
digitalWrite(b, LOW);
}
analogWrite(pwm, pwm_input);
}
}
void motor_off(int motor) {
int a;
int b;
int pwm;
if (motor == MOTORS::LIFT) {
a = HARDWARE::MOTOR_LIFT_A;
b = HARDWARE::MOTOR_LIFT_B;
pwm = HARDWARE::MOTOR_LIFT_PWM;
}
else if (motor == MOTORS::TILT) {
a = HARDWARE::MOTOR_TILT_A;
b = HARDWARE::MOTOR_TILT_B;
pwm = HARDWARE::MOTOR_TILT_PWM;
}
else {
return;
}
digitalWrite(a, LOW);
digitalWrite(b, LOW);
analogWrite(pwm, 0);
}

View File

@@ -9,10 +9,20 @@ import spnav
import rospy import rospy
from rover_control.msg import MiningControlMessage
##################################### #####################################
# Global Variables # Global Variables
##################################### #####################################
THREAD_HERTZ = 15 THREAD_HERTZ = 100
MINING_CONTROL_TOPIC = "/rover_control/mining/control"
Y_ANGULAR_DEADBAND = 0.05
Z_LINEAR_DEADBAND = 0.15
MINING_LIFT_SCALAR = 5
MINING_TILT_SCALAR = 5
##################################### #####################################
@@ -21,7 +31,7 @@ THREAD_HERTZ = 15
class SpaceNavControlSender(QtCore.QThread): class SpaceNavControlSender(QtCore.QThread):
spacenav_state_update__signal = QtCore.pyqtSignal(object) spacenav_state_update__signal = QtCore.pyqtSignal(object)
GUI_MODE = 0 MINING_MODE = 0
ARM_MODE = 1 ARM_MODE = 1
def __init__(self, shared_objects): def __init__(self, shared_objects):
@@ -95,7 +105,10 @@ class SpaceNavControlSender(QtCore.QThread):
5: "f_pressed" 5: "f_pressed"
} }
self.current_control_mode = self.GUI_MODE # ##### Mining Control #####
self.mining_control_publisher = rospy.Publisher(MINING_CONTROL_TOPIC, MiningControlMessage, queue_size=1)
self.current_control_mode = self.MINING_MODE
def run(self): def run(self):
spnav.spnav_open() spnav.spnav_open()
@@ -110,7 +123,7 @@ class SpaceNavControlSender(QtCore.QThread):
time_diff = time() - start_time time_diff = time() - start_time
self.msleep(max(int((self.wait_time - time_diff) * 1000), 0)) # self.msleep(max(int((self.wait_time - time_diff) * 1000), 0))
def process_spnav_events(self): def process_spnav_events(self):
event = spnav.spnav_poll_event() event = spnav.spnav_poll_event()
@@ -132,16 +145,33 @@ class SpaceNavControlSender(QtCore.QThread):
def check_control_mode_change(self): def check_control_mode_change(self):
if self.spnav_states["1_pressed"]: if self.spnav_states["1_pressed"]:
self.current_control_mode = self.GUI_MODE self.current_control_mode = self.MINING_MODE
elif self.spnav_states["2_pressed"]: elif self.spnav_states["2_pressed"]:
self.current_control_mode = self.ARM_MODE self.current_control_mode = self.ARM_MODE
def broadcast_control_state(self): def broadcast_control_state(self):
if self.current_control_mode == self.GUI_MODE: if self.current_control_mode == self.MINING_MODE:
self.spacenav_state_update__signal.emit(self.spnav_states) self.send_mining_commands()
# self.spacenav_state_update__signal.emit(self.spnav_states)
elif self.current_control_mode == self.ARM_MODE: elif self.current_control_mode == self.ARM_MODE:
pass pass
def send_mining_commands(self):
linear_z = self.spnav_states["linear_z"]
angular_y = self.spnav_states["angular_y"]
message = MiningControlMessage()
message.lift_set_absolute = 1024
message.tilt_set_absolute = 1024
message.lift_set_relative = linear_z * MINING_LIFT_SCALAR if abs(linear_z) > Z_LINEAR_DEADBAND else 0
message.tilt_set_relative = angular_y * MINING_TILT_SCALAR if abs(angular_y) > Y_ANGULAR_DEADBAND else 0
message.cal_factor = -1
self.mining_control_publisher.publish(message)
# print self.spnav_states["linear_z"], self.spnav_states["angular_y"]
def connect_signals_and_slots(self): def connect_signals_and_slots(self):
pass pass

View File

@@ -0,0 +1,139 @@
# coding=utf-8
#####################################
# Imports
#####################################
# Python native imports
from PyQt5 import QtCore, QtWidgets
import logging
import rospy
from rover_control.msg import MiningStatusMessage, MiningControlMessage
#####################################
# Global Variables
#####################################
MINING_STATUS_TOPIC = "/rover_control/mining/status"
MINING_CONTROL_TOPIC = "/rover_control/mining/control"
TRAVEL_POSITION_LIFT = 110
TRAVEL_POSITION_TILT = 1023
MEASURE_POSITION_LIFT = 350
MEASURE_POSITION_TILT = 1023
SCOOP_POSITION_LIFT = 228
SCOOP_POSITION_TILT = 215
#####################################
# UbiquitiRadioSettings Class Definition
#####################################
class Mining(QtCore.QObject):
lift_position_update_ready__signal = QtCore.pyqtSignal(int)
tilt_position_update_ready__signal = QtCore.pyqtSignal(int)
def __init__(self, shared_objects):
super(Mining, self).__init__()
# ########## Reference to class init variables ##########
self.shared_objects = shared_objects
self.left_screen = self.shared_objects["screens"]["left_screen"]
self.mining_qlcdnumber = self.left_screen.mining_qlcdnumber # type:QtWidgets.QLCDNumber
self.mining_tare_button = self.left_screen.mining_tare_button # type:QtWidgets.QPushButton
self.mining_measure_button = self.left_screen.mining_measure_button # type:QtWidgets.QPushButton
self.mining_cal_factor_spinbox = self.left_screen.mining_cal_factor_spinbox # type:QtWidgets.QSpinBox
self.mining_set_cal_factor_button = self.left_screen.mining_set_cal_factor_button # type:QtWidgets.QPushButton
self.lift_position_progress_bar = self.left_screen.lift_position_progress_bar # type:QtWidgets.QProgressBar
self.tilt_position_progress_bar = self.left_screen.tilt_position_progress_bar # type:QtWidgets.QProgressBar
self.mining_measure_move_button = self.left_screen.mining_measure_move_button # type:QtWidgets.QPushButton
self.mining_transport_move_button = self.left_screen.mining_transport_move_button # type:QtWidgets.QPushButton
self.mining_scoop_move_button = self.left_screen.mining_scoop_move_button # type:QtWidgets.QPushButton
# ########## Get the settings instance ##########
self.settings = QtCore.QSettings()
# ########## Get the Pick And Plate instance of the logger ##########
self.logger = logging.getLogger("groundstation")
# ########## Thread Flags ##########
self.run_thread_flag = True
# ########## Class Variables ##########
self.mining_status_subscriber = rospy.Subscriber(MINING_STATUS_TOPIC, MiningStatusMessage,
self.mining_status_message_received__callback)
self.mining_control_publisher = rospy.Publisher(MINING_CONTROL_TOPIC, MiningControlMessage, queue_size=1)
self.connect_signals_and_slots()
def connect_signals_and_slots(self):
self.mining_set_cal_factor_button.clicked.connect(self.on_mining_set_cal_factor_clicked__slot)
self.mining_tare_button.clicked.connect(self.on_mining_tare_clicked__slot)
self.mining_measure_button.clicked.connect(self.on_mining_measure_clicked__slot)
self.mining_measure_move_button.clicked.connect(self.on_mining_move_measure_clicked__slot)
self.mining_transport_move_button.clicked.connect(self.on_mining_move_transport_clicked__slot)
self.mining_scoop_move_button.clicked.connect(self.on_mining_move_scoop_clicked__slot)
self.tilt_position_update_ready__signal.connect(self.tilt_position_progress_bar.setValue)
self.lift_position_update_ready__signal.connect(self.lift_position_progress_bar.setValue)
def on_mining_set_cal_factor_clicked__slot(self):
message = MiningControlMessage()
message.tilt_set_absolute = 1024
message.lift_set_absolute = 1024
message.cal_factor = self.mining_cal_factor_spinbox.value()
self.mining_control_publisher.publish(message)
def on_mining_tare_clicked__slot(self):
message = MiningControlMessage()
message.tilt_set_absolute = 1024
message.lift_set_absolute = 1024
message.cal_factor = -1
message.tare = 1
self.mining_control_publisher.publish(message)
def on_mining_measure_clicked__slot(self):
message = MiningControlMessage()
message.tilt_set_absolute = 1024
message.lift_set_absolute = 1024
message.cal_factor = -1
message.measure = True
self.mining_control_publisher.publish(message)
def on_mining_move_transport_clicked__slot(self):
message = MiningControlMessage()
message.tilt_set_absolute = TRAVEL_POSITION_TILT
message.lift_set_absolute = TRAVEL_POSITION_LIFT
message.cal_factor = -1
self.mining_control_publisher.publish(message)
def on_mining_move_measure_clicked__slot(self):
message = MiningControlMessage()
message.tilt_set_absolute = MEASURE_POSITION_TILT
message.lift_set_absolute = MEASURE_POSITION_LIFT
message.cal_factor = -1
self.mining_control_publisher.publish(message)
def on_mining_move_scoop_clicked__slot(self):
message = MiningControlMessage()
message.tilt_set_absolute = SCOOP_POSITION_TILT
message.lift_set_absolute = SCOOP_POSITION_LIFT
message.cal_factor = -1
self.mining_control_publisher.publish(message)
def mining_status_message_received__callback(self, status):
status = status # type:MiningStatusMessage
self.tilt_position_update_ready__signal.emit(status.tilt_position)
self.lift_position_update_ready__signal.emit(status.lift_position)
self.mining_qlcdnumber.display(status.measured_weight)

View File

@@ -1392,6 +1392,334 @@ N/A</string>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Mining</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_8">
<item row="5" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QLabel" name="label_15">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Lift Position</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="lift_position_progress_bar">
<property name="maximum">
<number>1023</number>
</property>
<property name="value">
<number>512</number>
</property>
<property name="format">
<string>%v</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QLabel" name="label_14">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Tilt Position</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="tilt_position_progress_bar">
<property name="maximum">
<number>1023</number>
</property>
<property name="value">
<number>512</number>
</property>
<property name="format">
<string>%v</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_13">
<property name="font">
<font>
<pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Scoop Measurement</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="mining_tare_button">
<property name="text">
<string>Tare</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mining_measure_button">
<property name="text">
<string>Measure</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSpinBox" name="mining_cal_factor_spinbox">
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>114</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mining_set_cal_factor_button">
<property name="text">
<string>Set Cal Factor</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLCDNumber" name="mining_qlcdnumber">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>150</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>150</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="value" stdset="0">
<double>0.000000000000000</double>
</property>
<property name="intValue" stdset="0">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<pointsize>19</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>g</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="Line" name="line_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="7" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<spacer name="horizontalSpacer_13">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="mining_transport_move_button">
<property name="text">
<string>Transport</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mining_measure_move_button">
<property name="text">
<string>Measure</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mining_scoop_move_button">
<property name="text">
<string>Scoop</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_14">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab"> <widget class="QWidget" name="tab">
<attribute name="title"> <attribute name="title">
<string>SSH Console</string> <string>SSH Console</string>

View File

@@ -23,6 +23,7 @@ import Framework.StatusSystems.StatusCore as StatusCore
import Framework.StatusSystems.UbiquitiStatusCore as UbiquitiStatusCore import Framework.StatusSystems.UbiquitiStatusCore as UbiquitiStatusCore
import Framework.SettingsSystems.UbiquitiRadioSettings as UbiquitiRadioSettings import Framework.SettingsSystems.UbiquitiRadioSettings as UbiquitiRadioSettings
import Framework.InputSystems.SpaceNavControlSender as SpaceNavControlSender import Framework.InputSystems.SpaceNavControlSender as SpaceNavControlSender
import Framework.MiscSystems.MiningCore as MiningCore
##################################### #####################################
# Global Variables # Global Variables
@@ -101,6 +102,7 @@ class GroundStation(QtCore.QObject):
rospy.init_node("ground_station") rospy.init_node("ground_station")
# ##### Instantiate Regular Classes ###### # ##### Instantiate Regular Classes ######
self.__add_non_thread("Mining System", MiningCore.Mining(self.shared_objects))
# ##### Instantiate Threaded Classes ###### # ##### Instantiate Threaded Classes ######
self.__add_thread("Video Coordinator", RoverVideoCoordinator.RoverVideoCoordinator(self.shared_objects)) self.__add_thread("Video Coordinator", RoverVideoCoordinator.RoverVideoCoordinator(self.shared_objects))
@@ -132,6 +134,9 @@ class GroundStation(QtCore.QObject):
instance.setup_signals(self.start_threads_signal, self.connect_signals_and_slots_signal, instance.setup_signals(self.start_threads_signal, self.connect_signals_and_slots_signal,
self.kill_threads_signal) self.kill_threads_signal)
def __add_non_thread(self, name, instance):
self.shared_objects["regular_classes"][name] = instance
def __connect_signals_to_slots(self): def __connect_signals_to_slots(self):
self.shared_objects["screens"]["left_screen"].exit_requested_signal.connect(self.on_exit_requested__slot) self.shared_objects["screens"]["left_screen"].exit_requested_signal.connect(self.on_exit_requested__slot)
self.shared_objects["screens"]["right_screen"].exit_requested_signal.connect(self.on_exit_requested__slot) self.shared_objects["screens"]["right_screen"].exit_requested_signal.connect(self.on_exit_requested__slot)

View File

@@ -55,6 +55,8 @@ find_package(catkin REQUIRED COMPONENTS
DriveStatusMessage.msg DriveStatusMessage.msg
IrisStatusMessage.msg IrisStatusMessage.msg
TowerPanTiltControlMessage.msg TowerPanTiltControlMessage.msg
MiningControlMessage.msg
MiningStatusMessage.msg
) )
## Generate services in the 'srv' folder ## Generate services in the 'srv' folder

View File

@@ -0,0 +1,10 @@
int32 lift_set_relative
int32 tilt_set_relative
uint16 lift_set_absolute
uint16 tilt_set_absolute
bool measure
bool tare
int16 cal_factor

View File

@@ -0,0 +1,4 @@
uint16 lift_position
uint16 tilt_position
uint16 measured_weight

View File

@@ -96,7 +96,7 @@ class ChassisPanTiltControl(object):
delay_before_tx=TX_DELAY) delay_before_tx=TX_DELAY)
def run(self): def run(self):
self.send_startup_centering_command() # self.send_startup_centering_command()
while not rospy.is_shutdown(): while not rospy.is_shutdown():
start_time = time() start_time = time()

View File

@@ -0,0 +1,280 @@
#!/usr/bin/env python
#####################################
# Imports
#####################################
# Python native imports
import rospy
from time import time, sleep
import serial.rs485
import minimalmodbus
# from std_msgs.msg import UInt8, UInt16
# Custom Imports
from rover_control.msg import MiningControlMessage, MiningStatusMessage
#####################################
# Global Variables
#####################################
NODE_NAME = "effectors_control"
# ##### Communication Defines #####
DEFAULT_PORT = "/dev/rover/ttyEffectors"
DEFAULT_BAUD = 115200
GRIPPER_NODE_ID = 1
MINING_NODE_ID = 2
SCIENCE_NODE_ID = 3
GRIPPER_TIMEOUT = 0.15
MINING_TIMEOUT = 0.3
SCIENCE_TIMEOUT = 0.15
RX_DELAY = 0.01
TX_DELAY = 0.01
DEFAULT_HERTZ = 40
GRIPPER_CONTROL_SUBSCRIBER_TOPIC = "gripper/control"
MINING_CONTROL_SUBSCRIBER_TOPIC = "mining/control"
MINING_STATUS_PUBLISHER_TOPIC = "mining/status"
SCIENCE_CONTROL_SUBSCRIBER_TOPIC = "science/control"
# ##### Arm Defines #####
# ##### Mining Defines #####
MINING_MODBUS_REGISTERS = {
"LIFT_SET_POSITIVE": 0,
"LIFT_SET_NEGATIVE": 1,
"TILT_SET_POSITIVE": 2,
"TILT_SET_NEGATIVE": 3,
"TILT_SET_ABSOLUTE": 4,
"LIFT_SET_ABSOLUTE": 5,
"MEASURE": 6,
"TARE": 7,
"CAL_FACTOR": 8,
"LIFT_POSITION": 9,
"TILT_POSITION": 10,
"MEASURED_WEIGHT": 11
}
MINING_POSITIONAL_THRESHOLD = 20
# ##### Science Defines #####
# ##### Misc Defines #####
NODE_LAST_SEEN_TIMEOUT = 2 # seconds
UINT16_MAX = 65535
#####################################
# DriveControl Class Definition
#####################################
class EffectorsControl(object):
def __init__(self):
rospy.init_node(NODE_NAME)
self.port = rospy.get_param("~port", DEFAULT_PORT)
self.baud = rospy.get_param("~baud", DEFAULT_BAUD)
self.gripper_node_id = rospy.get_param("~gripper_node_id", GRIPPER_NODE_ID)
self.mining_node_id = rospy.get_param("~mining_node_id", MINING_NODE_ID)
self.science_node_id = rospy.get_param("~science_node_id", SCIENCE_NODE_ID)
self.gripper_control_subscriber_topic = rospy.get_param("~gripper_control_subscriber_topic",
GRIPPER_CONTROL_SUBSCRIBER_TOPIC)
self.mining_control_subscriber_topic = rospy.get_param("~mining_control_subscriber_topic",
MINING_CONTROL_SUBSCRIBER_TOPIC)
self.mining_status_publisher_topic = rospy.get_param("~mining_status_publisher_topic",
MINING_STATUS_PUBLISHER_TOPIC)
self.science_control_subscriber_topic = rospy.get_param("~science_control_subscriber_topic",
SCIENCE_CONTROL_SUBSCRIBER_TOPIC)
self.wait_time = 1.0 / rospy.get_param("~hertz", DEFAULT_HERTZ)
self.gripper_node = None # type:minimalmodbus.Instrument
self.mining_node = None # type:minimalmodbus.Instrument
self.science_node = None # type:minimalmodbus.Instrument
self.gripper_node_present = False
self.mining_node_present = True
self.science_node_present = False
self.connect_to_nodes()
# self.check_which_nodes_present()
# ##### Subscribers #####
self.mining_control_subscriber = rospy.Subscriber(self.mining_control_subscriber_topic, MiningControlMessage,
self.mining_control_message_received__callback)
# ##### Publishers #####
self.mining_status_publisher = rospy.Publisher(self.mining_status_publisher_topic, MiningStatusMessage, queue_size=1)
# ##### Misc #####
self.modbus_nodes_seen_time = time()
# ##### Mining Variables #####
self.mining_registers = [0 for _ in MINING_MODBUS_REGISTERS]
self.mining_control_message = None # type:MiningControlMessage
self.new_mining_control_message = False
self.run()
def __setup_minimalmodbus_for_485(self):
self.gripper_node.serial = serial.rs485.RS485(self.port, baudrate=self.baud, timeout=GRIPPER_TIMEOUT)
self.gripper_node.serial.rs485_mode = serial.rs485.RS485Settings(rts_level_for_rx=1, rts_level_for_tx=0,
delay_before_rx=RX_DELAY,
delay_before_tx=TX_DELAY)
self.mining_node.serial = serial.rs485.RS485(self.port, baudrate=self.baud, timeout=MINING_TIMEOUT)
self.mining_node.serial.rs485_mode = serial.rs485.RS485Settings(rts_level_for_rx=1, rts_level_for_tx=0,
delay_before_rx=RX_DELAY,
delay_before_tx=TX_DELAY)
self.science_node.serial = serial.rs485.RS485(self.port, baudrate=self.baud, timeout=SCIENCE_TIMEOUT)
self.science_node.serial.rs485_mode = serial.rs485.RS485Settings(rts_level_for_rx=1, rts_level_for_tx=0,
delay_before_rx=RX_DELAY,
delay_before_tx=TX_DELAY)
def run(self):
# self.initialize_mining_system()
while not rospy.is_shutdown():
try:
self.process_mining_control_message()
except IOError, e:
print e
if (time() - self.modbus_nodes_seen_time) > NODE_LAST_SEEN_TIMEOUT:
print "Lost connection to mining system. Exiting for reconnect."
return
except Exception, e:
print e
try:
self.send_mining_status_message()
except IOError, e:
print e
if (time() - self.modbus_nodes_seen_time) > NODE_LAST_SEEN_TIMEOUT:
print "Lost connection to mining system. Exiting for reconnect."
return
except Exception, e:
print e
def connect_to_nodes(self):
self.gripper_node = minimalmodbus.Instrument(self.port, int(self.gripper_node_id))
self.mining_node = minimalmodbus.Instrument(self.port, int(self.mining_node_id))
self.science_node = minimalmodbus.Instrument(self.port, int(self.science_node_id))
self.__setup_minimalmodbus_for_485()
def check_which_nodes_present(self):
try:
self.gripper_node.read_register(0)
self.gripper_node_present = True
except:
self.gripper_node_present = False
try:
self.mining_node.read_register(0)
self.mining_node_present = True
except:
self.mining_node_present = False
try:
self.science_node.read_register(0)
self.science_node_present = True
except:
self.science_node_present = False
def initialize_mining_system(self):
if self.mining_node_present:
self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET"]] = 1023
self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET"]] = 350
self.mining_registers[MINING_MODBUS_REGISTERS["CAL_FACTOR"]] = 114
while abs(self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_POSITION"]] - self.mining_registers[
MINING_MODBUS_REGISTERS["LIFT_SET"]]) > MINING_POSITIONAL_THRESHOLD or \
abs(self.mining_registers[MINING_MODBUS_REGISTERS["TILT_POSITION"]] - self.mining_registers[
MINING_MODBUS_REGISTERS["TILT_SET"]]) > MINING_POSITIONAL_THRESHOLD:
try:
self.mining_node.write_registers(0, self.mining_registers)
self.mining_registers = self.mining_node.read_registers(0, 7)
except Exception, e:
print "Had trouble communicating:", e
try:
self.mining_registers[MINING_MODBUS_REGISTERS["TARE"]] = 1
self.mining_node.write_registers(0, self.mining_registers)
self.mining_registers[MINING_MODBUS_REGISTERS["TARE"]] = 0
except:
print "Had trouble communicating: no tare: ", e
def process_mining_control_message(self):
if self.new_mining_control_message and self.mining_node_present:
lift_set_relative = self.mining_control_message.lift_set_relative
tilt_set_relative = self.mining_control_message.tilt_set_relative
lift_set_absolute = self.mining_control_message.lift_set_absolute
tilt_set_absolute = self.mining_control_message.tilt_set_absolute
cal_factor = min(self.mining_control_message.cal_factor, UINT16_MAX)
measure = self.mining_control_message.measure
tare = self.mining_control_message.tare
if lift_set_absolute < 1024:
self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET_ABSOLUTE"]] = lift_set_absolute
else:
if lift_set_relative >= 0:
self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET_POSITIVE"]] = lift_set_relative
else:
self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET_NEGATIVE"]] = -lift_set_relative
if tilt_set_absolute < 1024:
self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET_ABSOLUTE"]] = tilt_set_absolute
else:
if tilt_set_relative >= 0:
self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET_POSITIVE"]] = tilt_set_relative
else:
self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET_NEGATIVE"]] = -tilt_set_relative
if cal_factor > -1:
self.mining_registers[MINING_MODBUS_REGISTERS["CAL_FACTOR"]] = cal_factor
self.mining_registers[MINING_MODBUS_REGISTERS["MEASURE"]] = int(measure)
self.mining_registers[MINING_MODBUS_REGISTERS["TARE"]] = int(tare)
self.mining_node.write_registers(0, self.mining_registers)
self.modbus_nodes_seen_time = time()
self.new_mining_control_message = False
def send_mining_status_message(self):
if self.mining_node_present:
self.mining_registers = self.mining_node.read_registers(0, len(MINING_MODBUS_REGISTERS))
message = MiningStatusMessage()
message.lift_position = self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_POSITION"]]
message.tilt_position = self.mining_registers[MINING_MODBUS_REGISTERS["TILT_POSITION"]]
message.measured_weight = self.mining_registers[MINING_MODBUS_REGISTERS["MEASURED_WEIGHT"]]
self.mining_status_publisher.publish(message)
self.modbus_nodes_seen_time = time()
def mining_control_message_received__callback(self, control_message):
self.mining_control_message = control_message
self.new_mining_control_message = True
if __name__ == "__main__":
EffectorsControl()

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python
import rospy
import time
from rover_control.msg import MiningControlMessage
DEFAULT_TOWER_PAN_TILT_CONTROL_TOPIC = "/rover_control/mining/control"
rospy.init_node("effectors_tester")
publisher = rospy.Publisher(DEFAULT_TOWER_PAN_TILT_CONTROL_TOPIC, MiningControlMessage, queue_size=1)
time.sleep(2)
message = MiningControlMessage()
message.lift_set = 200
message.tilt_set = 1023
message.cal_factor = -1
publisher.publish(message)
time.sleep(5)
# message = MiningControlMessage()
# message.lift_set = -200
# message.tilt_set = -100
# message.cal_factor = -1
#
# publisher.publish(message)
#
# time.sleep(2)

View File

@@ -172,9 +172,9 @@ class TowerPanTiltControl(object):
def send_startup_centering_and_lights_off_command(self): def send_startup_centering_and_lights_off_command(self):
try: try:
registers = list(PAN_TILT_CONTROL_DEFAULT_MESSAGE) # registers = list(PAN_TILT_CONTROL_DEFAULT_MESSAGE)
registers[PAN_TILT_MODBUS_REGISTERS["CENTER_ALL"]] = 1 # registers[PAN_TILT_MODBUS_REGISTERS["CENTER_ALL"]] = 1
self.pan_tilt_node.write_registers(0, registers) # self.pan_tilt_node.write_registers(0, registers)
self.tower_node.write_register(0, TOWER_LIGHT_STATES["LIGHT_OFF"]) self.tower_node.write_register(0, TOWER_LIGHT_STATES["LIGHT_OFF"])
except: except:

View File

@@ -8,7 +8,8 @@
<rosparam param="topics"> <rosparam param="topics">
[{name: "/rover_control/command_control/ground_station_drive", compress: true, rate: 15.0}, [{name: "/rover_control/command_control/ground_station_drive", compress: true, rate: 15.0},
{name: "/rover_control/tower/pan_tilt/control", compress: true, rate: 30.0}, {name: "/rover_control/tower/pan_tilt/control", compress: true, rate: 30.0},
{name: "/rover_control/chassis/pan_tilt/control", compress: true, rate: 30.0}] {name: "/rover_control/chassis/pan_tilt/control", compress: true, rate: 30.0},
{name: "/rover_control/mining/control", compress: true, rate: 15.0}]
</rosparam> </rosparam>
</node> </node>

View File

@@ -34,5 +34,7 @@
<node name="tower_and_pan_tilt" pkg="rover_control" type="tower_and_pan_tilt_control.py" respawn="true" output="screen"/> <node name="tower_and_pan_tilt" pkg="rover_control" type="tower_and_pan_tilt_control.py" respawn="true" output="screen"/>
<node name="chassis_pan_tilt" pkg="rover_control" type="chassis_pan_tilt_control.py" respawn="true" output="screen"/> <node name="chassis_pan_tilt" pkg="rover_control" type="chassis_pan_tilt_control.py" respawn="true" output="screen"/>
<node name="effectors" pkg="rover_control" type="effectors_control.py" respawn="true" output="screen"/>
</group> </group>
</launch> </launch>

View File

@@ -0,0 +1,6 @@
<launch>
<group ns="rover_control">
<node name="effectors" pkg="rover_control" type="effectors_control.py" respawn="true" output="screen">
</node>
</group>
</launch>

View File

@@ -155,6 +155,7 @@
{name: "/rover_status/battery_status", compress: false, rate: 1.0}, {name: "/rover_status/battery_status", compress: false, rate: 1.0},
{name: "/rover_control/tower/status/co2", compress: false, rate: 1.0}, {name: "/rover_control/tower/status/co2", compress: false, rate: 1.0},
{name: "/rover_odometry/imu/data", compress: false, rate: 10.0}, {name: "/rover_odometry/imu/data", compress: false, rate: 10.0},
{name: "/rover_control/mining/status", compress: false, rate: 2.0},
] ]
</rosparam> </rosparam>
</node> </node>

View File

@@ -19,7 +19,7 @@ import minimalmodbus
##################################### #####################################
NODE_NAME = "chassis_pan_tilt_control" NODE_NAME = "chassis_pan_tilt_control"
DEFAULT_PORT = "/dev/rover/ttyChassisPanTilt" DEFAULT_PORT = "/dev/rover/ttyEffectors"
DEFAULT_BAUD = 115200 DEFAULT_BAUD = 115200
DEFAULT_INVERT = False DEFAULT_INVERT = False
@@ -57,7 +57,7 @@ NODE_LAST_SEEN_TIMEOUT = 2 # seconds
##################################### #####################################
class MiningControl(object): class MiningControl(object):
def __init__(self): def __init__(self):
self.port = "/dev/ttyUSB0" self.port = DEFAULT_PORT
self.baud = 115200 self.baud = 115200
self.mining_node = None self.mining_node = None
@@ -93,8 +93,8 @@ class MiningControl(object):
while True: while True:
try: try:
print self.mining_node.read_registers(0, 7) print self.mining_node.read_registers(0, 7)
# self.mining_registers[MINING_MODBUS_REGISTERS["CAL_FACTOR"]] = int(input("Enter new cal value:")) self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET"]] = int(input("Enter new tilt value:"))
# self.mining_node.write_registers(0, self.mining_registers) self.mining_node.write_registers(0, self.mining_registers)
except Exception, e: except Exception, e:
print e print e
@@ -106,12 +106,11 @@ class MiningControl(object):
def initialize_mining_system(self): def initialize_mining_system(self):
self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET"]] = 1023 self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET"]] = 1023
self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET"]] = 350 self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET"]] = 350
self.mining_registers[MINING_MODBUS_REGISTERS["CAL_FACTOR"]] = 114 self.mining_registers[MINING_MODBUS_REGISTERS["CAL_FACTOR"]] = 114
lift_current = 0 while abs(self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_POSITION"]] - self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET"]]) > POSITIONAL_THRESHOLD or \
tilt_current = 0 abs(self.mining_registers[MINING_MODBUS_REGISTERS["TILT_POSITION"]] - self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET"]]) > POSITIONAL_THRESHOLD:
while abs(self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_POSITION"]] - self.mining_registers[MINING_MODBUS_REGISTERS["LIFT_SET"]]) > POSITIONAL_THRESHOLD or abs(self.mining_registers[MINING_MODBUS_REGISTERS["TILT_POSITION"]] - self.mining_registers[MINING_MODBUS_REGISTERS["TILT_SET"]]) > POSITIONAL_THRESHOLD:
try: try:
self.mining_node.write_registers(0, self.mining_registers) self.mining_node.write_registers(0, self.mining_registers)
self.mining_registers = self.mining_node.read_registers(0, 7) self.mining_registers = self.mining_node.read_registers(0, 7)

View File

@@ -0,0 +1,28 @@
import socket
import sys
# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('task.cstag.ca', 4547)
messages = ["HELP", "LOGIN MTECH GITRDONE", "STATUS", "START", "STOP", "LOGOUT"]
print "Connected.... Enter commands now..."
# for message in messages:
while True:
try:
# Send data
message = raw_input()
# print type(message)
if message not in messages:
print "Invalid command. Please try again."
continue
sent = sock.sendto(message, server_address)
# Receive response
# print 'waiting to receive'
data, server = sock.recvfrom(4096)
print data
except:
pass